resp
Redis RESP
|  Redis Internel Course |  Redis Technical Support |  Redis Enterprise Server | 
|---|
RESP (REdis Serialization Protocol)
개요
RESP(REdis Serialization Protocol)는 레디스 통신 프로토콜(포멧) 이름입니다.redis-cli, 마스터-복제간 통신, redis client library(lettuce, jedis)가 이 프로토콜에 따라 통신합니다.
버전
- RESP는 버전 2와 3이 있는데, RESP 버전 2는 레디스의 기본 출력 프로토콜입니다. 레디스 6.x 부터는 RESP 버전 3을 선택해서 사용할 수 있습니다.
- RESP 3는 2018년 5월 부터 시작해서 2019년에 개발이 완료되었고, 2020년 4월에 발표된 레디스 6에 적용되었습니다.
- RESP 3를 사용하려면 hello 3 명령을 실행해야 하고, 접속 컨텍션(connection)별로 적용됩니다.
RESP 버전 2
프로토콜(포멧)
다섯 가지 포멧으로 구성됩니다.- status: 구분자 + 특수문자가 포함되지 않는 일반 문자열을 표시할 때 사용한다. 
 포멧: +<String><CR><LF> 예) OK
- error: 구분자 - 특수문자가 포함되지 않는 에러 문자열을 표시할 때 사용한다. 
 포멧: -<ERR msg><CR><LF> 예) ERR no such key
- integer: 구분자 :  정수를 표시할 때 사용한다. 
 포멧: :<1234><CR><LF> 예) 1234
 사용하는 명령: llen, scard
- bulk: 구분자 $  특수문자가 포함된 문자열을 표시할 때 사용한다. 
 포멧: $11<CR><LF><hello world><CR><LF>
 값(value)를 표시할 때 사용하고, 실수(double)도 이것을 사용한다.
 사용하는 명령: get, hget, 등
- multibulk: 구분자 * 배열을 표시할 때 사용한다. 
 포멧: *10<CR><LF>
 
 사용하는 명령: mget, lrange, smembers, zrange, hgetall, 등
RESP 버전 3
개발 배경
RESP 2에서 부족한 점- 정수(integer)와 실수(floating point number)의 구분이 없습니다. 
 정수는 ':'로 구분했지만, 실수는 bulk('$') 문자열을 사용했습니다.
- 불린(boolean, 참 거짓)을 명시적으로 표현하는 방법이 없었습니다. 
 그래서 1/0로 대신 했습니다.
- 널(null)도 구분 방법이 없어서 bulk $-1을 사용했습니다.
- JAVA같은 프로그래밍 언어에서 제공하는 array, set, map을 따로 구분하지 않고 
모두 multibulk(array)를 사용했습니다. 
 레디스 데이터 타입과 대응해보면 List -> array, Set -> set, Hash -> map에 해당합니다.
- 그리고 status(+), error(-) 같은 메시지도 CR, LF 같은 특수문자를 포함할 필요도 발생했습니다.
프로토콜(포멧) - 일반 데이터 타입
- Simple string: '+'     v2 status
 특수문자가 포함되지 않는 일반 문자열을 표시할 때 사용한다.
 포멧: +String<CR><LF>
- Simple error: '-'       v2 error
 특수문자가 포함되지 않는 에러 문자열을 표시할 때 사용한다.
 포멧: -ERR msg<CR><LF>
- Blob string: '$'       v2 bulk 
 특수문자가 포함된 문자열을 표시할 때 사용한다. binary safe
 포멧: $<length><CR><LF><String value><CR><LF>
 
- Blob error: '!' 
 특수문자가 포함된 문자열로 에러를 표시할 때 사용한다. binary safe
 포멧: !<length><CR><LF><Error String><CR><LF>
 
- Number:  ':'         v2 integer 
 정수를 표시할 때 사용한다. 사용 명령: LLEN, SCARD, 등
 포멧: :<number><CR<<LF>
 
