Redis Enterprise Release Notes



Enterprise 6.1.1 - 2020년 5월 25일(월)

ver 6.1.1 내용 정리

  1. redis.db 파일을 data-dir에 놓는다.
  2. flushall 명령을 실행하면 redis.db에 있는 redis 테이블을 drop하고 create한다. 그래서 모든 데이터를 지운다. nkeys, rowid도 0으로 초기화한다.
  3. 레디스 서버 시작할 때 AOF/RDB 로드 중 메모리가 부족하면 서버를 중지(exit)한다. 동기화(sync) 중 메모리가 부족한 경우에는 로드를 중지하고 서버 로그를 남긴다. 서버를 중지하지는 않는다.
  4. Startsync로 동기화 시 받은 rdb 파일이 maxmemory 보다 크면 로드하지 않는다. Maxmemory가 설정된 경우만 체크한다. readSyncBulkPayloadClone()
  5. Startsync 명령이 중복해서 실행되지 않도록 했다. server.startsync 서버 시작 시 redis.conf에 있는 startsync는 중복이 허용된다.
  6. Startsync 명령이 2분(120초) 동안 성공하지 못하면 취소한다. 서버 시작 시 redis.conf에 있는 startsync는 5분 동안 성공하지 못하면 취소한다.
  7. db info 명령에 server.nkeys, server.rowid 추가했다.
  8. stat.log에 server.nkeys, server.rowid 추가했다.
  9. serverCron() LL_VERBOSE, used_memory human 표시 추가했다.
  10. ls * value: redis 테이블에서 모든 데이터를 읽어오고 테이블에서는 삭제한다. ls * val: redis 테이블에서 모든 데이터를 읽오기만 한다.

