- 가용성은 일정 기간 동안 서비스를 정상적으로 사용할 수 있는 시간의 비율이다.
- 레디스는 고가용성을 위해 두 가지 기능이 필요하다.
- 복제: 마스터 노드 데이터를 복제본 노드로 실시간 복사한다.
- 자동 fail-over: 마스터 노드에 장애 발생 시 자동감지해 클라이언트 연결을 복제본 노드로 리다이렉트한다.
1. 레디스에서의 복제 구조
- 운영 중인 서비스에 복제본을 추가하는 이유는 다음과 같다.
- 마스터 장애 시 대신 사용할 여분 확보
- 마스터 노드에 대한 트래픽 분산
- 백업 실행 시 마스터에 대한 부하를 줄여서 서비스 영향 최소화
- MySQL, Postgresql은 멀티 마스터 복제 구조를 제공하기 때문에 모든 노드가 마스터이자 복제본이 될 수 있다.
- 레디스는 마스터가 복제본이 될 수 없다. 2.6 버전 이상부터는 복제본이 기본적으로 read-only이다.
1.1 복제 구조 구성하기
- 복제본이 될 레디스에 다음과 같은 커맨드를 입력하면 된다.
1
REPLICAOF <master-ip> <master-port>
- 마스터가 여러개의 복제본을 갖거나, 복제본이 또 다른 복제본을 가질 수 있다. 하지만 복제 그룹에서는 한 개의 마스터 노드만 존재해야 한다.
1.2 패스워드 설정
- 레디스 6.0 이상부터 패스워드를 이용해 데이터를 복제할 때는 masteroauth 옵션에 패스워드를 입력해야 한다.
- 패스워드 설정은 requirepass 옵션을 사용한다. 복제본은 masterauth라는 옵션에 마스터에 requirepass 값을 설정해서 마스터와 연결한다.
- 복제본 인스턴스 수정 후 재시작 외에 아래 방법으로 설정 파일을 다시 적용할 수 있다.
1
2
3
CONFIG SET masterauth mypassword
CONFIG REWRITE
2. 복제 매커니즘
- 버전 7 이전에는 repl-diskless-sync 옵션이 no이며 다음과 같이 복제 연결되었다.

- 동작 과정
- 복제 연결 시도
- 마스터 노드가 fork()로 자식 프로세스 생성 후 RDB 파일 생성
- 이 과정에서 새로운 노드에서 복제 요청이 들어오면 요청을 큐에 저장한다. RDB 파일 생성 완료 후 한 번에 복제 연결을 시작한다.
- 2번 과정 중 실행된 모든 데이터 변경은 레디스 프로토콜 형태로 마스터의 복제 버퍼에 저장한다.
- 생성 완료된 RDB 파일을 복제본 노드에 복사한다.
- 복제본에 저장된 모든 내용을 삭제한 뒤 RDB파일을 이용해 데이터를 로딩한다.
- 마스터 복제 버퍼에 있던 커맨드를 복제본에서 실행시킨다.
- 위 방식은 디스크를 사용하기 때문에 disk IO에 영향을 받는다.
- 버전 7 이후부터는 repl-diskless-sync 옵션이 yes이다. diskless 복제 방식은 다음과 같다.

