Redis Replication Introduction

Redis Server Course Redis Technical Support Redis Enterprise Server

Replication

복제란

  • 복제란 레디스의 데이터를 거의 실시간으로 다른 레디스 노드에 복사하는 작업입니다.   따라서 서비스를 제공하던 첫 번째 레디스 노드가 다운되더라도, 데이터를 받은 두 번째 레디스 노드가 서비스를 계속 할 수 있습니다.   레디스에서는 첫 번째 노드를 마스터라고 하고 두 번째 노드를 복제(replica)라고 합니다.
  • 복제기능이 없다면 어떤 일이 생길까요?   만약 레디스 인스턴스가 사람의 실수 또는 소프트웨어 적인 문제로 다운었을때, 관리자가 이를 인지하고 레디스를 문제없이 다시 시작했다면 서비스 중단 시간은 길지 않을 것입니다.   하지만 이때도 AOF 기능을 사용하고 있었고 데이터가 많이 쌓여 있다면, 인스턴스가 시작하는데 몇 분이 걸릴 수도 있습니다.   다운의 원인이 하드웨어 적인 문제였다면 서비스를 다시 시작하는 상당한 시간이 소요될 수 있고, 데이터를 복구하지 못할 수도 있습니다.
  • 이런 문제를 해결하고자 레디스는 복제기능을 제공합니다.   실 운영환경이라면 마스터-복제로 구성할 것을 권장합니다.   그리고 마스터와 복제는 물리적으로 다른 머신에 두어야 합니다.

복제 구성 설정

  • 매우 단순합니다. 복제서버의 redis.conf 파일을 보면 "# replicaof <masterip> <masterport>" 이 있습니다.
    앞에 주석을 지우고, 마스터 노드의 IP와 PORT를 넣어주세요.   예를 들어 마스터 노드이 IP가 127.0.0.1 이고 port 가 6382면, 복제서버의 redis.conf 파일에 replicaof 127.0.0.1 6382 라고 설정하면 됩니다.
  • 마스터를 시작한 후 복제서버를 시작하세요.   마스터에 데이터를 입력하고 복제서버에서 조회하면 나옵니다.   복제가 비동기 방식이긴 하지만 거의 실시간으로 복제서버에 전달됩니다.
  • 레디스 2.6 부터 기본적으로 복제서버는 쓰기는 할 수 없고, 조회만 가능합니다. 이것은 replica-read-only 파라미터로 변경 가능합니다.

서버 정보

  • 마스터 서버 정보
  • 127.0.0.1:6382> info replication
    role:master   Role -> Master  
    connected_slaves:2   복제서버가 2개 연결되어 있다. 여기서는 마스터를 직접 바라보는 복제서버가 2개 있을 경우 나오는 정보이다. 아래에 있는 2차 복제서버까지 마스터가 인식해서 나오는 것은 아니다.  
    slave0:ip=127.0.0.1,port=6383,state=online,offset=1508,lag=0   복제서버에 대한 정보를 볼 수 있다. 
    slave1:ip=127.0.0.1,port=6385,state=online,offset=1508,lag=1
  • 1차 복제서버 정보 : 마스터 정보와 2차 복제 정보까지 나온다.
  • 127.0.0.1:6383> info replication
    role:slave   Role -> Slave  
    master_host:127.0.0.1   마스터에 대한 정보
    master_port:6382
    master_link_status:up
    master_last_io_seconds_ago:4
    master_sync_in_progress:0
    slave_repl_offset:1690
    slave_priority:100
    slave_read_only:1
    connected_slaves:1   이 복제서버에 연결되어 있는 2차 복제서버 정보
    slave0:ip=127.0.0.1,port=6384,state=online,offset=1662,lag=1
    master_repl_offset:1662
  • 2차 복제서버 정보
  • 127.0.0.1:6384> info replication
    role:slave  Role -> Slave  
    master_host:127.0.0.1   마스터(1차 복제서버)에 대한 정보
    master_port:6383
    master_link_status:up
    master_last_io_seconds_ago:6
    master_sync_in_progress:0
    slave_repl_offset:1718
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_repl_offset:0

Replication 복제

  • 레디스는 비동기(asynchronous) 복제를 합니다.
  • 마스터는 복제서버를 여러 개 둘 수 있습니다.
  • 복제서버는 또 복제서버를 둘 수 있습니다.
    마스터 -> 복제1 -> 복제2 이런 구성이 됩니다.
  • 마스터에 많은 데이터가 있는 상태에서 복제서버를 시작하면, 대량의 마스터 데이터가 복제서버로 보내질 것입니다.   이 때에도 마스터는 멈추지 않고 정상적으로 요청을 처리합니다.   왜냐하면 데이터를 복제서버로 보내는(RDB 파일을 생성하는) 작업은 자식 프로세스가 처리합니다.
  • 복제서버에게 조회 요청을 처리하도록 하는 것도 부하를 분산하는 좋은 방법입니다.   특히 SORT 명령같은 것들은 복제서버에서 수행하는 것이 좋을 것입니다.
  • 마스터의 부하를 줄이기 위해서, AOF 쓰기나 RDB 파일 생성을 복제서버에서 수행하는 것도 좋은 방법입니다.   하지만 이런 설정을 했을 경우에는 마스터 자동 시작 하도록 하면 데이터가 유실 될 수 있습니다.   다음 섹션을 참고하세요.