ver 6.1.1 소스 정리

  1. server.h
    1. checkMemoryAndExitIfNeeded()에서 AOF/RDB를 구분하기 위해 만들었다.
      /* 2020.05.24(Sun) ver 6.1.1 Use checkMemoryAndExitIfNeeded() */
      #define AOF 0
      #define RDB 1
    2. struct redisServer
    3. 리턴값을 받기 위해 void를 int로 변경했다.
      int checkMemoryAndExitIfNeeded(int); /* 2020.05.22(Fri) ver 6.1.1 */
    4. 4) flushall에 redis table drop, create하기 위해 추가했다.
      /* 2020.05.24(Sun) ver 6.1.1 */
      int createTable(void);
      int dropTable(void);
  2. server.c
    1. VERBOSE 로그에서 5초마다 한번씩 찍히는 메시지에서 메모리 사용량(used_memory)를 humam으로 표시하기 위해 추가했다.
      /* 2020.05.23(Sun) ver 6.1.1 Charlie, 2 lines */
      char hmem[64];
      size_t zmalloc_used = zmalloc_used_memory();
    2. 위에서 zmalloc_used를 구했으므로 매번 zmalloc_used_memory() 호출하던 것을 이미 계산해 놓은 것을 사용하는 것으로 변경했다.
      /* 2020.05.23(Sun) ver 6.1.1 Modify zmalloc_used_memory() -> zmalloc_used */
      if (zmalloc_used > server.stat_peak_memory)
          server.stat_peak_memory = zmalloc_used;
    3. VERBOSE 로그에서 5초마다 한번씩 찍히는 메시지에서 human으로 표시한다.
      /* 2020.05.23(Sun) ver 6.1.1 bytesToHuman */ bytesToHuman(hmem,zmalloc_used); serverLog(LL_VERBOSE,     "%lu clients connected (%lu replicas), %s(%zu bytes) in use",     listLength(server.clients)-listLength(server.slaves),     listLength(server.slaves),hmem,zmalloc_used);
    4. initServerConfig()에 redisServer에 추가한 nkeys,startsync를 초기화한다.
      server.nkeys = 0; /* 2020.05.24(Sun) ver 6.1.1 Number of keys in redis.db file */
      server.startsync = 0; /* 2020.05.24(Sun) ver 6.1.1 startsync 여부, 증가 */
    5. stat.log serverInfoLog()에 redisServer의 nkeys,rowid를 추가했다.
      /* 2020.05.24(Sun) ver 6.1.1 Add nKeys,rowid */
      info = sdscatprintf(info,
      "%-21s Memory=%s,Rss=%s,Keys=%lld,Cpu=%ld,Clients=%ld,Cmd=%lld,Conn=%lld,
      nKeys=%ld,rowid=%ld", tmbuf,hmem,rss_hmem,keys,cpu,clients,server.stat_numcommands,server.stat_numconnections
      ,server.nkeys,server.rowid);
  3. clone.c
    1. 1) readSyncBulkPayloadClone()
      repl_transfer_size(받을 데이터(파일) 크기)가 maxmemory보다 크면 로드하지 않는다.
    2. 2) readSyncBulkPayloadClone() RDB load가 실패했을 경우 AOF를 rewrite하는 기능인데 여기서는 불필요하고 오히려 서버의 성능을 떨어뜨리린다.
      startsync했을 경우 메모리가 부족하면 load를 중지하고 에러를 리턴하는데 그때마다 AOF rewrite는 매우 부담되는 작업이다. 그리고 startsync는 실패하면 120회(2분) 반복 시도한다. 그때마다 AOF rewrite는 정말 필요없다.
    3. 3) startSyncCommand() startsync를 명령으로 입력해서 실행했을 경우 완료되면 다음 명령을 실행할 수 있다. 서버 시작 시 redis.conf에 있는 startsync 명령은 중복해서 실행 가능하다.
    4. 4) startSyncCommand() startsync가 정상적으로 시작되었으면 1로 설정한다.
    5. 5) endSyncCommand() endsync가 정상적으로 완료되었으면 0으로 설정한다.
    6. 6) cloneCron() 1초마다 실행되는 cloneCron에 startsync 증가를 추가했다. 이 값이 120이 넘으면 startsync를 취소한다.
    7. 7) cloneCron() 이것은 명령으로 startsync를 입력했을 경우에 2분이 적용된다. 서버 시작 시에 실행된 startsync는 5분이 지나면 취소된다.
  4. db.c
    1. 1) flushallCommand() flushall 명령을 실행하면 redis.db에 있는 redis 테이블을 삭제하고 다시 생성한다. 데이터를 모두 지웠으므로 파일에도 쓰레기를 남겨놓을 필요가 없다. sqlite에는 truncate table 명령이 없다.
    2. 2) keysCmdGate() restore_value 변수 추가 이것은 메모리 부족으로 redis.db 파일에 저장된 데이터를 모두 메모리로 올리기 위해서 사용한다.
      redis.db에 데이터가 있으면 background로 AOF rewrite, RDB save를 수행할 수 없다. 왜냐하면 parent와 child가 한 파일을 접근할 수 없기 때문이다. Child가 접근하면 database lock이 발생한다. 이것은 bgrewriteaof, bgsave 명령을 실행할 수 없고, startsync, replicaof 명령을 실행할 수 없음을 의미한다.
      Maxmemory를 증가시키고 ls * value 명령으로 모든 데이터를 메모리로 올리고 redis.db에서는 삭제한다. 그러면 위에서 설명한 background 명령을 실행할 수 있다. ls * val을 사용하면 redis.db에서 삭제하지 않는다. 값을 조회하는 용도일 때는 이 옵션을 사용한다.
    3. keysCmdGate() 'value', 'val'을 구분해서 처리한다.
    4. keysCmdGate() restore_value, restore_val 값에 따라 그에 맞는 function을 호출한다.
    5. dbsizeInfo() db info 명령에서 expire member 관련 표시 2개를 삭제했다. 너무 많은 숫자가 나와서 필요한 정보를 보는데 방해된다. 만든 나도 시간이 지나서 보면 뭘 의미하는지 잘 기억나지 않는다.
    6. dbsizeCommand() db info 명령에 nkeys,rowid 를 추가했다.
  5. evict.c
    1. checkMemoryAndExitIfNeeded() 아래 2가지 경우에 호출된다.
      aof.c: loadAppendOnlyFile() checkMemoryAndExitIfNeeded(AOF)
      rdb.c: rdbLoadRio() checkMemoryAndExitIfNeeded(RDB)
    2. 2) freeMemoryBySave()
      1) timelimit 100ms를 초과하면 서버 로그를 남긴다.
      2) DB에 키가 없는데 메모리가 부족할 경우 서버 로그를 남긴다.
          repl_backlog_size를 maxmemory보다 크게했을 경우 발생한다.
  6. rdb.c
    1. 1) rdbSaveRio() redis.db에 값이 없거나 child일 때는 에러 처리한다.
    2. 2) rdbSaveRio() 메모리 부족으로 에러가 발생해도 이미 로드한 데이터는 그대로 둔다. freeMemoryForLoading()는 사용하지 않는다.
  7. aof.c
    1. 1) loadAppendOnlyFile()
  8. 8. persist.c
    1. 1) openSqliteDb() redis.db 파일이 data-dir에 생기게 수정했다.
    2. 2) insertSql(), deleteSql() redis table에 insert하면 1 증가, delete하면 1 감소 이 숫자로 redis table에 있는 값의 개수를 알 수 있다.
    3. 3) restoreValNoDelete() Child이면 에러를 리턴한다. Child는 redis.db에 접근할 수 없다. 접근하도록 허용하면 database lock이 발생한다.