- 동작 과정
- 복제 연결 시도
- 소켓 통신을 이용해 마스터와 복제본이 연결해서 RDB 파일을 생성됨과 동시에 복제본 소켓에 전송
- 2 과정 중 변경된 데이터는 레디스 프로토콜 형태로 마스터의 복제 버퍼에 저장
- RDB 파일을 복제본 디스크에 저장한다
- 복제본은 데이터를 모두 삭제하고 RDB 파일 내용을 메모리에 로딩한다.
- 소켓 통신으로 받은 RDB가 정상인지를 확인하지 못하기 때문에 데이터 안정성을 위해 우선 자신의 데이터를 디스크에 저장한다.
- 마스터의 복제 버퍼에 있던 커맨드를 복제본에서 실행시킨다.
- diskless 방법에서는 복제 연결이 끝날떄 까지 새로운 복제 연결을 할 수 없다. 복제 연결 중 새로운 연결이 들어오면 큐에서 대기한다. 이를 방지하기 위해 ‘repl-diskless-sync-delay n’ 옵션을 사용한다. n은 초다. 기본값은 5초로, 새로운 복제 연결이 들어오면 n초간 대기 후 복제 연결을 시작한다. 이 기간 내 들어온 요청에 대해 소캣 통신을 한 번에 연결해 RDB 파일을 전송한다.
2.1 비동기 방식으로 동작하는 복제 연결
- 마스터-복제본 간 데이터 전달은 비동기로 동작한다.
- 클라이언트가 마스터 노드에게 데이터 입력 후, 복제본에 데이터 입력 성공 여부와 상관 없이 클라이언트에게 OK 응답을 보낸다.
- 이 때문에 성능은 높지만 복제본에 데이터가 전달되지 않을 수도 있다. 데이터가 전달되는 속다는 매우 빠르기에 대체로 유실되지는 않는다.
2.2 복제 ID
- 모든 레디스 인스턴스는 복제 사용 여부와 상관 없이 replication id를 가진다. offset 값은 매 수정 커맨드 실행 마다 1씩 증가한다. 두 레디스가 같은 replication id를 갖는다면, 이들은 동일한 데이터셋을 갖는다는 의미이다.
- 두 값은 INFO REPLICATION이라는 커맨드로 확인 가능하다.
- offset값을 master, slave에서 각각 확인했을 때 값이 다르다면 slave에서 그 만큼의 커맨드를 실행해야 마스터와 값이 일치한다는 의미이다. 아래 예시에서는 802 ~ 807 커맨드를 실행해야 한다.
2.3 부분 재동기화
- 레디스는 네트워크 환경에 상관 없이 빠른 동기화를 부분 재동기화를 제공한다.
- 재연결 마다 RDB 파일을 새로 전달하면 네트워크가 안좋은 환경에서는 레디스 성능이 저하된다.
- 재동기화 과정
- 마스터는 백로그 버퍼라는 메모리 공간에 복제본에 전달한 커맨드를 저장해둔다. (기본 크기: 1MB, repl-backlog-size로 설정)
- 백로그는 repl-backlog-size가 다 차거나 repl-backlog-ttl만큼 지나면 삭제
- 복제본 재연결 후 PSYNC 커맨드 호출 후 자신의 replication id와 offset을 전달
- 마스터가 자신의 offset과 차이 비교 후 차이나는 offset 내용을 전달해서 부분 재동기화(partial resynchronization)
- 커맨드가 없거나 전달받은 replication id가 없다면 전체 재동기화(full resync)
- 마스터는 백로그 버퍼라는 메모리 공간에 복제본에 전달한 커맨드를 저장해둔다. (기본 크기: 1MB, repl-backlog-size로 설정)
2.4 Secondary 복제 ID
- 레디스는 4.0 부터 복제본이 마스터로 승격될 때를 대비해 복제 ID를 2개 가진다.
- master_replid는 마스터가 바뀔 때 같이 변경되며 기존 master_replid 값은 master_replid2에 저장된다.
- 이렇게 되면 새로운 마스터 노드에 slave들이 재연결할 때 master_replid가 다름으로 인해 전체 재동기화를 할 필요가 없어진다. master_replid2가 같다면 부분 재동기화를 진행한다.
2.5 읽기 전용 모드로 동작하는 복제본 노드
- 레디스 2.6 부터 복제본은 모두 read-only가 기본값이다. 이는 replica-read-only 옵션으로 제어된다.
- 이 때, replica-read-only 옵션을 변경해서 복제본 데이터를 변경했더라도, 변경은 로컬에서만 반영된다.
2.6 유효하지 않은 복제본 데이터
- 마스터와 복제본 데이터가 일치하지 않으면 유효하지 않은 상태이다.
- 마스터와 복제본 간 연결 유실, 복제 연결 미완료 등 상황에서 복제본 데이터가 유효하지 않다.
- 복제본 데이터가 유효하지 않을 때 동작을 replica-serve-stale-data 파라미터로 제어할 수 있다.
- yes: 기본값, 데이터가 유효하지 않아도 모든 읽기 요청을 실행한다
- no: INFO, CONFIG 등 일부 커맨드를 제외하고 모두 SYNC with in progress 에러를 반환한다.
2.7 백업을 사용하지 않는 경우에서의 데이터 복제
- 복제본 사용 시 데이터 안전성을 위해 백업 기능을 같이 사용하는 것이 좋다.
- 만약 백업을 사용하지 않는다면 마스터 레디스 자동 재시작 옵션을 사용하지 않는 것이 좋다. 그래야 복제본을 마스터로 변경해서 데이터가 사라지지 않는다.
- 만약 마스터의 자동 재시작이 실행되면 다음과 같은 상황이 발생한다.
- 백업을 사용하지 않는 마스터와 복제본이 존재한다.
- 마스터 노드가 장애로 종료되고, 마스터 레디스가 자동 재시작한다. 메모리는 초기화된다.
- 복제본 노드에 데이터가 존재하지만, 마스터 노드에 복제 연결을 시도한다.
- 마스터 노드는 빈 데이터셋을 전달한다.
출처 - 개발자를 위한 레디스