Redis DEBUG subcommand

Redis Server Course Redis Technical Support Redis Enterprise Server

DEBUG

레디스 서버 테스트, 디버그 용으로 사용할 수 있는 명령입니다.
redis.io에는 설명이 너무 간단해서, debug 명령을 활용할 수 있도록 정리했습니다.
Subcommand를 클릭하면 해당 설명 섹션으로 넘어갑니다.
이 문서는 5.0.2를 기준으로 작성되었습니다.

Data Structure 관련 명령


DEBUG HELP

debug 도움말이다.

  • help에는 4) 번이 crash-and-recovery로 나오는데, 실제 명령은 crash-and-recover로 'y'를 빼야한다.
  • 4) 번 다음에 *) oom은 help에는 없으나, 실제 명령은 사용할 수 있으므로 넣었다.

DEBUG SEGFAULT

Help: Crash the server with sigsegv.
redis.io 설명: performs an invalid memory access that crashes Redis. It is used to simulate bugs during the development.

소스코드: debugCommand()   debug.c

debug 명령으로 서버를 crash할 수 있는 subcommand가 4개 있다.
segfault, crash-and-recover, oom, assert 이 중에서 crash-and-recover는 아무 로그도 남기지 않지만, 나머지 3개 subcommand는 버그 리포트를 남긴다.
버그 리포트는 크게 두 부분으로 나눌 수 있는데, 앞 부분은 각 subcommand 마다 다르게 나오고, 이후 부분은 공통이다.

segfault에만 나오는 내용


공통으로 나오는 버그 리포트

  • stack trace: 어느 function에서 에러가 났는지 보여준다.
  • info output: info 명령을 실행했을 때 나오는 정보이다.   info 명령에 대한 자세한 내용은 여기를 보세요.
  • client 정보: client list 정보와 현재 client 정보를 보여준다.
  • registers: 레지스터 정보를 보여준다.
  • fast memory test: 정보를 보여준다.

DEBUG RESTART

Help: Graceful restart: save config, db, restart.
버전 3.2.0에서 추가되었다.
config(설정) 정보를 rewrite 하고, RDB, AOF 데이터를 디스크에 쓰고, 서버를 재시작한다.   재시작은 시스템 콜 execvc()를 실행하므로 같은 PID를 이어받는다.   재시작 시 delay는 없다.
debug.c에서 restartServer(flags,delay=0) 실행한다. 이 function은 server.c에 있다.
flags 정보: flags = (RESTART_SERVER_GRACEFULLY|RESTART_SERVER_CONFIG_REWRITE)
다음은 restartServer()에서 수행해는 내용이다.

  • config 정보를 다시 쓴다.   rewriteConfig(server.configfile);
  • 서버를 정리하고 shutdown 한다.   prepareForShutdown(SHUTDOWN_NOFLAGS);
    • rdb child process가 있으면 kill 하고 tempfile을 지운다.
    • AOF rewrite 중(AOF_WAIT_REWRITE)이면 shutdown하지 않는다.   그렇지 않으면(AOF_ON) aof child process를 kill 한다.   AOF child process가 있으면서 kill 되는 시간은 rewrite 직전, 직후 아주 짧은 시간이다.
    • AOF fsync()를 한다.
    • RDB file을 save 한다.
    • 데이터를 슬레이브 노드에 flush 한다.   flushSlavesOutputBuffers();
    • 소켓을 닫는다.   closeListeningSockets(1);
  • 서버를 재시작한다.   execve(server.executable,server.exec_argv,environ);
  • 소스코드: debugCommand()   debug.c

DEBUG CRASH-AND-RECOVER <milliseconds>

Help: Hard crash and restart after <milliseconds> delay.
버전 3.2.0에서 추가되었다.
아무 로그도 남기지 않는다.   위에 설명한 restart 처럼 restartServer(flags,delay=ms) 실행하는데, 플래그(flags = RESTART_SERVER_NONE)를 아무것도 하지 않는 것으로 넘긴다.   milliseconds 후에 execve()로 재시작한다.