ver 6.1.1 테스트

  1. 서버 시작 시 maxmemory보다 큰 AOF/RDB 파일 로드
    결과: 서버 중지
  2. Startsync(동기화) 테스트1: 소스 서버 문제
    소스 서버에서 파일을 작성하지 못했을 경우
    6000번 서버가 메모리가 부족해서 redis.db에 데이터가 있는 경우
    6001번 서버에서 startsync를 실행하면
    6000번 서버는 background로 RDB 파일을 만드는 중 select하면 RDB 파일 작성을 중지하고 에러를 리턴한다.
    6001번 서버는 에러를 받고 동기화를 중지하고 1초 후에 다시 시도한다. 2분이 지나도 성공하지 못하면 동기화를 취소한다.
  3. Startsync(동기화) 테스트2: 타겟 서버 문제
    타겟 서버의 maxmemory보다 큰 파일을 받았을 경우
    6001번 서버는 파일을 받기 전에 사이즈를 확인해서 maxmemory보다 크면 동기화를 중지하고 1초 후에 다시 시도한다. 2분이 지나도 성공하지 못하면 동기화를 취소한다.
  4. Startsync(동기화) 테스트3: 타겟 서버 문제
    타겟 서버에서 RDB 파일을 로드 중 maxmemory를 초과하면 로드를 중지한다. 이미 로드된 데이터는 그대로 둔다.
  5. Startsync(동기화) 테스트4: 서버 시작 시
    5분 동안 성공하지 못하면 취소한다.

Enterprise 6.1.0 - 2020년 5월 22일(금)

메모리 한계를 넘다.

메모리 부족 시 key(data)를 지우지 않고 sqlite db에 저장해서 데이터 유실없이 계속 사용하게 했다.

2020년 2월 9일 최초 버전이 startsync 시 CPU 100%를 사용하는 문제가 있어서 재작업했다.
  1. redisObject에 rowid(8바이트)를 추가했다.
    • val->rowid를 구해서(++server.rowid) db에 id, value를 저장한다.
    • rowid가 0 보다 크면 value가 db에 저장되어있는 것이다.
    • db 저장 조건: val->rowid > 0 and val->ptr == NULL
    • Module와 String의 embstr, int는 대상에 제외한다.
  2. redisServer.rowid id를 구하는 전역변수이다.
    • insert 시마다 1씩 증가시킨다. int64
  3. table: redis id integer primary key, value blob
    • insert into redis(id,value) values(:id,:value);
    • select value from redis where id=:id;
    • delete from redis where id=:id;
    • key는 저장하지 않는다. key를 사용하면 int id보다 속도가 느리다.
  4. persist.c
    • opendb: redis.db를 오픈하고 redis table을 만든다. 서버 초기화 시 수행.
    • closedb: redis.db를 close한다.
    • insertSql: value를 insert한다.
    • selectSql: value를 select한다.
    • deleteSql: value를 delete한다.
    • saveVal: evict.c에서 메모리 부족 시 saveVal()를 호출해서 value를 db에 저장한다.
    • restoreVal: 대분분의 명령 실행 시 value가 db에 저장되어 있으면 select해서 원래대로 복원한다.
    • insertCommand: value를 db에 저장한다. 테스트용.
    • Module와 String의 embstr, int는 대상에 제외한다.
  5. serialize.c
    • rdb.c를 참조해서 만들었다.
    • table에 저장할 value를 serialize하는 목적이다.
    • Serialize해서 value에 저장한다. 그러므로 select value해도 그냥 볼 수 없다.
    • 기본적으로 rdb format과 같다.
    • Module은 대상에 제외한다.
  6. evict.c
    • 메모리 부족 시 제거 대상 키를 선별한다.
    • 선별된 key의 value를 sqlite db에 저장한다.
    • evictionPoolPopulate() 제외 대상 추가
    • freeMemoryIfNeeded() db에 저장하는 saveVal() 추가
  7. db.c
    • lookupKey: restoreVal() 추가 Value를 필요로하는 대부분의 명령에 적용된다.
    • dbSyncDelete: deleteSql() 추가 db에 저장된 key를 삭제할 때 사용된다. expire 일때도 같이 적용된다.
    • keysCmdGate에 rowid를 추가했다. lsCommand에 적용된다.
  8. server.c
    • initServerConfig: sqlite_dbfile, sqlitedb, table, iStmt, sStmt, dStmt, rowid 초기화
    • initServer: initSqliteDb() 추가.
    • prepareForShutdown: closeSqliteDb() 추가.
  9. object.c
    • createObject: rowid=0 초기화
    • OBJ_ENCODING_EMBSTR_SIZE_LIMIT 28로 변경
    • freeObject(): val->ptr만 free() 한다.
  10. sqlite.c 추가
  11. server.h
    • include "sqlite3.h"
    • redisObject int64_t rowid 추가
    • redisServer
      • sqlite_dbfile
      • sqlitedb
      • table
      • iStmt
      • sStmt
      • dStmt
      • rowid

