redis sync 문제 해결하기

팀원이 keys로 레디스를 고장냈다면?

이슈 발생 배경

우리 팀은 3대의 마스터 노드와 3대의 replica 노드로 구성된 Redis Cluster를 사용하고 있었다.

팀원 중 한 명이 'keys' 명령어와 와일드카드(*)를 포함한 명령을 실행했고, 이로 인해 특정 노드가 완전히 블로킹됐다. 처음에는 이 문제가 해결된 것으로 보였다.

하지만 수일이 지난 후, 모니터링 알림을 통해 해당 노드가 더 이상 동기화되지 않고 있다는 걸 발견했다. 이는 초기 블로킹 이슈가 완전히 해결되지 않았음을 의미했다.

  • 3번 노드만 keys 명령어 친 이후로 이상하다!

우리는 replica prefer여서 해당 replica 노드에 요청이 갔었다.

그래서 해당 노드로 요청이 갔을때, 분명히 있어야하는 데이터임에도 불구하고 데이터가 없는 경우가 많았다.

문제 분석

  • redis-cli를 활용

  • cluster info

  • cluster nodes

검사 결과 cluster 자체의 상태는 정상이었다. 이를 통해 문제가 특정 레플리카와 해당 레플리카가 바라보는 마스터 노드에 국한되어 있을 것이라 예상했다.

문제 해결을 위해 해당 레플리카가 바라보는 마스터 노드의 로그를 확인했고, 다음과 같은 내용을 발견했다.

  •       5271:M 23 Dec 2024 12:41:47.968 * Starting BGSAVE for SYNC with target: disk
          15271:M 23 Dec 2024 12:41:48.539 * Background saving started by pid 27098
          15271:M 23 Dec 2024 12:43:25.085 # Client id=260598 addr=[3번기replica노드IP]:43738 fd=42 name= age=155 idle=155 flags=S db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=4867 oll=7781 omem=182471032 events=r cmd=psync scheduled to be closed ASAP for overcoming of output buffer limits.
          15271:M 23 Dec 2024 12:43:25.086 # Connection with replica [3번기replica노드IP]:6379 lost.
          15271:M 23 Dec 2024 12:43:25.130 * Replica [3번기replica노드IP]:6379 asks for synchronization
          15271:M 23 Dec 2024 12:43:25.130 * Full resync requested by replica [3번기replica노드IP]:6379
          15271:M 23 Dec 2024 12:43:25.130 * Can't attach the replica to the current BGSAVE. Waiting for next BGSAVE for SYNC
          27098:C 23 Dec 2024 12:44:20.157 * DB saved on disk
          27098:C 23 Dec 2024 12:44:20.708 * RDB: 1878 MB of memory used by copy-on-write
          15271:M 23 Dec 2024 12:44:21.689 * Background saving terminated with success
          15271:M 23 Dec 2024 12:44:21.689 * Starting BGSAVE for SYNC with target: disk
          15271:M 23 Dec 2024 12:44:22.251 * Background saving started by pid 27818
          15271:M 23 Dec 2024 12:45:56.023 # Client id=260609 addr=[3번기replica노드IP]:43762 fd=42 name= age=151 idle=151 flags=S db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=16239 oll=8202 omem=190005488 events=r cmd=psync scheduled to be closed ASAP for overcoming of output buffer limits.
          15271:M 23 Dec 2024 12:45:56.023 # Connection with replica [3번기replica노드IP]:6379 lost.
          15271:M 23 Dec 2024 12:45:56.379 * Replica [3번기replica노드IP]:6379 asks for synchronization
          15271:M 23 Dec 2024 12:45:56.379 * Full resync requested by replica [3번기replica노드IP]:6379
          15271:M 23 Dec 2024 12:45:56.379 * Can't attach the replica to the current BGSAVE. Waiting for next BGSAVE for SYNC
          27818:C 23 Dec 2024 12:46:54.573 * DB saved on disk
          27818:C 23 Dec 2024 12:46:55.125 * RDB: 2421 MB of memory used by copy-on-write
          15271:M 23 Dec 2024 12:46:56.167 * Background saving terminated with success
          15271:M 23 Dec 2024 12:46:56.167 * Starting BGSAVE for SYNC with target: disk
          15271:M 23 Dec 2024 12:46:56.742 * Background saving started by pid 28265
    
  • 레플리카에서 master sync가 불가능함을 확인함

  • /data01/sw/redis/redis-5.0.5/src/redis-cli --raw -c -p 6379 info replication

  •       # Replication
          role:slave
          master_host:[해당 레플리카가 바라보는 마스터노드 IP]
          master_port:6379
          master_link_status:down
          master_last_io_seconds_ago:-1
          master_sync_in_progress:1
          slave_repl_offset:1
          master_sync_left_bytes:-1
          master_sync_last_io_seconds_ago:1
          master_link_down_since_seconds:283070
          slave_priority:100
          slave_read_only:1
          connected_slaves:0
          master_replid:1168f617f43b1691082d31fdb09650eb1e3c5912
          master_replid2:0000000000000000000000000000000000000000
          master_repl_offset:88389362693519
          second_repl_offset:-1
    

