Heim  >  Artikel  >  Datenbank  >  Was bedeutet Redis-Protokoll?

Was bedeutet Redis-Protokoll?

尚
Original
2019-07-04 13:14:463898Durchsuche

Was bedeutet Redis-Protokoll?

Der Redis-Client interagiert mit dem Redis-Server über ein Protokoll namens RESP (REdis Serialization Protocol, Redis-Serialisierungsprotokoll). Obwohl dieses Protokoll für Redis konzipiert ist, kann es auch in anderen Softwaresystemen mit Client-Server-Architektur verwendet werden. (Anmerkung: Einigen öffentlichen Informationen zufolge bezieht sich Momos IM-Protokolldesign auf das Redis-Protokoll)

RESP wägt die folgenden Aspekte ab:

Die Implementierung sollte einfach und das Parsen schnell und bequem sein . Leute lesen

RESP kann verschiedene Datentypen wie Ganzzahlen, Zeichenfolgen, Arrays serialisieren und auch spezielle Typen für Fehler entwerfen. Der Client sendet eine Anfrage in Form eines String-Parameter-Arrays zur Ausführung an den Redis-Server, und Redis gibt den Datentyp zurück, der sich auf den Befehl bezieht.

RESP ist binärsicher und erfordert kein Parsen von Massendaten, die von einem Prozess an einen anderen gesendet werden, da es ein Längenpräfix zur Übertragung von Massendaten verwendet.

Hinweis: Das hier genannte Protokoll wird nur für die Client-Server-Kommunikation verwendet. Redis Cluster verwendet verschiedene Binärprotokolle für den Nachrichtenaustausch zwischen Knoten.

Netzwerkschicht

Der Client kommuniziert mit Redis, indem er eine TCP-Verbindung mit Port 6379 herstellt.

Obwohl RESP technisch gesehen nicht mit TCP verwandt ist, wird das Protokoll für Redis nur für TCP (oder andere Streaming-Protokolle wie Unix-Domänenprotokolle) verwendet. (Anmerkung: Andererseits unterstützt Memcached sowohl TCP als auch UDP, aber tatsächlich verwendet die Produktionsumgebung im Grunde nur TCP. Ich denke, dass dies ein Überdesign ist und von Hackern verwendet werden kann, um Memcached-UDP-Reflektionsangriffe durchzuführen . . )

Request-Response-Modell

Redis empfängt Befehle, die aus verschiedenen Parametern bestehen. Wenn der Befehl empfangen wird, wird er verarbeitet und die Antwort an den Client gesendet.

Dies ist das einfachste Modell, es gibt jedoch zwei Ausnahmen:

Redis unterstützt Pipelining (wird später erwähnt). So kann der Client mehrere Befehle gleichzeitig senden und auf Antworten warten. Wenn der Client einen Pub/Sub-Kanal abonniert, ändert das Protokoll seine Semantik und wird zu einem Push-Protokoll, was bedeutet, dass der Client keine Befehle senden muss, da der Server nach Erhalt der Nachricht automatisch neue Nachrichten an den Client sendet ( Kanal, den der Kunde abonniert hat).

Zusätzlich zu diesen beiden Punkten ist das Redis-Protokoll ein einfaches Anfrage-Antwort-Protokoll.

RESP-Protokollbeschreibung

Das RESP-Protokoll wurde in Redis 1.2 eingeführt, ist aber mittlerweile zum Standard-Interaktionsprotokoll für Redis 2.0 geworden. Sie sollten dieses Protokoll verwenden, wenn Sie einen Redis-Client implementieren.

RESP ist eigentlich ein Serialisierungsprotokoll, das die folgenden Typen unterstützt: Einfache Zeichenfolgen, Fehler, Ganzzahlen, Massenzeichenfolgen und Arrays.

RESP wird als Request-Response-Protokoll in Redis wie folgt verwendet:

Der Client sendet Befehle in Form eines Arrays von RESP-Bulk-Strings an den Redis-Server. Der Server implementiert verschiedene Befehle und gibt die entsprechende RESP-Implementierung zurück.

In RESP wird der Typ einiger Daten durch das erste Byte bestimmt:

Für SIMple Strings ist das erste Byte der Antwort „+“, für Errors das erste Wort der Antwort. Der Abschnitt ist „-“. Bei Ganzzahlen ist das erste Byte der Antwort „:“. Bei Arrays ist das erste Byte der Antwort „*“.

Zusätzlich zu RESP können Sie einen speziellen Bulk-String oder ein Array verwenden, um Nullwerte darzustellen, was später erwähnt wird.

In RESP werden verschiedene Teile des Protokolls immer durch „rn“ (CRLF) getrennt.

RESP Simple Strings

Einfache Strings werden codiert durch: ein Pluszeichen, gefolgt von einer Zeichenfolge, die keine CR- oder LF-Zeichen (keine Zeilenumbrüche) enthält und mit CRLF („rn“) endet. Beenden.

SImple Strings überträgt nicht-binäre sichere Strings mit minimalem Aufwand. Beispielsweise antworten viele Redis-Befehle bei Erfolg mit „OK“, d Verwenden Sie für Zeichenfolgen RESP Bulk Strings.

Wenn Redis auf einen einfachen String antwortet, sollte die Clientbibliothek den String vom ersten „+“-Zeichen bis zum Ende des Strings an den Aufrufer zurückgeben, ausgenommen CRLF-Bytes.


RESP-Fehler

RESP hat einen speziellen Datentyp für Fehler. Eigentlich ist der Fehler genau wie der einfache RESP-String, aber der erste String ist „-“ anstelle eines Pluszeichens. Der eigentliche Unterschied zwischen einfachen Zeichenfolgen und Fehlern in RESP besteht darin, dass Fehler vom Client als Ausnahmen behandelt werden und die Zeichenfolge, die den Fehlertyp darstellt, die Zeichenfolge selbst ist. Das Grundformat ist:

"-Error messagern"

Die Fehlerantwort wird nur gesendet, wenn ein Fehler auftritt, z. B. wenn Sie den falschen Datentyp oder den Befehl eingegeben haben existiert nicht, warte. Beim Empfang einer Fehlerantwort sollte der Client eine Ausnahme auslösen.

Das Folgende ist ein Beispiel für eine Fehlerantwort:


-ERR unbekannter Befehl 'foobar'-WRONGTYPE Operation gegen einen Schlüssel, der die falsche Art von Wert enthält

bei „-“ an das erste Leerzeichen oder das erste Wort in einer neuen Zeile, was die Art des zurückzugebenden Fehlers angibt. Dies ist nur eine Konvention von Redis selbst, nicht das von RESP Error angegebene Format.

例如,ERR 是通用错误,而 WRONGTYPE 是一种更加具体的错误,表示客户端尝试操作错误的数据类型。这称为 Error Prefix (Error前缀),客户端可从此得知服务器返回错误的类型而不需依赖于那个确切的消息描述,后者会随时改变。

一个客户端的实现可能对不同的error返回不同类型的异常,或者向调用者返回代表错误的字符串。然而这种特性并不是必须的,因为这并没什么卵用,一些精简的客户端实现可能简单的返回一般的错误情况,例如 false。

RESP Integers 

这种类型就是一个代表整数的以CRLF结尾的字符串,并以“:”字节开头。例如 ":0\r\n", 或 ":1000\r\n" 都是整数响应。

很多Redis命令返回RESP Integers, 像 INCR, LLEN 和 LASTSAVE。

返回的整数并没什么特殊的含义,它就是 INCR 增加后的数字,LASTSAVE 的UNIX时间戳等。但返回的整数可以保证是在64位有符号整数的范围内。

整数响应也被大量的用于表示true或false。例如EXISTS和 SISMEMBER 等命令会返回1表示true, 0表示false。

以下命令会返回一个整数: SETNX, DEL, EXISTS, INCR, INCRBY, DECR, DECRBY, DBSIZE, LASTSAVE, RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD。

RESP Bulk Strings

Bulk Strings 用于表示一个二进制安全的字符串,最大长度为512M。

Bulk Strings 的编码格式如下:

“$” 后跟字符串字节数(prefix length),以CRLF结束实际的字符串CRLF结束

所以字符串"foobar" 被编码成:

"$6\r\nfoobar\r\n"

空字符串:

"$0\r\n\r\n"