Enterprise 6.0.4 - 2020년 5월 19일(월)

  1. startsync가 redis.conf에 있을 때는 IP:Port 자기 자신인지 체크하는 부분 추가
    startSyncCommand()에서는 이미 체크하고 있었다.
    config.c loadServerConfigFromString()

Enterprise 6.0.3 - 2020년 5월 17일(일)

  1. 마스터 클론과 연결이 끊긴지 5분이 지나면 클론을 삭제하고 더 이상 연결을 시도하지 않는다. serverLog()에 연결이 끊긴 경과 시간을 초로 표시했다. 1) clone.c cloneCron() 수정 2) clone.c readSyncBulkPayloadClone() server.current_clone = NULL; 추가 3) server.h ELAPSE_MIN1,2,5 추가 4) version.h -> 6.0.3
  2. networking.c checkClientOutputBufferLimits() 수정 client-output-buffer-limit parameter 관련해서 hard or soft limit를 초과했을 때 serverLog() 추가.
  3. config.c configCommand() 수정 config set 또는 resetstat 명령을 실행하면 로그를 남김. config set/resetstat serverLog() 추가
  4. config.c loadServerConfigFromString() 수정 redis.conf 파일에 auto-aof-rewrite-spec-time이 "" 또는 Null 일 때 처리

Enterprise 6.0.2 - 2020년 4월 11일(토)

  1. Upgrade: AOF 파일 Rewrite를 시간(hh24:mm)을 지정해서 실행하게 한다.
    keyword: AOF 시간 지정
    1. redis.conf: Add parameter: auto-aof-rewrite-spec-time hh24:mm
    2. struct redisServer
      aof_rewrite_spec_time hh24:mm or NULL, 분 단위까지 지정한다.
      aof_rewrite_spec_hour int <- hh24, range 00-23, default -1
      aof_rewrite_spec_minute int <- mm, range 00-59, default -1
      aof_rewrite_last_run_time : 마지막으로 AOF rewrite가 실행된 시간을 저장한다.
      spec_time에 여러 번 실행되지 않게 하기 위해서.
    3. server.h struct redisServer
    4. version.h -> 6.0.2
    5. server.c serverCron(), initServerConfig()
    6. aof.c backgroundRewriteDoneHandler()
    7. config.c loadServerConfigFromString()
      configSetCommand() config set
      configGetCommand() config get
      rewriteConfig() config rewrite

Enterprise 6.0.1 - 2020년 3월 19일(목)

  1. slowlog.c slowlogLog() strncat() 관련 수정. 2002.03.19(목) 버그로 서버 다운 발생.
  2. version.h 6.0.1로 수정.

