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
	
	
	답글이 올라오면 이메일로 알려드리겠습니다.
	
 