마스터 자동 시작과 Persistence 기능 사용

  • 서버가 리부트할 때 레디스를 자동 재시작하도록 설정했다면, 마스터에서는 persistence(AOF, RDB)를 사용할 것을 권장합니다.   Persistence 기능을 사용하지 않는다면 자동 재시작 기능을 이용하지 않는 것이 좋습니다.
  • Persistence 기능을 사용하지 않는 상태에서 자동 재시작하도록 설정했다면, 마스터와 복제서버 모두 데이터를 잃어버릴 수 있습니다.   아래와 같은 시나리오가 발생할 수 있습니다
    1. 노드 A를 마스터(persistence 기능 끔)로 하고 노드 B를 복제서버로 설정.
    2. 노드 A가 예외 상항으로 다운되었다 다시 시작했을때, 레디스 마스터 서버가 자동 재시작 했다면, persistence 기능을 꺼 놓았으므로 AOF나 RDB 파일이 없읍니다. 그럼 마스터는 데이터가 없는 빈 상태로 뜰것입니다.
    3. 노드 B는 마스터의 아무것도 없는 데이터를 복제하게 되어, 결과적으로 복제서버 데이터도 사라지게 됩니다.   복제서버에 AOF 파일이 있어도, 초기 복제 후에 AOF Rewrite 기능이 수행되어 복제서버의 AOF 파일에도 데이터는 사라지게 됩니다.
  • 테이터의 보호는 언제나 중요합니다. 자동 재시작 기능을 사용한다면 Persistence를 사용하십시요.

복제 방식 - 전체 동기화(full synchronization)

  • 복제 순서
    1. 마스터는 자식 프로세스를 시작해 백그라운드로 RDB파일에 데이터를 저장합니다.
    2. 데이터를 저장하는 동안 마스터에 새로 들어온 명령들은 처리 후 복제버퍼에 저장됩니다.
    3. RDB 파일 저장이 완료되면, 마스터는 파일을 복제서버에게 전송합니다.
    4. 복제서버는 파일을 받아 디스크에 저장하고, 메모리로 로드합니다.
    5. 마스터는 복제버퍼에 저장된 명령을 복제서버에게 전송합니다.
  • 레디스 2.8.18 부터는 RDB 파일을 디스크에 만들지 않고 복제하는 기능을 제공합니다.
    자세한 내용은 아래 디스크를 사용하지 않는 동기화에 있습니다.
  • 마스터 다운되면 복제서버는 1초에 한 번씩 마스터에 Connect 요청을 보냅니다.
    마스터가 살아나면 복제서버에 복제 순서에 따라 Sync를 합니다. 복제서버가 여러 개 일때도 RDB 파일은 하나만 생성합니다.

복제시 서버에서 나오는 정보

RDB를 디스크에 저장해서 동기화하는 경우(Disk-based): repl-diskless-sync no
  • 마스터
  • 59394:M 08:30:53.369 * Slave 127.0.0.1:6383 asks for synchronization
    59394:M 08:30:53.369 * Full resync requested by slave 127.0.0.1:6383   복제서버로 부터 전체 동기화 요청을 받음  
    59394:M 08:30:53.369 * Starting BGSAVE for SYNC with target: disk
    59394:M 08:30:53.370 * Background saving started by pid 59497   자식 프로세스 생성해서 RDB 파일 쓰기를 시작  
    59497:C 08:30:54.295 * DB saved on disk   RDB 파일 쓰기 완료  
    59497:C 08:30:54.295 * RDB: 42 MB of memory used by copy-on-write
    59394:M 08:30:54.325 * Background saving terminated with success
    59394:M 08:30:54.345 * Synchronization with slave 127.0.0.1:6383 succeeded   복제서버에게 RDB 파일 전송 완료  
  • 복제서버
  • 59494:S 08:30:53.369 * Connecting to MASTER 127.0.0.1:6382
    59494:S 08:30:53.369 * MASTER <-> SLAVE sync started   마스터에 동기화 요청  
    59494:S 08:30:53.369 * Non blocking connect for SYNC fired the event.
    59494:S 08:30:53.369 * Master replied to PING, replication can continue...
    59494:S 08:30:53.369 * Partial resynchronization not possible (no cached master)
    59494:S 08:30:53.369 * Full resync from master: 5ef2944bef28a57b39fb867550b2d02e04f14755:1
    59494:S 08:30:54.325 * MASTER <-> SLAVE sync: receiving 33911898 bytes from master   마스터로 부터 RDB 파일을 받기 시작  
    59494:S 08:30:54.537 * MASTER <-> SLAVE sync: Flushing old data   메모리에 있는 데이터를 삭제  
    59494:S 08:30:54.537 * MASTER <-> SLAVE sync: Loading DB in memory   RDB 파일로 부터 데이터 로드  
    59494:S 08:30:55.552 * MASTER <-> SLAVE sync: Finished with success
    이후 Appendonly 가 yes 이면 appendonly file Rewrite가 시작된다.

