복제
가용성은 일정 기간 동안 서비스를 정상적으로 사용할 수 있는 시간의 비율을 뜻한다. 레디스에서 고가용성을 확보하기 위해서는 아래의 두 가지 기능이 필요하다.
- 복제 : 마스터 노드의 데이터를 복제본 노드로 실시간 복사하는 기능이다. 마스터 노드의 서버에 장애가 생겨 데이터가 유실되어도 복제본 노드에서 데이터를 확인할 수 있다.
- 자동 페일오버 : 마스터 노드에서 발생한 장애를 감지해 레디스로 들어오는 클라이언트 연결을 자동으로 복제본 노드로 리디렉션하는 기능이다. 이를 통해 자동으로 엔드포인트를 변경하여 빠른 장애 조치가 가능하다.
레디스에서의 복제 구조
서비스에서 복제본 노드를 추가하는 이유는 다음과 같다.
- 애플리케이션을 실행하는 하드웨어는 언제든지 고장날 수 있기 때문에, 마스터 DB가 다운됐을 때 대신 사용할 여분의 복제본이 필요하다.
- 대규모 서비스에서 복제본은 트래픽을 감소시키는 역할을 수행할 수 있다. 마스터 노드에 접근하는 트래픽을 복제본으로 나누어 부하를 분산시킨다.
- 마스터 노드에서 매번 데이터의 백업을 받는 것은 부담스러운 작업이므로, 이를 복제본에서 수행하면 백업 작업이 서비스에 미치는 영향도를 줄일 수 있다.
MySQL이나 PostgreSQL은 멀티 마스터 복제 구조를 제공하여 모든 노드가 마스터이면서 동시에 복제본이 되는 구조이지만, 레디스는 이를 지원하지 않아서 마스터는 복제본이 될 수 없다. 복제본 노드는 기본으로 읽기 전용으로 동작하기 때문에 데이터의 입력은 마스터 노드에서 이뤄지는 것이 일반적이다.
레디스에서 복제본을 설정하는 것은 간단하다. 복제본 노드에서 아래의 커맨드를 입력하면 된다.
REPLICAOF <master-ip> <master-port>
레디스에서 마스터에는 여러 개의 복제본이 연결될 수 있으며, 복제본 노드에 또 복제본을 추가하는 것도 가능하다. 하지만 하나의 복제 그룹에서는 항상 한 개의 마스터 노드만 존재해야 한다.
복제 메커니즘
버전 7 이전과 이후의 차이가 있지만, 7 이후의 메커니즘만을 설명한다. 둘의 차이는 repl-diskless-sync 옵션의 Y/N 차이이며, 7 이후는 기본값이 yes 이다.
과정은 다음과 같다.
- REPLICAOF 커맨드로 복제 연결을 시도한다.
- 마스터 노드는 소켓 통신을 이용해 복제본 노드에 바로 연결하며, RDB 파일은 생성됨과 동시에 점진적으로 복제본의 소켓에 전송된다.
- (2)의 과정 동안 마스터 노드에서 수행된 모든 데이터셋 변경 작업은 레디스 프로토콜(RESP) 형태로 마스터의 복제 버퍼에 저장된다.
- 소켓에서 읽어온 RDB 파일을 복제본의 디스크에 저장한다.
- 복제본에 저장된 모든 데이터를 모두 삭제한 뒤 RDB 파일 내용을 메모리에 로딩한다.
- 복제 버퍼의 데이터를 복제본으로 전달해 수행시킨다.
복제본 노드는 마스터에서 가져온 데이터를 불러오기 전에 자신의 데이터를 모두 삭제하는 과정을 거쳐야 하는데, 이때 소켓 통신으로 받아온 RDB 데이터가 정상적인지를 미리 확인할 수 없기 때문에 모두 삭제하기 전 자신의 디스크에 데이터를 저장하는 과정을 선행함으로 데이터의 안정성을 확보할 수 있다.
디스크 I/O가 느리고, 네트워크가 빠른 경우 위 방식을 사용하는 것이 더 빠르게 복제 연결을 완료할 수 있다.
비동기 방식으로 동작하는 복제 연결
레디스는 비동기 방식으로 마스터에서 복제본으로 데이터가 전달된다. 따라서 데이터를 입력할 때마다 복제본에 데이터가 정확하게 전달됐는지 확인하는 과정을 거치지 않아서 복제 구조를 사용하더라도 짧은 지연 시간과 높은 성능을 갖는다. 다만 복제본에 전달이 되지 않고 마스터 노드가 비정상 종료된 경우에는 복제본에 데이터가 전달되지 않은 상태이기 때문에 유실될 가능성이 존재한다. 하지만 실제로 데이터가 복제본에 전달되는 속도는 굉장히 빨라서 유실이 빈번하지는 않는다.
센티널(Sentinel)이란
레디스의 자체 고가용성 기능인 센티널은 데이터를 저장하는 기존 레디스 인스턴스와는 다른 역할을 하는 프로그램이다. 센티널을 이용하면 마스터 인스턴스가 장애가 발생하더라도 레디스를 계속 사용할 수 있도록 하여 다운타임을 최소화할 수 있다.
기능
- 모니터링 : 마스터, 복제본 인스턴스를 실시간으로 확인한다.
- 자동 페일오버 : 마스터의 비정상 상태를 감지해 정상 상태의 복제본 중 하나를 마스터로 승격시킨다. 기존의 마스터로 연결된 복제본은 새로 승격된 마스터에 연결된다.
- 인스턴스 구성 정보 안내 : 센티널은 클라이언트에게 현재 구성에서의 마스터 정보를 알려준다. 페일오버가 발생하면 변경된 마스터 정보를 재전달하기 때문에 레디스의 엔드포인트 정보를 변경할 필요가 없다.
분산 시스템으로 동작하는 센티널
센티널은 그 자체로 단일 장애 지점이 되는 것을 방지하기 위해, 최소 3대 이상일 때 정상적으로 동작할 수 있도록 설계되었으며, 하나의 센티널이 이상이 생기더라도 다른 센티널이 계속해서 역할을 수행할 수 있다.
클라이언트는 먼저 센티널에 연결해 마스터의 정보를 받아온다. 만약 마스터와 복제본 인스턴스가 정상이지만 센티널 인스턴스가 문제가 생긴다면 클라이언트는 다른 2대의 센티널로부터 마스터의 정보를 받아올 수 있다.
센티널은 쿼럼(quorum)을 이용하여 오탐을 줄인다. 쿼럼은 마스터가 비정상 동작을 한다는 것에 대한 동의해야 하는 센티널의 수로, 쿼럼을 만족하는 경우 페일오버를 시작한다. 일반적으로 과반수이며, 따라서 센티널 인스턴스가 3개일 때 쿼럼은 2로 설정한다. 따라서 센티널은 홀수로 구성하는 것이 좋다.
센티널 인스턴스 배치 방법
센티널은 물리적으로 서로 영향받지 않는 서버에서 실행되는 것이 좋다. 마스터의 장애를 감지할 수 있어야 하기 때문에 서로 다른 가용영역에 배치하는 것이 일반적이다. 1개의 마스터와 2개의 복제본이 있는 경우, 서버A에 마스터와 센티널 1개, 서버B, C에 각각 복제본과 센티널 1개를 배치하여 나누는 것이 가장 일반적이며, 보통 하나의 서버에 레디스 프로세스와 센티널 프로세스를 동시에 실행시킨다.
서버 리소스에 여유가 있다면 위의 그림처럼 2개의 복제본을 가질 수 있도록 하는 것이 안정적이지만, 1개의 복제본만으로도 충분한 서비스가 있을 수 있다. 이럴 경우, 서버는 3개로 유지하고 서버당 센티널을 실행시키고, 2대의 서버에만 각각 마스터와 복제본을 띄우면 된다. 이때 센티널만 실행시키는 서버는 최저 사양의 스펙으로 구성이 되어도 괜찮다.
'TIL ✍️' 카테고리의 다른 글
24년 6월 16일(일요일) - 81번째 TIL : Failed to Connect to MySQL at 127.0.0.1 with user root (0) | 2024.06.16 |
---|---|
24년 4월 9일(화요일) 80번째 TIL : JUnit 조건에 따른 테스트 (0) | 2024.04.09 |
24년 1월 29일(월요일) - 78번째 TIL :레디스(1) : 캐싱 전략 (0) | 2024.01.31 |
24년 1월 25일(목요일) - 77번째 TIL : DB 로직 최소화 (0) | 2024.01.31 |
24년 1월 24일(수요일) - 76번째 TIL : StringRedisTemplate (1) | 2024.01.31 |