Enterprise 6.0.0 - 2019년 12월 21일(토)

  1. version.h에 ENT_VERSION 추가. 2019.11.12(Tue)
    • server.c info()에 ENT_VERSION 추가
    • redis-cli.c help에 ENT_VERSION 추가 redis-cli를 redis-ecli로 수정
  2. serverLog() date format 변경: YYYY-mm-DD HH:MM:SS.fff. 2019.11.14(Thu)
    server.c 수정.
  3. Lua script: 2019.12.21(Sat)
    • command: update_mstime 적용
    • 클론에 전파 완료
    • Script list 명령 추가
    • Script info 명령 추가
    • Script get 명령 추가
  4. SET. 2020.01.03(Fri)
    • sls myset val* 명령 추가.
    • srm myset val* 명령 추가

Enterprise 2019.09.15 버전 Based on Redis 5.0.4 - 2019년 9월 15일(일)

  1. Slowlog 명령에 geth, log 옵션 추가
  2. Latency 명령에 latesth, historyh, log 옵션 추가
  3. Server 모니터링 정보(stat, slowlog, latency) 기록 기능 추가
  4. Log dir, Data dir 구분 설정 기능 추가
    Log directory: redis.log, stat.log, slowlog.log, latency.log
    Data directory: appendonly.aof, dump.rdb

Enterprise 2019.08 버전 Based on Redis 5.0.4 - 2019년 8월 31일(수)

  1. Expire Member 기능 추가
    1. EXPIRE key members: 멤버에 expire 기능 추가
      • 사용 가능 데이터타입: SET, ZSET, HASH
      • EXPIRE myset member 10 <seconds>
      • EXPIRE myset member1 member2 10 <seconds>
    2. EXPIRE members를 구현하기 위해 redisDb에 expire_keys(ZSET), expire_members(dict), expire_member_count(long long)를 추가했다.
    3. SETs: SADD에 expire member 기능 추가
      • SADD myset member ex 10 <seconds>
      • SADD myset member1 member2 ex 10 <seconds>: multi member 가능
      • SADD myset (get key) ex 10 <seconds>: subquery 가능
    4. ZSETs: ZADD에 expire member 기능 추가
      • ZADD myzset 10 mem1 ex 10 <seconds>
      • ZADD myzset 10 mem1 20 mem2 ex 10 <seconds>: multi member 가능
      • ZADD myzset (get key) ex 10 <seconds>: subquery 가능
    5. HASHs: HSET에 expire member 기능 추가
      • HSET myhash f1 v1 ex 10 <seconds>
      • HSET myhash f1 v1 f2 v2 ex 10 <seconds>: multi member 가능
      • HSET myhash (get key) ex 10 <seconds>: subquery 가능
    6. TTL key member: 멤버 ttl 조회 기능 추가
    7. PERSIST key member: 멤버단위로 설정된 만료시간을 삭제하는 기능 추가
    8. RENAME 명령: 내부적으로 만료시간이 설정된 멤버가 있는지 확인해서 db->expire_keys, db->expire_members에 키 이름 변경 기능 추가
    9. MOVE 명령: 내부적으로 만료시간이 설정된 멤버가 있는지 확인해서 해당 키를 이동하는 기능 추가
    10. 키가 삭제(DEL, EXPIRE)될 때 내부적으로 만료시간이 설정된 멤버가 있는지 확인해서 같이 삭제하는 기능 추가
    11. SREM 명령: 내부적으로 만료시간이 설정된 멤버가 있는지 확인해서 만료시간을 삭제하는 기능 추가
    12. ZREM 명령: 내부적으로 만료시간이 설정된 멤버가 있는지 확인해서 만료시간을 삭제하는 기능 추가
    13. HDEL 명령: 내부적으로 만료시간이 설정된 멤버가 있는지 확인해서 만료시간을 삭제하는 기능 추가
    14. SET, ZSET, HASH: 멤버를 조회할 때 expire된 멤버가 있는지 확인해서 있으면 삭제하는 기능 추가
    15. databasesCron()에 설정된 멤버를 삭제하는 기능 추가
    16. DBSIZE INFO 명령: expire member 정보 표시하는 기능 추가
  2. redis-cli: Enterprise 버전 표시
  3. redis-cli: --stat에 옵션 추가
    • -pagesize 추가: pagesize 지정
    • -t 추가: 출력에 일시(date,time) 추가
  4. SELECT 명령: index를 입력하지 않으면 0번 DB로 이동
  5. SERVER_INFO_INTERVAL: redis.conf에 추가
    • 서버 정보를 일정 시간 마다 redis.log 파일에 찍는다.
  6. SMEMBERS multi key 기능 추가
    • SMEMBERS key1 key2 가능
    • SMEMBERS key1 key2 sort 가능
  7. HGETALL, HKEYS, HVALS multi key 기능 추가
    • HGETALL key1 key2 가능
    • HKEYS key1 key2 가능
    • HVALS key1 key2 가능
  8. Redis-server 시작 직후(data load 후)와 종료할 때 redis.log에 dbsize 정보 기록

