Skip to main content

Command Palette

Search for a command to run...

Redis서버가 장애가 나도 사용자가 아무것도 모르도록 만들어보자

Redis 장애 대응 전략 설정으로 사용자 경험을 더 안정적으로 만들어보자

Updated
6 min read

Redis란?

Redis(Remote Dictionary Server)는 인메모리 데이터 구조 저장소로, 다양한 데이터 구조(문자열, 해시, 리스트, 셋, 정렬된 셋 등)를 지원하는 NoSQL 데이터베이스입니다. 주요 특징으로는:

  • 인메모리 작동 방식으로 매우 빠른 읽기/쓰기 성능 제공

  • 데이터 영속성 지원 (RDB 스냅샷, AOF 로그)

  • 단일 스레드 아키텍처로 원자적 작업 보장

  • 복제, 클러스터, 센티널 등의 고가용성 기능 제공

  • 키-값 저장소지만, 다양한 데이터 타입을 지원해 활용도가 높음

Redis는 캐싱, 세션 저장소, 메시지 브로커, 실시간 분석 등 다양한 용도로 사용됩니다.

Redis가 장애가 났을 때 장애 복구를 위해서 할 수 있는 대응 방법

Redis 장애 상황에서 복구를 위한 여러 방법이 있습니다:

  1. 복제(Replication): 마스터-슬레이브 구조로 데이터를 여러 서버에 복제하여 마스터 서버 장애 시 슬레이브가 데이터 제공

  2. Redis Sentinel: 자동 장애 감지 및 페일오버를 통해 마스터 장애 시 슬레이브를 새 마스터로 승격

  3. Redis Cluster: 여러 노드에 데이터를 분산 저장하고 자동 장애 복구 제공

  4. 데이터 지속성 설정: RDB(Redis Database Backup) 스냅샷이나 AOF(Append Only File) 로그를 통해 데이터 복구 가능

  5. 백업 및 복원: 정기적인 백업을 통해 장애 발생 시 데이터 복원

이 중에서 Redis Sentinel은 고가용성을 위한 가장 효과적인 솔루션 중 하나입니다.

센티널이란 무엇인가?

Redis Sentinel은 Redis의 고가용성 솔루션으로, 다음과 같은 기능을 제공합니다:

  1. 모니터링: 마스터와 슬레이브 노드가 정상적으로 작동하는지 지속적으로 감시합니다.

  2. 자동 장애 감지: 마스터 노드에 문제가 발생하면 이를 감지합니다. 여러 센티널이 쿼럼을 통해 마스터 장애를 합의합니다.

  3. 자동 페일오버: 마스터 노드에 장애가 발생하면 적합한 슬레이브를 선택해 새로운 마스터로 승격시키고, 다른 슬레이브들이 새 마스터를 바라보도록 재구성합니다.

  4. 클라이언트 통지: 클라이언트에게 현재 마스터의 주소를 알려주어 연결 관리를 도와줍니다.

  5. 구성 제공자: 클라이언트가 현재 Redis 토폴로지를 조회할 수 있는 서비스 역할을 합니다.

센티널은 일반적으로 최소 3개 이상의 인스턴스로 구성하여 과반수 투표를 통한 안정적인 장애 감지를 보장합니다.

센티널과 클러스터는 무엇이 다른가?

클러스터는 여러 노드에 데이터를 분산해서 수평적인 확장을 할 수 있도록 하는 것이 목적입니다.

클러스터 내장으로 자체 자동 장애 감지가 있는 경우가 있습니다.

그래서 클러스터의 경우 각 마스터 노드가 대체로 전속 슬레이브 노드를 가지고 있습니다.

센티널의 경우 복제 환경을 기본전제로 두고 장애 상황에서 Master-Slave 간의 전환을 통해서 장애 대응을 하는 전략을 의미합니다.

따라서 기본적으로 Master-Slave 가 최소 1개 이상 존재해야하며 일반적으로 센티널 노드까지 일반적으로 최소 3개 이상 구성되어 있어야 합니다.