DEBUG OOM

Out Of Memory
debug help에는 나오지 않는다.   소스에서는 아래와 같은 방법으로 OOM을 발생시킨다.
ULONG_MAX 값은 18,446,744,073,709,551,615ULL로 18엑사바이트이다.
kB -> MB -> GB -> TB -> PB(페타) -> EB(엑사) -> ZB(제타) -> YB(요타)

void *ptr = zmalloc(ULONG_MAX); /* Should trigger an out of memory. */
OOM에만 나오는 버그 리포트

공통으로 나오는 버그 리포트 중 STACK TRACE 부분
  • 소스코드: debugCommand()   debug.c

DEBUG ASSERT

Help: Crash by assertion failed.
debug assert하면 bug report를 남기고 레디스 서버가 죽는다.
debug.c에 있는 소스코드는 아래와 같다.

serverAssertWithInfo(c,c->argv[0],1 == 2);
assert에서는 마지막 인자가 False이면 서버가 죽는데, 1==2는 False이므로 서버가 죽는다.

Assert에만 나오는 버그 리포트



공통으로 나오는 버그 리포트 중 STACK TRACE 부분

  • 소스코드: debugCommand()   debug.c

DEBUG RELOAD [MERGE] [NOFLUSH] [NOSAVE]

데이터를 RDB 파일에 저장하고, 메모리에 있는 데이터를 지우고, RDB 파일을 다시 읽어들여 메모리에 넣는다.   3개 옵션(MERGE, NOFLUSH, NOSAVE)은 6.0부터 사용 가능합니다.

  • MERGE: 키가 충돌하면 기존 키를 지우고 로드한 키를 저장한다.
  • NOFLUSH: 메모리에 있는 데이터를 지우지 않는다.
  • NOSAVE: 메모리에 있는 데이터를 저장하지 않는다. 새로운 데이터를 로드할 때 사용한다.
  • 소스코드: debugCommand()   debug.c

DEBUG LOADAOF

Help: Flush the AOF buffers on disk and reload the AOF in memory.
AOF가 OFF 일때도 AppendOnlyFile을 읽어들인다.

  • AOF가 ON이면 아직 AppendOnlyFile에 쓰이지 않은 데이터를 flush 한다.   flushAppendOnlyFile(1)
    버전 3.2.0 이전에는 이 부분이 없었다.
  • 메모리에 있는 데이터 삭제한다.   emptyDb(NULL)
  • AppendOnlyFile을 읽어들인다.   loadAppendOnlyFile(server.aof_filename)
  • AOF나 슬레이브 노드에 전파(propagate)되는 것을 막기 위해 다음과 같이 셋팅한다.
    server.dirty = 0; /* Prevent AOF/replication */
  • 소스코드: debugCommand()   debug.c

DEBUG OBJECT

Help: Show low level info about key and associated value.
redis.io 설명: DEBUG OBJECT is a debugging command that should not be used by clients.   Check the OBJECT command instead.
Object 명령과 비슷한 정보를 보여주지만, 그것보다 더 자세하다.   object 명령에 대한 자세한 내용은 여기를 보세요.

입력된 예로써 각 항목을 설명한다.