Enterprise 2019.06 버전 Based on Redis 5.0.4 - 2019년 6월 30일(일)

  1. ZRANGE JOIN 기능 추가
    1. 대상 명령
    2. ZSETs 키들과 조인할 수 있고, HMGET 명령으로 HASHs 키와 조인할 수 있고, GET 명령으로 STRINGs 키와 조인해서 값을 조회할 수 있습니다.
  2. Data Type별 키 관리 기능 추가
    1. 내부 처리
      • redisDb에 robj *datatypes[] 추가
      • 키가 추가될 때 저장: dbAdd()에 기능 추가
      • 키가 삭제될 때 삭제: dbSyncDelete(), dbAsyncDelete()에 기능 추가
      • flushdb(), flushall(): emptyDb()에 기능 추가
    2. KEYS 명령에 기능 추가
      • KEYS * string: String type의 키들만 조회
      • KEYS * list set: List와 set type의 키들을 조회
    3. DBSIZE INFO 명령에 data type별 키 개수 조회 기능 추가
  3. Subquery 기능 추가
    1. Subquery가 가능한 명령과 subquery로 사용 가능한 명령
      * 사용 예) SET key (GET key1)
      • SET: GET, LPOP, RPOP, LINDEX, LRANGE, HGET
      • APPEND: GET, MGET, LPOP, RPOP, LINDEX, LRANGE, SMEMBERS, SUNION, SINTER, SDIFF, ZRANGE, ZREVRANGE, HGET, HMGET, HKEYS, HVALS, HGETALL
      • LPUSH: GET, MGET, LPOP, RPOP, LRANGE, SMEMBERS, SUNION, SINTER, SDIFF, ZRANGE, ZREVRANGE, HGET, HMGET, HKEYS, HVALS, HGETALL
      • RPUSH: GET, MGET, LPOP, RPOP, LRANGE, SMEMBERS, SUNION, SINTER, SDIFF, ZRANGE, ZREVRANGE, HGET, HMGET, HKEYS, HVALS, HGETALL
      • SADD: GET, MGET, LPOP, RPOP, LRANGE, SMEMBERS, SUNION, SINTER, SDIFF, ZRANGE, ZREVRANGE, HGET, HMGET, HKEYS, HVALS, HGETALL
      • ZADD: GET, MGET, LPOP, RPOP, LRANGE, SMEMBERS, SUNION, SINTER, SDIFF, ZRANGE, ZREVRANGE, HGET, HMGET, HKEYS, HVALS, HGETALL, KEYS
      • HSET: GET, MGET, HGET, HMGET, HGETALL
      • XADD: HGETALL, ZRANGE, ZREVRANGE
      • DEL: GET, MGET, LPOP, RPOP, LRANGE, SMEMBERS, SUNION, SINTER, SDIFF, ZRANGE, ZREVRANGE, HGET, HMGET, HKEYS, HVALS, HGETALL, KEYS
      • UNLINK: GET, MGET, LPOP, RPOP, LRANGE, SMEMBERS, SUNION, SINTER, SDIFF, ZRANGE, ZREVRANGE, HGET, HMGET, HKEYS, HVALS, HGETALL, KEYS
  4. 추가된 명령
    • LREVRANGE: LIST에서 오른쪽에서 왼쪽으로 조회, 소트 기능
    • ZISMEMBER: ZSET에서 멤버가 있는지 확인
  5. KEYS 명령에 많은 옵션 추가
  6. LRANGE 명령에 소트기능 추가
  7. LINSERT 명령에 인덱스로 특정 위치에 데이터 넣는 기능 추가
  8. LREM 명령에 인덱스로 값을 삭제하는 기능 추가
  9. SMEMBERS 명령에 소트 기능 추가
  10. SUNION, SINTER, SDIFF 명령에 소트 기능 추가
  11. XRANGE, XREVRANGE 명령에 필드명으로 조회하는 기능 추가

조회수 :

Email 답글이 올라오면 이메일로 알려드리겠습니다.