- Big number:  '('         v2 bulk 
 큰 정수를 표시할 때 사용한다.
 포멧: (<big number><CR><LF>
- Double:  ','         v2 bulk 
 실수를 표시할 때 사용한다. ZSet의 스코어는 이 포멧을 사용한다.
 포멧: ,<double><CR><LF>
- Null:  '_'         v2 bulk "$-1\r\n" 
 널을 표시할 때 사용한다.
 포멧: _<CR><LF>
- Boolean:  '#'         v2 1/0 
 참/거짓을 표시할 때 사용한다.
 포멧: #t<CR><LF> #f<CR><LF>
- Verbatim string:  '=' 
 text를 그대로 출력할 때 사용
 사용하는 명령: INFO, MEMORY, CLIENT, LATENCY, CLUSTER
 포멧: =<length><CR><LF> txt:Some string <CR><LF> txt: plain text
 포멧: =<length><CR><LF> mkd:Some string <CR><LF> mkd: markdown
 mkd는 정의는 되어 있으나 아직 사용되지는 않는다. 위 명령은 모두 txt를 사용한다.
프로토콜(포멧) - 반복 지정
Array, Set, Map을 지정할 수 있습니다.- Array: *  
 반복을 지정할 때 사용한다. Array 안에 array를 또 지정할 수 있다.
 포멧: *<length><CR><LF> v2 multibulk
 
 List에서 사용 예
 ZSet에서 사용 예
 레디스에서 아래와 같이 사용하는 경우는 없습니다만, 프로토콜 상으로는 가능합니다.
- Set: ~  
 반복을 지정할 때 사용한다. 레디스 데이터 타입 Set에서 사용한다.
 이 구분자로 데이터를 받으면 Java의 Set 컬렉션을 사용하면 된다.
 포멧: ~<length><CR><LF> v2 multibulk
 
 Set에서 사용 예: ~3
 레디스에서 아래와 같이 사용하는 경우는 없습니다만, 프로토콜 상으로는 가능합니다. ~5
- Map: %  
 Map 반복을 지정할 때 사용한다. 레디스 데이터 타입 Hash에서 사용한다.
 이 구분자로 데이터를 받으면 Java의 Map 컬렉션을 사용하면 된다.
 포멧: %<length><CR><LF> v2 multibulk
 
 Hash에서 사용 예: %2 레디스에서 아래와 같이 사용하는 경우는 없습니다만, 프로토콜 상으로는 가능합니다.
프로토콜(포멧) - 스트리밍(Streaming)
전체 데이터의 길이를 모를 경우 사용할 수 있습니다.*, %, $ 다음에 '?'를 사용합니다.
*, %의 END 구분자는 .<CR><LF> 이고
$의 END 구분자는 ;0<CR><LF> 입니다.
레디스에서 실제 사용되지는 않습니다.
- Array *? 사용 예
- Map %? 사용 예
- Bulk $? 사용 예
RESP 버전 2 - Functions
공통
- void addReply(client *c, robj *obj)
- addReply(c,shared.mbulkhdr[ll]); - "*%d\r\n"
- addReply(c,shared.bulkhdr[ll]); - "$%d\r\n"
- addReply(c,shared.nullbulk); - "$-1\r\n" --> RESP3: addReplyNull(c);
- addReply(c,shared.czero); - ":0\r\n"
- addReply(c,shared.cone); - ":1\r\n"
- addReply(c,shared.ok); - "+OK\r\n"
- addReply(c,shared.syntaxerr); "-ERR syntax error\r\n"
 
- RESP2와 3에서 이름이 변경된 functions.
- void addReplyString(client *c, const char *s, size_t len) --> RESP3:
 void addReplyProto(client *c, const char *s, size_t len)
- void *addDeferredMultiBulkLength(client *c) --> RESP3:
 void *addReplyDeferredLen(client *c)
- void setDeferredMultiBulkLength(client *c, void *node, long length) --> RESP3:
 void setDeferredReply(client *c, void *node, const char *s, size_t length)
- void addReplyMultiBulkLen(client *c, long length) --> RESP3:
 void addReplyArrayLen(client *c, long length)
- void _addReplyStringToList(client *c, const char *s, size_t len) --> RESP3:
 void _addReplyProtoToList(client *c, const char *s, size_t len)
 
- void addReplyString(client *c, const char *s, size_t len) --> RESP3:
Status: 구분자 +
- void addReplyStatus(client *c, const char *status)
- void addReplyStatusLength(client *c, const char *s, size_t len)
- void addReplyStatusFormat(client *c, const char *fmt, ...)
Error: 구분자 -
- void addReplyError(client *c, const char *err)
- void addReplyErrorLength(client *c, const char *s, size_t len)
- void addReplyErrorFormat(client *c, const char *fmt, ...)
Integer: 구분자 :
- void addReplyLongLong(client *c, long long ll)
- void addReplyLongLongWithPrefix(client *c, long long ll, char prefix)
Bulk: 구분자 $
- void addReplyString(client *c, const char *s, size_t len)
- void addReplyBulk(client *c, robj *obj)
- void addReplyBulkLen(client *c, robj *obj)
- void addReplyBulkCBuffer(client *c, const void *p, size_t len)
- void addReplyBulkSds(client *c, sds s)
- void addReplyBulkCString(client *c, const char *s)
- void addReplyBulkLongLong(client *c, long long ll)
- void addReplySds(client *c, sds s)
- void addReplyDouble(client *c, double d) - $%d\r\n%s\r\n
- void addReplyHumanLongDouble(client *c, long double d)
Multibulk: 구분자 *
- void addReplyMultiBulkLen(client *c, long length)
 --> RESP3: addReplyArrayLen(client *c, long length)
- void *addDeferredMultiBulkLength(client *c)
 --> RESP3: addReplyDeferredLen(client *c)
- void setDeferredMultiBulkLength(client *c, void *node, long length)
 --> RESP3: setDeferredArrayLen(client *c, void *node, long length)
RESP 버전 3 - Functions
공통
- void addReply(client *c, robj *obj)
Simple string: '+' v2 status
- void addReplyStatus(client *c, const char *status)
- void addReplyStatusLength(client *c, const char *s, size_t len)
- void addReplyStatusFormat(client *c, const char *fmt, ...)
Simple error: '-' v2 error
- void addReplyError(client *c, const char *err)
- void addReplyErrorLength(client *c, const char *s, size_t len)
- void addReplyErrorFormat(client *c, const char *fmt, ...)
- void afterErrorReply(client *c, const char *s, size_t len)
- void addReplyErrorObject(client *c, robj *err)
- void addReplyErrorSds(client *c, sds err)
Blob string: '$' v2 bulk
- void addReplyProto(client *c, const char *s, size_t len)
- void addReplyBulk(client *c, robj *obj)
- void addReplyBulkLen(client *c, robj *obj)
- void addReplyBulkCBuffer(client *c, const void *p, size_t len)
- void addReplyBulkSds(client *c, sds s)
- void addReplyBulkCString(client *c, const char *s)
- void addReplyBulkLongLong(client *c, long long ll)
- void addReplySds(client *c, sds s)
Blob error: '!'
- Blob error를 사용하는 function은 없다.
Number: ':' v2 integer
- void addReplyLongLong(client *c, long long ll)
- void addReplyLongLongWithPrefix(client *c, long long ll, char prefix)
Big number: '(' v2 bulk
- void addReplyBigNum(client *c, const char* num, size_t len) - resp2 $, resp3 (
Double: ',' v2 bulk
- void addReplyDouble(client *c, double d) - ,%.17g\r\n
- void addReplyHumanLongDouble(client *c, long double d)
Null: '_' v2 bulk "$-1\r\n"
- void addReplyNull(client *c) - resp2 "$-1\r\n", resp3 "_\r\n"
Boolean: '#' v2 1/0
- void addReplyBool(client *c, int b) - resp2 shared.cone, shared.czero, resp3 "#t\r\n", "#f\r\n"
Verbatim string: '='
- void addReplyVerbatim(client *c, const char *s, size_t len, const char *ext) - "=%zu\r\nxxx:" txt, mkd
Aggregate: *,~,%,|,>
- void addReplyAggregateLen(client *c, long length, int prefix)
- void setDeferredAggregateLen(client *c, void *node, long length, char prefix)
Array: *
- void addReplyArrayLen(client *c, long length)
- void *addReplyDeferredLen(client *c)
- void setDeferredArrayLen(client *c, void *node, long length)
Set: ~
- void addReplySetLen(client *c, long length) -> int prefix = c->resp == 2 ? '*' : '~';
- void setDeferredSetLen(client *c, void *node, long length) int prefix = c->resp == 2 ? '*' : '~';
Map: %
- void addReplyMapLen(client *c, long length) -> int prefix = c->resp == 2 ? '*' : '%';
- void setDeferredMapLen(client *c, void *node, long length) int prefix = c->resp == 2 ? '*' : '%';
Attribute: |
- void addReplyAttributeLen(client *c, long length) c->resp >= 3
- void setDeferredAttributeLen(client *c, void *node, long length) -> '|' c->resp >= 3
Push: >
- void addReplyPushLen(client *c, long length) c->resp >= 3
- void setDeferredPushLen(client *c, void *node, long length) -> '>' c->resp >= 3
| << Stream | RESP | 
|---|
	Email
	
	
	답글이 올라오면 이메일로 알려드리겠습니다.
	
 


 
  
			 
			