디스크를 사용하지 않고 소켓을 통해서 동기화하는 경우(Diskless): repl-diskless-sync yes
  • 마스터
  • 12637:M 22:43:01.713 * Slave 127.0.0.1:6383 asks for synchronization
    12637:M 22:43:01.713 * Full resync requested by slave 127.0.0.1:6383
    12637:M 22:43:01.713 * Delay next BGSAVE for SYNC   repl-diskless-sync-delay 만큼 기다림  
    12637:M 22:43:07.273 * Starting BGSAVE for SYNC with target: slaves sockets   소켓 통신  
    12637:M 22:43:07.274 * Background RDB transfer started by pid 12647
    12647:C 22:43:07.406 * RDB: 12 MB of memory used by copy-on-write
    12637:M 22:43:07.474 * Background RDB transfer terminated with success
    12637:M 22:43:07.474 # Slave 127.0.0.1:6383 correctly received the streamed RDB file.
    12637:M 22:43:07.474 * Streamed RDB transfer with slave 127.0.0.1:6383 succeeded (socket). Waiting for REPLCONF ACK from slave to enable streaming
    12637:M 22:43:08.057 * Synchronization with slave 127.0.0.1:6383 succeeded
  • 복제서버
  • 12642:S 22:43:07.276 * MASTER <-> SLAVE sync: receiving streamed RDB from master
      이 부분이 disk 방식과 다름. 요청 후 repl-diskless-sync-delay 만큼 기다렸다 이 메시지가 나옴
      Diskless는 마스터에만 적용됩니다. 복제서버는 데이터를 RDB 파일에 저장합니다.  

    12642:S 22:43:07.463 * MASTER <-> SLAVE sync: Flushing old data
    12642:S 22:43:07.559 * MASTER <-> SLAVE sync: Loading DB in memory
    12642:S 22:43:07.755 * MASTER <-> SLAVE sync: Finished with success

부분 동기화(Partial resynchronization)

  • 마스터와 복제서버는 각 서버의 run id 와 replication offset을 가지고 있습니다.   마스터와 복제서버간 네트워크가 끊어지면 마스터는 복제서버에 전달할 데이터를 backlog-buffer에 저장합니다. 다시 연결되었을 때 backlog-buffer가 넘치지 않았으면 run id와 offset을 비교해서 그 이후 부터 동기화를 합니다. 이것을 부분 동기화라고 합니다.   Backlog-buffer 크기는 repl-backlog-size 파라미터로 설정합니다.   부분 동기화 기능은 레디스 버전 2.8 부터 제공됩니다.
  • 네크워트 단절 시간이 길어져 마스터의 backlog-buffer가 넘치면 다시 연결되었을 때 전체 동기화(full synchronization)를 합니다.   마스터나 복제서버 중 한쪽이 재시작했을 경우에도 전체 동기화를 합니다.

마스터: 디스크를 사용하지 않는 동기화 (Diskless Replication)

  • 레디스 버전 2.8.18 부터 디스크를 사용하지 않는 동기화 기능을 제공합니다.   이 기능은 레디스를 케시 용도로 사용할 경우 또는 마스터가 설치된 머신의 디스크 성능이 좋지 않을 경우 이용할 수 있습니다.   디스크를 사용하지 않는 것은 마스터만 적용됩니다. 복제서버는 받은 데이터를 RDB 파일에 저장합니다.
  • 마스터의 자식 프로세스가 RDB 데이터를 소켓을 통해서 복제서버에게 직접 쓰는 방식입니다.
  • redis.conf(Master) 파라미터: repl-diskless-sync no or yes, default no
    디폴트는 no 입니다. Yes로 하면 디스크를 사용하지 않고 동기화가 됩니다.
  • 여러 복제서버에서 요청이 들어올 경우, 기본적으로 첫 번째 복제서버의 소켓에 데이터를 전송하고, 완료되면, 다음 복제을 처리합니다. 몇 개 복제서버를 한 번에 처리할 수 있도록 요청을 기다리는 옵션이 있습니다.
  • redis.conf(Master) 파라미터: repl-diskless-sync-delay 5
    첫 번째 요청이 온 후 5초 동안 다른 복제서버의 요청을 기다렸다가, 요청이 오면 같이 처리합니다.
    즉, 5초 안에 3개 복제서버에서 동기와 요청이 왔다면 이는 병렬로 처리할 수 있습니다.
    즉시 처리하도록 하려면 0으로 설정하십시오.
  • 이 기능을 만들게 된 동기와 디자인 노트에 대한 이야기는 Antirez weblog: Diskless replication: a few design notes. 에서 보실 수 있습니다.

