개요
앞서 작성한 Redis 백업 및 장애 복구 방법 게시글에서 언급했다시피 대용량 트래픽이 예상되는 서비스에서는 주로 Redis Sentinel 대신 Redis Cluster를 구성해서 운영을 합니다.
이번 게시글에서는 Redis Cluster 관련 개념을 간단히 정리하고 로컬에서 간단하게 클러스터 구축하는 방법에 대해 정리하겠습니다.
Redis Cluster
레디스 클러스터는 아래 세 가지 특성을 제공합니다.
- 다수의 노드에 자동으로 데이터 분산
- 일부 노드에 연결 실패하더라도 계속 동작하는 가용성
- 고성능을 보장하면서 선형 확장성을 제공
- 요구사항이 증가하더라도 비용이 선형적으로 증가
- 즉, y축이 비용, x축이 요구사항 개수라고 할 때 일차 함수
Redis Cluster 특징
레디스 클러스터의 특징은 아래와 같습니다.
- full-mesh 구조로 통신 (모든 노드끼리 연결되어 있는 구조)
- cluster bus라는 추가 채널 사용하며 보통은 Redis 기본 포트인 6379에 10000을 더한 16379를 포트로 사용
- gossip protocol 사용
- 사내 소문이 순식간에 퍼지는 것처럼 일부 노드에 정보를 전달하면 full-mesh 구조이기 때문에 결국에는 모든 정보가 해당 정보를 알게 된다는 논리
- 16,384개의 hash slot을 사용한 키 관리
- DB0 만 사용 가능하며 이는 클러스터 노드에는 DB 1개만 사용 가능하다는 의미
- 데이터가 노드 간 분산되어 있기 때문에 multi key 명령어를 사용할 수 없음
- 클라이언트는 모든 노드에 접속
Redis Cluster vs Sentinel
레디스 클러스터와 레디스 센티넬과의 차이점은 아래와 같습니다.
- 클러스터는 데이터 분산(샤딩)을 제공
- 클러스터는 자동 장애조치를 위한 모니터링 노드(Sentinel)를 추가 배치할 필요 없음
- 앞서 언급했듯이 클러스터는 샤딩을 제공하기 때문에 multi key 명령어를 사용할 수 없음
- Sentinel의 경우 비교적 단순한 소규모 시스템에서 고가용성이 필요할 때 채택하고 TPS가 높은 대규모 시스템에서는 주로 Redis Cluster를 사용
Redis Cluster 샤딩하는 기준
레디스 클러스터에서 데이터를 분산하는 기준은 아래와 같습니다.
- 특정 키의 데이터가 어느 노드에 속할 것인지 결정해야 하는 메커니즘으로 해싱을 사용
- 다만, 노드의 개수를 줄이거나 늘릴 때마다 모든 매핑을 새로 계산하는 단순 해싱으로는 한계가 존재
(hash([key]) % 노드의 개수)
- 다만, 노드의 개수를 줄이거나 늘릴 때마다 모든 매핑을 새로 계산하는 단순 해싱으로는 한계가 존재
- 앞서 레디스 클러스터 특징으로 언급했던 16384개의 hash slot으로 키 공간을 나누어 관리
- 각 키는 CRC16 해싱 후 16384로 모듈러 연산을 해 각 hash slot으로 매핑하고 hash slot은 각 노드들에게 나누어 분배
- CRC16의 자세한 내용은 아래 링크 참고
- https://ko.wikipedia.org/wiki/%EC%88%9C%ED%99%98_%EC%A4%91%EB%B3%B5_%EA%B2%80%EC%82%AC
클라이언트가 Redis Cluster 내 데이터 접근하는 방법
클라이언트가 특정 key를 요청할 때 클러스터 노드가 특정 키가 해당하는 노드로 자동 redirect 해주는 구조는 아닙니다.
클라이언트가 특정 노드로 요청을 했을 때 키가 포함되어 있으면 다행이지만 해당 키가 포함된 노드가 아닐 경우 MOVED 에러를 반환하고 해당 에러를 받은 클라이언트는 MOVED 에러에 언급된 올바른 노드로 재요청해야 합니다.
얼핏 보면 매번 다른 노드로 요청해서 재시도를 계속한다면 매우 비효율적인 것 아니냐고 생각할 수 있지만 레디스 클러스터가 매핑 테이블을 캐싱하고 있기 때문에 재시도가 자주 발생하지는 않습니다.
Redis Cluster의 성능, 데이터 일관성 및 가용성
클라이언트 입장에서는 Redis를 단일 인스턴스로 사용하는 것과 클러스터로 구성하는 것과 상관없이 동일한 성능으로 이용 가능합니다.
다만, 클러스터와 같은 분산 시스템에서 성능은 데이터 일관성과 일종의 trade-off가 존재합니다.
- 레디스 클러스터의 경우 고성능의 수평 확장성을 제공하면서 적절한 수준의 데이터 안전성 및 가용성을 유지하는 것으로 목표
- 레디스 클러스터의 경우 높은 성능을 유지하기 위해 비동기 복제하를 하기 때문에 strong consistency를 제공하지는 않기 때문에 데이터 일관성이 깨질 수 있음 (Master 노드에 저장했지만 Replica 노드에 복제하기 전에 Master 노드가 죽을 경우 데이터 유실)
클러스터는 고가용성을 제공하기 위해 아래와 같은 기능을 제공합니다.
- auto failover
- replica migration
첫 번째 기능으로 언급된 auto failover 기능을 제공하기 위해서는 아래와 같이 두 가지 조건이 성립해야 합니다.
- 과반수 이상의 마스터 노드가 RUNNING 상태
- 사라진 마스터 노드의 레플리카 노드가 RUNNING 상태
위와 같은 조건이 성립할 때 node timeout 동안 과반수의 마스터 노드들과 통신하지 못한 master는 스스로 error 상태로 빠지고 write 요청을 받지 않고 error 상태로 빠진 마스터 노드의 레플리카 노드가 master로 승격되어 hash slot을 커버 가능합니다.
그리고 replica migration의 경우 redis.conf에 설정에 각 마스터 노드 당 갖는 최소 replica 개수를 설정할 수 있습니다.
그리고 운영 도중 장애로 인해 특정 마스터 노드가 설정한 최소 replica 개수를 충족시키지 못했을 때 여유가 있는 마스터 노드로부터 replica 노드를 양도받는 기능이 replica migration입니다.
Redis Cluster의 제약 사항
레디스 클러스에는 아래와 같이 크게 세 가지의 제약 사항이 존재합니다.
- 클러스터에서는 단일 DB인 DB0만 사용 가능
- 데이터가 각기 다른 노드로 분산되어 있기 때문에 Multi Key operation 사용 불가능
- 같은 노드 안에 속한 key들에 대해서는 multi key 명령어 사용 가능
- hash tags 기능을 통해 다양한 key들을 하나의 hash slot에 저장 가능
- 클라이언트는 클러스터 내 모든 노드에 접속해야 하기 때문에 MOVED 에러에 따른 redirect 기능 구현의 강제성 필요
- spring-data-redis 혹은 node.js에서 제공하는 라이브러리처럼 잘 구현된 라이브러리의 경우 별도 구현 필요 없음
로컬에서 간단하게 Redis Cluster 구축 (Mac북 기준)
우선 redis 공식 사이트에서 버전에 맞는 redis.conf 파일을 다운로드하여 주세요.
저 같은 경우 docker에서 최신 이미지를 받아 띄웠으므로 redis.conf 7.2 버전을 다운로드하였습니다.
https://redis.io/docs/management/config/
그리고 레디스 노드들을 7000~7005번 포트에 띄울 것이므로 홈 디렉터리에 7000~7005번 디렉터리를 mkdir 700X와 같이 생성해 주고 각 디렉터리 하위에 다운로드한 redis.conf를 복사 붙여 넣기 해주세요.
이렇게 각 노드마다 별도 디렉터리를 만든 이유는 redis-server 명령어를 통해 레디스 노드를 띄우는데 같은 디렉터리에서 redis-server 명령어를 여러 번 실행할 경우 nodes.conf 파일을 서로 다른 노드끼리 공유할 수 없다는 문구와 함께 실패하기 때문입니다.
아 그리고 다운로드한 redis.conf 내에는 디폴트로 port 번호가 6379로 세팅되어 있을 것인데 각각의 디렉터리명과 똑같이 port 번호를 바꿔줘야 합니다.
또한, 각 redis.conf 설정에 cluster-enabled 설정이 yes로 되어있는 것을 확인해야 합니다.
앞선 설정이 완료되었으면 각 디렉토리 내에서 아래와 같은 명령어를 실행하면 됩니다.
redis-server redis.conf
7000 ~ 7005번 포트에 레디스 인스턴스를 띄운 이후에는 클러스터 구성을 해야 하는데 아래와 같이 명령어를 실행하면 레디스 클러스터를 구성할 수 있습니다.
redis-cli --cluster create localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005 --cluster-replicas 1
위와 같이 실행하면 클러스터가 구성이 되었고 저 같은 경우 7000, 7001, 7002번 인스턴스가 마스터 노드로 선정되었고
7004번이 7000번, 7005번이 7001번, 그리고 7003번이 7002번의 레플리카 노드로 지정되었습니다.
클러스터가 구성이 되면 hash slot이 지정되었다고 아래와 같은 안내문이 나옵니다.
Redis Cluster auto-failover 기능 체크
Redis Cluster의 auto-failover 기능을 간단하게 체크가 가능합니다.
마스터 노드인 7001번 인스턴스를 잠시 껐다가 다시 띄우면 됩니다.
이렇게 되면 레플리카 노드였던 7005번 인스턴스가 Master로 승격되고 7001번 인스턴스가 레플리카가 되는 것을 확인할 수 있습니다.
노드를 추가하는 방법
노드를 추가하고 싶으면 우선 7006번 디렉터리를 생성하고 앞선 예시와 똑같이 레디스 인스턴스를 띄웁니다.
그리고 아래와 같이 명령어를 작성하면 레디스 인스턴스를 마스터 노드로 추가가 가능합니다.
redis-cli --cluster add-node localhost:7006 localhost:7001
반면, 레플리카 노드로 띄우고 싶다면 아래와 같이 명령어를 실행하면 됩니다. (새로운 7007번 인스턴스를 방금 추가한 7006번 인스턴스의 레플리카 노드로 추가)
redis-cli --cluster add-node localhost:7007 localhost:7006 --cluster-slave
스프링부트 설정
저 같은 경우 프로젝트를 진행할 때 주로 스프링부트를 사용하는데 다행히 스프링부트의 경우 redis cluster 설정을 아래와 같이 지정하면 제공해 주는 spring-data-redis 라이브러리를 통해 쉽게 레디스 연동이 가능합니다.
비고
redis-conf 내 주요 설정들
- cluster-enabled: 클러스터 모드로 실행할지 여부 결정 (yes/no)
- cluster-config-flie [filename]: 해당 노드의 클러스터를 유지하기 위한 설정을 저장하는 파일 (사용자 수정하지 않음)
- cluster-node-timeout [milliseconds]: 특정 노드가 정상이 아닌 것으로 판단하는 기준 시간이며 해당 시간동안 감지되지 않은 master 노드는 replica 노드에 의해 failover가 이루어짐
- cluster-replica-validity-factor [factor]: master 노드와 통신한지 오래된 replica가 failover를 수행하지 않게 하기 위한 설정
- (cluster-node-timeout * factor)만큼 master 노드와 통신이 없었던 레플리카 노드는 failover 대상에서 제외
- cluster-migration-barrier [count]: 한 마스터 노드가 유지해야하는 최소 레플리카 노드의 개수
- 이 개수를 충족하는 선에서 일부 레플리카 노드가 replica migration 실행 가능
- cluster-require-full-coverage: 일부 hash slot이 커버되지 않을 때 write 요청을 받지 않을지 여부 (yes/no)
- 디폴트 값은 yes이며 no로 설정할 경우 일부 노드에 장애가 생겨 해당 hash slot이 정상 작동하지 않더라도 나머지 hash slot에 대해서는 작동하도록 할 수 있음
- cluster-allow-reads-when-down: 클러스터 상태가 정상이 아니더라도 read 요청은 받도록 할지 여부 (yes/no)
- 디폴트 설정은 yes이며 어플리케이션에서 read 동작의 일관성이 중요치 않은 경우 yes로 설정
출처
백엔드 개발자를 위한 한 번에 끝내는 대용량 데이터 & 트래픽 처리 초격자 패키지 Online - 고성능 서비스를 위한 Redis 활용 및 아키텍처
'Redis' 카테고리의 다른 글
[Redis] Redis Streams (0) | 2023.11.22 |
---|---|
[Redis] Redis 성능 튜닝 (1) | 2023.11.21 |
[Redis] Redis 백업 및 장애 복구 방법 정리 (0) | 2023.11.15 |