센티널 설정하고 직접 장애 내보기

센티널을 설정하고 장애 테스트를 하는 과정은 다음과 같습니다:

  1. Docker Compose 파일 구성:

    • Redis 마스터 노드 1개

    • Redis 슬레이브 노드 2개

    • Sentinel 노드 2개

    • 각각 고정 IP 주소 할당

  2. 센티널 설정 파일 구성:

     port 26379
     dir "/tmp"
     sentinel monitor mymaster 172.18.0.2 6379 2
     sentinel down-after-milliseconds mymaster 5000
     sentinel failover-timeout mymaster 60000
     sentinel auth-pass mymaster redispassword
     sentinel known-replica mymaster 172.18.0.5 6379
     sentinel known-replica mymaster 172.18.0.6 6379
     requirepass "redispassword"
    
  3. 장애 테스트 시나리오:

    • 마스터 노드(172.18.0.2)를 강제 종료

    • 센티널이 장애를 감지하고 슬레이브 중 하나를 마스터로 승격

    • 새 마스터는 포트 번호 변경 없이 역할만 변경됨

    • 다른 슬레이브는 새 마스터를 바라보도록 재구성

    • 애플리케이션은 센티널을 통해 새 마스터 정보를 얻어 접속 계속

  4. 실제 테스트 확인:

    • docker-compose stop redis-master 명령으로 마스터 노드 중단

    • redis-cli -h 172.18.0.3 -p 26379 -a redispassword sentinel masters 명령으로 새 마스터 확인

    • 센티널 로그를 통해 페일오버 과정 확인

그림을 통해서 보는 장애 시나리오

센터널 실제 로그 분석

센티널 노드의 전체 로그

1:X 04 May 2025 07:28:15.355 # +sdown master mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:15.447 # +odown master mymaster 172.18.0.2 6379 #quorum 2/2
1:X 04 May 2025 07:28:15.447 # +new-epoch 1
1:X 04 May 2025 07:28:15.447 # +try-failover master mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:15.455 # Could not rename tmp config file (Device or resource busy)
1:X 04 May 2025 07:28:15.455 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 04 May 2025 07:28:15.455 # +vote-for-leader abadec7630202c8c8c151e5ac8e9945f13c6d066 1
1:X 04 May 2025 07:28:15.462 * 6c10b56b55c5190b3b87376b575263fa1a871725 voted for abadec7630202c8c8c151e5ac8e9945f13c6d066 1
1:X 04 May 2025 07:28:15.508 # +elected-leader master mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:15.508 # +failover-state-select-slave master mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:15.565 # +selected-slave slave 172.18.0.5:6379 172.18.0.5 6379 @ mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:15.565 * +failover-state-send-slaveof-noone slave 172.18.0.5:6379 172.18.0.5 6379 @ mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:15.656 * +failover-state-wait-promotion slave 172.18.0.5:6379 172.18.0.5 6379 @ mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:16.461 # Could not rename tmp config file (Device or resource busy)
1:X 04 May 2025 07:28:16.462 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 04 May 2025 07:28:16.462 # +promoted-slave slave 172.18.0.5:6379 172.18.0.5 6379 @ mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:16.462 # +failover-state-reconf-slaves master mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:16.559 * +slave-reconf-sent slave 172.18.0.6:6379 172.18.0.6 6379 @ mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:17.544 * +slave-reconf-inprog slave 172.18.0.6:6379 172.18.0.6 6379 @ mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:17.544 * +slave-reconf-done slave 172.18.0.6:6379 172.18.0.6 6379 @ mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:17.611 # +failover-end master mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:17.611 # +switch-master mymaster 172.18.0.2 6379 172.18.0.5 6379
1:X 04 May 2025 07:28:17.611 * +slave slave 172.18.0.6:6379 172.18.0.6 6379 @ mymaster 172.18.0.5 6379
1:X 04 May 2025 07:28:17.611 * +slave slave 172.18.0.2:6379 172.18.0.2 6379 @ mymaster 172.18.0.5 6379
1:X 04 May 2025 07:28:17.615 # Could not rename tmp config file (Device or resource busy)
1:X 04 May 2025 07:28:17.615 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 04 May 2025 07:28:22.676 # +sdown slave 172.18.0.2:6379 172.18.0.2 6379 @ mymaster 172.18.0.5 6379
1:X 04 May 2025 07:29:31.905 # -sdown slave 172.18.0.2:6379 172.18.0.2 6379 @ mymaster 172.18.0.5 6379
1:X 04 May 2025 07:29:41.827 * +convert-to-slave slave 172.18.0.2:6379 172.18.0.2 6379 @ mymaster 172.18.0.5 6379
  1. 마스터 노드가 모종의 이유(그것은 나)로 죽었고 fail-over 전략을 시도하는 것을 확인할 수 있습니다
1:X 04 May 2025 07:28:15.355 # +sdown master mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:15.447 # +odown master mymaster 172.18.0.2 6379 #quorum 2/2
1:X 04 May 2025 07:28:15.447 # +new-epoch 1
1:X 04 May 2025 07:28:15.447 # +try-failover master mymaster 172.18.0.2 6379
  1. 슬레이브 노드 중 하나가 센티널에 의해서 마스터 노드로 승격될 대상으로 결정된 것을 볼 수 있습니다
1:X 04 May 2025 07:28:15.508 # +elected-leader master mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:15.508 # +failover-state-select-slave master mymaster 172.18.0.2 6379
1:X 04 May 2025 07:28:15.565 # +selected-slave slave 172.18.0.5:6379 172.18.0.5 6379 @ mymaster 172.18.0.2 6379
  1. 다시 살아난 마스터노드는 이후에 슬레이브 노드로 좌천되는 것도 볼 수 있습니다
1:X 04 May 2025 07:29:41.827 * +convert-to-slave slave 172.18.0.2:6379 172.18.0.2 6379 @ mymaster 172.18.0.5 6379

결론 요약

  • Redis는 메모리 기반의 Key-Value 저장소이다

  • Redis 장애 대응을 위한 준비로 크게 아래의 것들을 할 수 있습니다

    • Cluster Setting

    • Redis Sentinel

    • Snapshot Backup

  • Redis Sentinel은 최소 1개의 Master, Slave 노드가 존재해야하만 사용할 수 있고 Application 단에서도 장애 상황에 변경되는 마스터 노드를 확인하기 위한 대비가 application 단에서 되어 있어야합니다.

  • Redis Sentinel는 특정 마스터 노드가 문제가 발생하였을 때 센티널들끼리 투표를 통해서 슬레이브 노드를 마스터 노드로 승격시키고 기존 마스터 노드가 회복되면 슬레이브 노드로 강등시킵니다.

느낀점

Redis Sentinel을 통한 고가용성 구성에서 배운 중요한 점들:

  1. 무중단 서비스의 중요성: Redis와 같은 핵심 인프라 서비스는 장애 시에도 서비스 중단 없이 계속 작동해야 함을 실감했습니다.

  2. 자동화된 장애 복구: 센티널을 통해 사람의 개입 없이 자동으로 마스터 노드 장애를 감지하고 복구하는 메커니즘의 효율성을 경험했습니다.

  3. 애플리케이션 설계 고려사항: 고가용성 인프라를 활용하기 위해서는 애플리케이션도 적절히 설계되어야 함을 알게 되었습니다. 특히 Sentinel 클라이언트 라이브러리를 사용하여 마스터 노드 변경에 대응하는 방법이 중요합니다.

  4. 포트 번호 유지와 역할 변경: 페일오버 시 IP와 포트는 그대로 유지되고 노드의 역할만 변경된다는 것이 매우 직관적이고 효과적인 설계임을 알게 되었습니다.

  5. 분산 시스템 이해 증진: 마스터-슬레이브 아키텍처와 센티널을 통한 고가용성 구성을 통해 분산 시스템에 대한 이해가 깊어졌습니다.