복제(Replica): 디스크를 사용하지 않는 동기화 (repl-diskless-load)

  • 복제서버에서 디스크를 사용하지 않는 동기화입니다. 즉, 복제서버에 rdb 파일을 생성하지 않습니다.
    이 기능은 버전 6.0부터 사용할 수 있습니다.
  • redis.conf(Replica) 파라미터: repl-diskless-load   disabled/on-empty-db/swapdb, default disabled
    세 가지
  • disabled: diskless를 사용하지 않습니다.
  • on-empty-db: 복제서버에 데이터(키)가 없을 경우에 적용, 데이터가 있으면 rdb 파일을 생성해서 복제합니다.
  • swapdb: 복제서버에 데이터(키) 여부와 상관없이 diskless로 동작합니다. 이 경우 만약의 사태에 대비해서 기존 데이터를 메모리(RAM)에 보존합니다. 복제가 성공하면 RAM에 보존한 데이터는 지웁니다. 복제가 실패하면 RAM에 보존한 데이터로 복구합니다. 이 경우 기존 데이터 + 새 데이터 만큼 메모리(RAM)이 필요하므로 충분한 메모리가 있어야 합니다.

복제서버는 읽기 전용

  • 레디스 버전 2.6 부터 복제서버는 디폴트로 읽기 전용입니다.
  • redis.conf 파라미터: replica-read-only yes or no, default yes
  • 복제서버에 데이터를 입력했어도 마스터와 Resync 되면 복제서버에 입력된 데이터는 사라집니다.

운영 중 복제서버를 마스터로 변경하기

  • 마스터가 다운되었을때 복제서버를 마스터로 변경하는 명령은 다음과 같다.
  • 127.0.0.1:6383> replicaof no one
  • 복제서버가 마스터로 변경되었을 때 복제서버 로그
  • 57070:M 10:33:31.774 # Connection with master lost.
    57070:M 10:33:31.774 * Caching the disconnected master state.
    57070:M 10:33:31.774 * Discarding previously cached master state.
    57070:M 10:33:31.775 * MASTER MODE enabled (user request)

마스터 서버를 복구 했을 경우 원 위치 방법 1: SLAVEOF 명령

  1. 새로운 레디스 서버를 마스터로 실행한다. 새 서버를 1번, 현 서버를 2번이라고 하자.
    간단히 표기하기 위해 ip는 127.0.0.1로 하고, 1번 서버 포트를 6382, 2번 서버 포트를 6383 으로 하자.
    이전에 반드시 확인해야 할 사항은 1번 서버를 마스터로 바라보는 복제서버가 없어야 한다. 만약 복제서버가 있다면 데이터가 없는 마스터를 복제서버가 동기화할 것이므로 복제서버에 있던 데이터도 사라지게 된다.
  2. 클라이언트 접속 차단
  3. 새 서버(1번)는 현 서버(2번)의 데이터를 받는다. 데이터를 받기 위해 일시적으로 1번을 복제서버로 만든다.
    replicaof 127.0.0.1 6383
  4. 동기화 완료 후 1번 서버에서 replicaof no one 명령으로 다시 마스터가 된다.
  5. 2번 서버는 replicaof 127.0.0.1 6382 명령으로 복제서버가 된다. 그러면 2번 서버는 다시 1번 서버의 데이터를 동기화한다.
  6. 클라이언트는 새로운 1번 서버로 접속한다.
  7. 2번 서버에서는 반드시 변경 내용을 redis.conf에 기록하기 위해 config rewrite 명령을 실행한다.
  8. 이 방법이 다소 복잡할 수 있지만 RDB 파일을 수동으로 복사하지 않고 변경하는 방법이다.

마스터 서버를 복구 했을 경우 원 위치 방법 2: RDB 파일 복사

  1. 클라이언트 접속 차단
  2. 2번 서버에서 bgsave 또는 save 명령으로 RDB 파일을 생성한다.
  3. RDB파일을 1번 서버의 redis.conf 에 설정한 working directory로 복사한다.
  4. 1번 서버를 마스터로 실행한다.
  5. 2번 서버를 복제서버으로 설정을 변경하고 실행한다.
  6. 클라이언트는 새로운 1번 서버로 접속한다.

<< RDB Functions Redis 4.0 Partial Resync >>

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