127.0.0.1:6379> set key value
OK
127.0.0.1:6379> debug object key
Value at:0x7fd6e1eb70c0   refcount:1   encoding:embstr   serializedlength:6   lru:3916170   lru_seconds_idle:23

  • Value at: 값이 있는 메모리 주소(포인터),   소스코드: (void*)val
  • refcount: 값의 참조 횟수, 레디스는 메모리를 절약하기 위해서 0~9999까지 숫자는 미리 만들어 놓고 사용한다. 이 숫자들의 초기 refcount는 1이고, 실제 값이 입력되면 2가 된다.   다른 값은 입력되는 시점에 1이 된다. OBJECT refcount 명령은 여기를 참고하세요.
  • encoding: 데이터의 인코딩 타입이고 종류는 다음과 같다.   클릭하면 자세한 정보가 나옵니다.
    int, embstr, raw, ziplist, intset, quicklist, skiplist, hashtable
    OBJECT encoding 명령은 여기를 참고하세요.
  • serializedlength: RDB 파일에 저장할때 값의 길이다. 값 앞에 길이를 저장하는데, 이 길이 바이트까지 포함한 바이트 수이다.   압축되었을 경우는 압축된 길이를 나타낸다.   예에서 6인 이유는, 길이 5를 저장하는 1 바이트, "value" 5 바이트, 합해서 6 바이트입니다.
    RDB file format은 여기를 참고하세요.
  • lru: 키 생성 시 lru(Least Recently Used) time이 들어가고, access마다 변경된다.   이 값으로 idletime을 구하고, 메모리 정책에 따라 삭제될 키를 찾는데 사용된다.
  • lru_seconds_idle: 마지막 access 한 이후로 지난 시간을 초로 보여준다.
    OBJECT idletime 명령은 여기를 참고하세요.

  • 인코딩 타입이 Quicklist일때는 좀 더 자세한 정보를 보여준다.
    127.0.0.1:6379> lrange mylist 0 -1
    1) "0123456789"
    2) "01234567890123456789"
    3) "012345678901234567890123456789"
    127.0.0.1:6379> debug object mylist
    Value at:0x7fd6f56a74a0   refcount:1   encoding:quicklist   serializedlength:48   lru:3935360   lru_seconds_idle:10   ql_nodes:1   ql_avg_node:3.00   ql_ziplist_max:-2   ql_compressed:0   ql_uncompressed_size:77
    • ql_nodes: quicklist 노드수
    • ql_avg_node: 노드당 평균 값(엔트리) 개수, 계산식 = 총 entires(element) 수 / quicklist 노드수
    • ql_ziplist_max: ziplist 크기:   -1(4kb),  -2(8kb) default,   -3(16kb),   -4(32kb),   -5(64kb)
      이것은 redis.conf에 list-max-ziplist-size 파라미터와 관계가 있다.
      다음은 redis.conf에 나와있는 설명이다.
    • ql_compressed: 압축 여부: 0은 압축하지 않음, 1은 압축
      압축 방식(list-compress-depth)은 아래를 참조하세요.
      1은 head, tail 2개 노드는 압축하지 않고 나머지 노드는 압축한다.
      다음은 redis.conf에 나와있는 설명이다.
    • ql_uncompressed_size: 퀵리스트 모든 노드의 압축되지 않는 사이즈(바이트)이다.
      예에서 ql_uncompressed_size:77인것은 값 3개가 10, 20, 30바이트로 합하면 60바이트이고, 각 값마다 prelen, itself len이 각 1바이트씩, 2바이트가 들어가고, 짚리스트 헤더 10바이트, 테일(zlend) 1바이트, 총 77바이트이다.   계산식: 값(66)+길이(6)+헤더(10)+테일(1) = 77바이트.
      serializedlength 48은 77바이트 짚리스트 노드를 RDB 파일에 저장하기 위해서 합축했을때의 크기이다.
  • 소스코드: debugCommand()   debug.c

DEBUG SDSLEN

Help: Show low level SDS string info representing key and value.
SDS(Simple Dynamic Strings)는 레디스에서 string을 다루는 Library이다.   키와 값의 길이(바이트)와 할당했지만 아직 비어있어 사용 가능한 바이트수를 표시한다.   버전 2.8.0에서 추가되었다.

127.0.0.1:6379> set key value
OK
127.0.0.1:6379> debug sdslen key
key_sds_len:3, key_sds_avail:0, val_sds_len:5, val_sds_avail:0
대상은 데이터 타입이 string이고 문자열(embstr, raw)일때 가능하다.   값이 정수이면 안된다.

  • key_sds_len: 키에 널('\0') 문자를 제외한 순수 문자열 길이(바이트)
  • key_sds_avail: 키에 사용 가능한 공간 길이(바이트)
  • val_sds_len: 값에 널('\0') 문자를 제외한 순수 문자열 길이(바이트)
  • val_sds_avail: 값에 사용 가능한 공간 길이(바이트),   append 명령을 사용해서 큰 값(value)을 입력하면 0이 아닌 값(avail)을 볼 수 있다.
  • 소스코드: debugCommand()   debug.c

DEBUG POPULATE

Help: Create string keys named key:.   If a prefix is specified is used instead of the 'key' prefix.
테스트용 데이터를 생성할 때 사용된다.   버전 3.0에서 추가되었다.
클러스터에서는 사용하지 말 것.   슬롯을 고려하지 않고 dbAdd() function으로 바로 들어가므로 비정상적인 DB 상황이 된다.

  • 사용법: populate <count> [prefix]
  • <count>는 입력 횟수로, SET 명령 실행 횟수를 정하는 것이다. 생략할 수 없다.
  • [prefix]는 키를 정한다. 생략하면 'key'로 시작하는 키가 생성된다.   prefix는 키에만 영향을 미친다.
  • 아래는 실제 입력과 결과이다.
  • debug populate 100 -> key:1 value:1 ~ key:100 value:100
    debug populate 100 xxx -> xxx:1 value:1 ~ xxx:100 value:100
  • 소스코드: debugCommand()   debug.c

DEBUG DIGEST

Help: Outputs an hex signature representing the current DB content.
DIGEST는 데이터베이스 전체의 해시 값을 20 바이트로 계산합니다.   이 값으로 두 서버 데이터가 같은지 비교할 수 있습니다.   예를 들어 마스터와 슬레이브 DB 데이터가 같은지 확인할 수 있습니다.
이 명령은 CPU를 많이 사용하고, 명령이 수행되는 동안 다른 명령을 실행할 수 없으므로 사용시 주의가 필요합니다.

  • 실행 예
  • 127.0.0.1:6379> debug digest
    c471feae63d93dc4302e0db02c3b2da3d2e35d4f
    (3.10s)
  • 소스코드: Main function은 debug.c에 있는 computeDatasetDigest()이다.

DEBUG DIGEST-VALUE

Help: Output a hex signature of the values of all the specified keys.
지정한 키의 값에 대한 digest값을 계산한다.  

127.0.0.1:5010> debug digest-value key1 key2
1) 8b06d62b6b33e452ce6d722400e8de8505ababb8
2) 638a70cdd3e1ed9b5888f8bf4e86166ce3e7bc4d

DEBUG SLEEP

Help: Stop the server for . Decimals allowed.
지정한 시간(초) 동안 서버의 모든 기능을 멈춘다.   소수점 이하도 입력할 수 있다.
응답 시간(latency) 테스트 등에 사용된다.

  • 실행 예
  • 127.0.0.1:6379> debug sleep 1
    OK
    (1.00s)
    127.0.0.1:6379> debug sleep 5.5
    OK
    (5.50s)
    127.0.0.1:6379> debug sleep 70
    OK
    (70.00s)
  • 소스코드: debugCommand()   debug.c

DEBUG SET-ACTIVE-EXPIRE

Help: Setting it to 0 disables expiring keys in background when they are not accessed (otherwise the Redis behavior).   Setting it to 1 reenables back the default.

레디스 서버는 디폴트로 1초에 10번(100ms마다) databasesCron()을 실행해서 만료된(expire) 키를 삭제한다.   이 기능을 활성화(1)/비활성화(0) 할 수 있다.   이 기능은 레디스 서버에 당연히 제공되어야 하는 것이므로 redis.conf에 설정할 수 없고, debug 명령으로만 가능하다.
만료된 키를 삭제하는 것은 get 같은 명령을 실행할 때도 expire time을 확인해서 지났으면 삭제한다. 명령 실행 시 만료 키 삭제 기능은 100ms마다 만료된 키를 삭제하지만, 그 사이에 access 했을 때를 대비해서이다.   그리고 이 100ms는 redis.conf에 hz 파라미터로 계산(1000/hz) 하는데, hz를 1로 하면 1초에 한 번씩 수행하게 된다.   그러므로 access 시에 만료된 키를 삭제하는 기능은 필요하다.

  • 실행 예
  • 127.0.0.1:6379> debug set-active-expire 0
    OK
    127.0.0.1:6379> debug set-active-expire 1
    OK
  • 소스코드: debugCommand()   debug.c
  • 소스코드: databasesCron()   server.c

DEBUG LUA-ALWAYS-REPLICATE-COMMANDS

Help: Setting it to 1 makes Lua replication defaulting to replicating single commands, without the script having to enable effects replication.
버전 3.2.0에서 추가되었다.

  • 실행 예
  • 127.0.0.1:6379> debug lua-always-replicate-commands 0
    OK
    127.0.0.1:6379> debug lua-always-replicate-commands 1
    OK
  • 소스코드: debugCommand()   debug.c

DEBUG ERROR

Help: Return a Redis protocol error with as message.   Useful for clients unit tests to simulate Redis errors.   버전 2.8.8에서 추가되었다.

  • 실행 예
  • 127.0.0.1:6379> debug error "This is a error Message."
    (error) This is a error Message.
  • 소스코드: debugCommand()   debug.c

DEBUG LOG

Help: write message to the server log.
버전 5.0에서 추가되었다.

  • 실행 예
  • 127.0.0.1:5010> debug log "Log Message"
    OK
    22837:M 31 Dec 2018 23:17:00.631 # DEBUG LOG: Log Messag

DEBUG STRUCTSIZE

Return the size of different Redis core C structures.
버전 3.2.0에서 추가되었다.
레디스 핵심 C 구조체의 크기(바이트)를 보여준다.

  • 실행 예
  • 127.0.0.1:6379> debug structsize
    "bits:64 robj:16 dictentry:24 sdshdr5:1 sdshdr8:3 sdshdr16:5 sdshdr32:9 sdshdr64:17 "
  • bits:64는 info server 명령의 arch_bits:64 와 같은 데이터이다.
  • robj:16은 redisObject 구조체이다. 아래는 server.h에 있는 정의이다.
  • dictentry:24는 dictEntry 구조체이다. 아래는 dict.h에 있는 정의이다.
  • sdshdr5:1   sds header 구조는 버전 3.2.0에서 많이 변경되었다.   sds.h에 정의되어 있다.
  • ** 구조체의 마지막 멤버인 char buf[]는 크기를 지정하지 않은 멤버로 구조체의 마지막 멤버일 때만 허용된다.
    이것을 사용하면 포인터를 사용하지 않고 가변 데이터를 저장할 수 있다.
    sizeof 연산자에서 이 배열 크기는 0으로 간주된다.
  • sdshdr8:3
  • sdshdr16:5
  • sdshdr32:9
  • sdshdr64:17
  • 버전 3.2.0 이전: sdshdr:8

DEBUG HTSTATS

Help: Return hash table statistics of the specified Redis database.
버전 3.2.0에서 추가되었다.
DB 키 통계정보(Hash table)를 보여준다.   Hash table에 대한 설명은 여기를 보세요.

사용법: debug htstats dbid

  • 실행 예
  • 통계정보는 크게 세 부분으로 구성된다.
    • [Dictionary HT] Hash table 0 stats (main hash table): 메인 해시 테이블 정보
    • Hash table 1 stats (rehashing target): rehashing 중일때만 나온다.
    • [Expires HT] Hash table 0 stats (main hash table): Expire 키가 있을 때만 나온다.
  • 항목 설명
    • table size: 262144 : Hash table 크기, 예는 2^18이다.
    • number of elements: 105876 : 키 개수이다.
    • max chain length: 7 : 해시 값이 충돌해서 최대로 연결된 개수이다.   아래 Chain length distribution의 마지막 숫자와 같다.
    • avg chain length (counted): 1.58 : 평균 체인 길이다.
    • Chain length distribution:
      0: 195094 (74.42%): 사용되지 않는 slot이다.   table size 262144 중 74.42%인 195094개가 미사용중이다.
      1: 39129 (14.93%) 엔트리가 하나만 달려있는 slot 개수이다.
      7: 10 (0.00%) 엔트리가 7개 달려있는 slot 개수이다.
  • 소스코드 #1: debugCommand()   debug.c
  • 소스코드 #2: dictGetStats()   dict.c
  • 소스코드 #3: _dictGetStatsHt()   dict.c

DEBUG HTSTATS-KEY

Help: Like htstats but for the hash table stored as key's value..
키가 hash table에 저장되어 있을 때 hash table 정보를 조회합니다.
키의 내부 data type은 object encoding 명령으로 확인할 수 있습니다.
사용법: debug htstats-key key

  • 실행 예

DEBUG JEMALLOC INFO

Help: Show internal jemalloc statistics.
버전 3.2.0에서 추가되었다. 4.0에서 debug 명령에서는 제거되었고, memory 명령이 새로 생겼다. 4.0에서는 memory malloc-stats 이다.
Jemallc()는 레디스에서 메인으로 사용하고 있는 메모리 할당 알고리즘으로, 미리 정해놓은 단위로 할당함으로써 메모리 할당 속도를 높이고, 메모리 단편화(fragmantation)를 줄일 수 있는 이점이 있다.
Jason Evans가 개발해서 malloc 앞에 JE가 붙었다.   레디스 버전 3.2.0에서는 jemalloc 4.0.3이 사용된다.
Jason Evans가 쓴 jemalloc에 대한 글을 보려면 여기를 클릭하세요
실행 예

  • small: 16kb 미만
  • large: 16kb ~ 2mb 미만
  • huge: 2mb 이상
  • allocated: 할당된 메모리 바이트 = (nmalloc - ndalloc) * size
    예에서는 total 200mb가 할당되었다.
  • nmalloc: 할당한 횟수
  • ndalloc: 해제한 횟수
  • Quantum: time slice라고도 한다.
  • 두산백과 시분할시스템(time sharing system) 설명

DEBUG JEMALLOC PURGE

Force jemalloc to release unused memory.
버전 3.2.0에서 추가되었다. 4.0에서 debug 명령에서는 제거되었고, memory 명령이 새로 생겼다. 4.0에서는 memory purge 이다.
jemalloc가 사용하지 않는 메모리를 해제한다.

  • 소스코드: info, purge 같이 표시 debugCommand()   debug.c

DEBUG ZIPLIST key

Show low level info about the ziplist encoding.
Data Type이 ziplist 일 때 내부 구조를 자세히 보여준다.
Ziplist 내부구조 그림과 같이 보면 이해하는데 도움이 됩니다.

DEBUG

3.03.24.05.0
assertassertassertassert
digestdigestdigestdigest
errorerrorerrorerror
log
loadaofloadaofloadaofloadaof
objectobjectobjectobject
oomoomoomoom
populatepopulatepopulatepopulate
reloadreloadreloadreload
sdslensdslensdslensdslen
segfaultsegfaultsegfaultsegfault
set-active-expireset-active-expireset-active-expireset-active-expire
sleepsleepsleepsleep
crash-and-recovercrash-and-recovercrash-and-recover
htstatshtstatshtstats
htstats-key
jemalloc info
jemalloc purge
lua-always-replicate-commandslua-always-replicate-commandslua-always-replicate-commands
restartrestartrestart
structsizestructsizestructsize
panicpanic
ziplistziplist
change-repl-id

명령문

DEBUG subcommand arg1 arg2 ... argN

  • 이 명령은 version 1.0.0 부터 사용할 수 있다.
  • 논리적 처리 소요시간은 subcommand 마다 다르다.

Clients for C Hiredis

<< INFO DEBUG SLOWLOG >>

조회수 :

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