해결 시도

replica 노드 껏켯

마스터 노드의 경우 단순 재시작만으로도 keys 명령어에 의한 버퍼가 초기화될 것으로 예상했다.

하지만 재시작 후에도 문제는 해결되지 않았다. 레플리카의 메모리만 초기화됐을 뿐, 여전히 동기화 문제가 지속됐다.

master노드의 client-output-buffer-limit 설정 변경

Redis는 클라이언트 연결을 normal, slave, pubsub으로 구분해 버퍼를 할당한다.

이 중 slave 버퍼는 마스터에서 레플리카로 데이터를 복제할 때 사용된다. 문제의 원인은 master 노드의 client-output-buffer-limit slave 설정값이 기본값(256MB hard limit, 64MB soft limit)으로 설정되어 있어 너무 작았기 때문이었다.

이로 인해 마스터 노드에서 레플리카로 데이터를 복제하는 과정에서 버퍼 제한에 걸려 연결이 끊어지는 현상이 반복됐다.

연결이 끊어질 때마다 레플리카는 마스터에 재동기화를 요청했고, 이는 마스터 노드에 추가적인 부하를 발생시켰다.

해결을 위해 maxmemory를 고려한 적절한 client-output-buffer-limit slave 값을 설정했다. A

WS ElastiCache의 권장사항을 참고해 maxmemory의 1/10 수준으로 설정했다

  • client-output-buffer-limit slave 10gb 5gb 60

  • 이는 다음을 의미한다

    • hard limit: 1024MB (이 값을 초과하면 즉시 연결 종료)

    • soft limit: 256MB (이 값을 60초 이상 초과하면 연결 종료)

    • soft limit 시간: 60초

설정 변경 후 master-replica 간 동기화가 정상적으로 이루어졌고, 더 이상 connection lost 현상이 발생하지 않았다. 이는 레플리카 노드가 마스터의 데이터를 안정적으로 복제할 수 있을만큼 충분한 버퍼 공간이 확보됐기 때문이다.

교훈

  1. Redis keys 명령어 사용 금지
  • 전체 데이터를 조회하기 때문에 노드 블로킹을 유발할 수 있음

  • 대신 scan 명령어 사용 권장

  • 팀 구성원 전체에게 주기적인 교육과 공유 필요

  1. 모니터링의 중요성
  • replica 노드의 sync 상태와 master-replica 연결 상태 모니터링이 문제 발견의 핵심

  • Redis 운영 시 필수 모니터링 지표:

  • master-replica sync 상태

  • client output buffer 사용량

  • 노드별 메모리 사용량

  • 연결 끊김 이벤트

  1. Redis Cluster 운영 설정 최적화
  • client-output-buffer-limit을 시스템 상황에 맞게 적절히 설정

  • maxmemory와 서비스 사용량을 고려한 설정 필요