이러한 경험을 통해 프로덕션 환경에서 안정적인 서비스를 제공하기 위한 인프라 구성의 중요성과 그 구현 방법에 대해 실질적인 지식을 얻게 되었습니다.

참고 자료

More from this blog

JVM 객체 할당의 비밀 — TLAB, Bump-the-Pointer, 그리고 할당이 거의 공짜인 이유

Java에서 new를 호출하면 무슨 일이 벌어질까요? "힙에 메모리를 잡는다"는 한 문장 뒤에는 스레드마다 자기만의 분양 구역을 나눠 갖는 정교한 설계가 숨어 있어요. 이 글은 HotSpot JVM이 객체 할당을 어떻게 "거의 공짜"로 만드는지 그 내부를 따라가 보려는 글이에요. JVM 메모리 동작 원리에 관심 있는 분께 권해요. 자바를 쓰다 보면 객체를

May 15, 202614 min read

Java Zero-Copy — FileChannel.transferTo, sendfile, 그리고 Kafka가 디스크를 네트워크로 흘려보내는 방법

"파일을 읽어서 소켓으로 보낸다." 한 줄짜리 요구사항이에요. 그런데 이 한 줄 뒤에서 데이터는 메모리를 네 번이나 복사하고, CPU는 커널과 유저 공간을 네 번이나 들락거려요. Kafka처럼 초당 수십만 건을 흘려보내야 하는 시스템에서 이 비용은 그냥 넘길 수가 없어요. 이 글은 그 복사를 한 겹씩 벗겨내는 zero-copy의 동작 원리를 따라가요. 전통

May 15, 202617 min read

Git merge 내부 동작 — 3-way merge, merge base, 그리고 recursive에서 ort로

git merge를 매일 쓰지만, 그 한 줄이 안에서 무슨 일을 하는지 들여다본 적은 드물어요. 이 글은 merge가 두 갈래의 변경을 어떻게 합치는지, merge base가 왜 필요한지, 그리고 Git이 기본 전략을 recursive에서 ort로 갈아치운 이유를 따라가요. Git을 쓰는 백엔드 개발자를 대상으로 해요. 브랜치 두 개를 합치는 일은 겉보기

May 15, 202612 min read

Java NIO ByteBuffer 내부 구조 — Direct vs Heap, Cleaner, 그리고 off-heap 메모리가 GC를 우회하는 방법

Netty가 빠른 이유, Kafka 클라이언트가 직렬화에 신경 쓰는 이유, MappedByteBuffer로 수 GB짜리 파일을 다루는 이유. 그 한가운데에는 ByteBuffer가 있어요. 이번 글에서는 ByteBuffer의 두 얼굴 — heap과 direct — 가 어떻게 다른지, off-heap 메모리는 어떻게 잡고 어떻게 풀리는지, JVM과 운영체제 사

May 15, 202612 min read

Java Flight Recorder 내부 구조 — Thread-Local Buffer부터 Disk Repository까지

JFR을 켜면 1% 미만 오버헤드로 JVM 내부가 그대로 기록돼요. 어떻게 이렇게 가벼울 수 있는지, 그리고 그 데이터가 어떤 경로를 거쳐 디스크에 쌓이는지 한 번 따라가 봐요. 이 글은 JFR을 "그냥 잘 쓰는 도구"에서 "내부 동작을 아는 도구"로 끌어올리고 싶은 분을 위한 글이에요. 운영 중인 서버에서 갑자기 응답 시간이 튀어요. 메트릭 그래프는 분

May 15, 202614 min read

끄적끄적 테크 블로그

162 posts

물류 회사에 다니고 있는 개발자 블로그입니다. 개발을 너무 좋아해서 정신없이 작업하다가 중간에 끄적거리며 내용들을 몇개 적어봅니다 ㅎㅎ