RESP Bulk String 也可以用一种代表Null值的特殊格式来表示不存在的值。这种特殊格式的长度值为-1, 并且没数据,所以Null表示为:

"$-1\r\n"

这称为 Null Bulk String。

当服务器返回Null Bulk String时,客户端API不应该返回空串,而是nil 对象。例如Ruby库应该返回 'nil' 而 C 库应该返回 NULL (或在返回的对象设置特殊的标记),等等。

RESP Arrays

客户端用RESP Arrays向Redis服务器发送命令。同样某些Redis命令要返回一个元素集合时也使用RESP Arrays作为返回的类型。一个例子是LRANGE 命令返回一个元素列表。

RESP Arrays使用以下格式发送:

“*” 为第一个字节,后跟数组的元素个数,然后CRLF。然后是数组中的每一个RESP类型表示的元素。

例如一个空数组表示为:

"*0\r\n"

而有两个RESP Bulk Strings "foo" 和 "bar" 的数组编码为:

"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"

正如你所见,在数组前面的 *570b78fce6f4d82c6d7725059f1f48f1CRLF 后,数组中的其他的数据类型一个接一个的连接在一起。例如一个有三个整数的数组编码如下:

"*3\r\n:1\r\n:2\r\n:3\r\n"

数组可以包含混合类型,它不要求所有的元素都是相同的类型。例如,一个有4个interges和1个bulk string的数组可以编码为:

*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n

(为清晰起见响应被分为多行)。

服务器发送的第一行 *5\r\n 表示后跟有5个响应,然后每个代表元素的响应被发送。

Null 数组的概念同样存在,它是Null值的替代方式 (通常使用Null Bulk String,但由于历史原因我们有两种格式)。

例如当BLPOP命令超时,它返回一个长度为-1的Null 数组,如下所示:

"*-1\r\n"

在服务端返回Null数组时,客户端库API应该返回null对象而不是空数组。区分返回空的列表与其他的情况(如BLPOP命令超时的情况)是有必要的。

RESP允许数组的数组。例如一个含两个数组的数组编码如下:

*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n

高效解析Redis协议

尽管Redis协议非常可读并且容易实现,它却可以兼得二进制协议的高效。

RESP使用长度前缀来传输bulk 数据,所以不需要像JSON一样扫描数据负载中的特殊符号,或者用引号括住数据负载。

Bulk和Multi Bulk长度的处理可以一次处理一个字符,同时可以扫描CR字符,像如下的C代码:

#include <stdio.h>

int main(void) {
    unsigned char *p = "$123\r\n";
    int len = 0;

    p++;
    while(*p != &#39;\r&#39;) {
        len = (len*10)+(*p - &#39;0&#39;);
        p++;
    }

    /* Now p points at &#39;\r&#39;, and the len is in bulk_len. */
    printf("%d\n", len);
    return 0;
}

当第一个CR被识别后,后面的LF可以忽略不处理。然后bulk数据可以一次读取而不需要分析 数据负载。最后剩下的CR和LF字符串可以丢弃不处理。

与二进制协议比较性能时,Redis协议在大部分的高级语言实现起来足够简单,减少了客户端软件的bug数量。

注:

1. 协议中的CR和LF相当于分割符,命令间存在多个CRLF不应影响后续解析,应为多个CRLF应被忽略掉。例如:

$> (printf "PING\r\nPING\r\nPING\r\n\r\n\rPING\r\n"; sleep 1) | nc localhost 6379
+PONG
+PONG
+PONG
+PONG

2. 对比一下memcached的协议,redis的协议确实设计得比较精简:

(1) 一致的请求形式。redis的请求都是以 Bluk String 数组发送,不同命令只是数组的元素个数不同,所有命令的处理可以先读取完整个数组再根据不同命令解析数组的参数;而不是像mc协议一样,不同请求的命令格式不同,那么在读取网络字节流的过程中就要对不同命令做不同的处理,增加了协议解析的难度。

(2) 长度前缀是高效解析协议的关键。字段长度信息并不是二进制协议的专利,文本协议也可以有。

更多Redis相关知识,请访问Redis使用教程栏目!

Das obige ist der detaillierte Inhalt vonWas bedeutet Redis-Protokoll?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn