본문 바로가기

독서/개발자를 위한 레디스

[개발자를 위한 레디스] 10장 클러스터

반응형
SMALL

레디스 클러스터와 확장성

스케일 업 vs 스케일 아웃

확장성: 운영 중인 시스템에서 증가하는 트래픽에 유연하게 대응할 수 있는 능력

 

리소스를 투입하는 방식에 따라 스케일 업과 스케일 아웃으로 구분할 수 있다.

스케일 업과 스케일 아웃

  • 스케일 업 (수직 확장): 서버의 하드웨어를 높은 사양으로 업그레이드하는 것
  • 스케일 아웃 (수평 확장): 장비를 추가해 시스템을 확장시키는 방식

 

레디스에서의 확장성

  • 키의 이빅션(eviction)이 자주 발생한다면 서버의 메모리를 증가시키는 스케일 업을 고려할 수 있다.
    • 키의 이빅션: 레디스 인스턴스의 max memory만큼 데이터가 차 있을 때 또 다시 데이터를 저장할 때 발생하는 것
  • 처리량을 증가시키고자 할 때 여러 서버로 분할해 관리하면 다수의 서버에서 요청을 병렬로 처리할 수 있으므로, 서버 대수를 늘림으로써 처리량을 선형적으로 확장시킬 수 있다.

 

레디스 클러스터의 기능

  • 클러스터 모드를 사용하면 수평 확장이 가능해진다.
  • 데이터의 분산 처리와 복제, 자동 페일오버 기능 또한 사용할 수 있다.

 

데이터 샤딩

레디스 클러스터 기능 - 샤딩

클러스터에서 데이터는 키를 이용해 샤딩되면 하나의 키는 항상 하나의 마스터 노드에 매핑된다.

 

고가용성

레디스 클러스터 기능 - HA(High Availability)

  • 클러스터 내의 노드들은 클러스터 버스라는 독립적인 통신을 이용한다.
  • 클러스터는 풀 메쉬 토폴로지 형태이다.
  • 1개 노드에서 다른 노드로 PING을 보냈을 때 PONG 응답이 늦는다면 해당 노드로의 연결을 새로 시도한다.

 

레디스 클러스터 동작 방법

해시슬롯을 이용한 데이터 샤딩

3대의 마스터 노드로 클러스터를 구성한다.

 

해시슬롯의 분포

  • 첫 번째 마스터 노드는 0부터 5460까지의 해시글롯을 포함
  • 두 번째 마스터 노드는 5461부터 10922까지의 해시슬롯을 포함
  • 세 번째 마스터 노드는 10923부터 16383까지의 해시슬롯을 포함

 

해시슬롯에 키가 저장되는 과정

 

$ HASH_SLOT = CRC16(key) mod 16384

모든 키는 하나의 해시슬롯에 매핑된다.

 

마스터 노드의 추가

해시슬롯은 마스터 노드 내에서 자유롭게 옮겨질 수 있으며, 옮겨지는 중에도 데이터는 정상적으로 접근할 수 있다.

 

해시태그

$ MGET user1:name user2:name

다중 키 커맨드: 한 번에 여러 키에 접근해 데이터를 가져오는 커맨드

 

클러스터에서 다중 키 커맨드를 사용할 수 없는 이유

레디스 클러스터에서는 서로 다른 해시슬롯에 속한 키에 대해서는 다중 키 커맨드를 사용할 수 없다.

 

user:{123}:profile
user:{123}:account

 

해시태그 기능을 사용하면 이런 문제를 해결할 수 있다. 키에 대괄호를 사용하면 전체 키가 아닌 대괄호 사이에 있는 값을 이용해 해시될 수 있다.

 

자동 재구성

모든 노드는 클러스터 버스를 통해 통신하며, 인스턴스에 문제가 생겼을 때 자동으로 클러스터 구조를 재구성한다.

 

자동 페일오버

자동 페일오버

 

자동 복제본 마이그레이션

자동 복제본 마이그레이션

모든 마스터가 적어도 1개 이상의 복제본에 의해 복제되는 것을 보장한다.

 

cluster-allow-replica-migration yes
cluster-migration-barrier 1
  • cluster-allow-replica-migration 옵션이 yes일 때 동작한다.
  • cluster-migration-barrier는 복제본을 마이그레이션하기 전 마스터가 가지고 있어야 할 최소 복제본의 수를 의미한다.

 

레디스 클러스터 실행하기

6개의 레디스 인스턴스를 사용한다. 3개의 노드는 마스터, 나머지 노드는 복제본이 되도록 구성한다.

 

클러스터 초기화

클러스터 초기화

cluster-enabled yes

클러스터 모드로 변경한다.

 

redis-cli -cluster create [host:port] --cluster-replicas 1

클러스터를 생성한다.

  • cluster-replicas 1 옵션: 각 마스터마다 1개의 복제본을 추가

 

클러스터 상태 확인하기

현재 클러스터의 상태를 확인할 수 있다.

 

<id> <ip:port@cport> <flags> <master> <ping-sent> <pong-recv> <config-epoch> <link-state> <slot> <slot> ... <slot>
  • id: 노드가 생성될 때 자동으로 만들어지는 랜덤 스트링의 클러스터 ID 값
  • ip:port@cport: 노드가 실행되는 ip와 port 그리고 클러스터 버스 포트 값
  • flags: 노드의 상태
  • master: 복제본 노드일 경우 마스터 노드의 ID, 마스터 노드일 경우 - 문자가 표시된다.
  • ping-sent: 보류 중인 PING이 없다면 0, 있다면 마지막 PING이 전송된 유닉스 타임을 표시한다.
  • pong-sent: 마지막 PONG이 수신된 유닉스 타임을 표시한다.
  • cofig-epoch: 현재 노드의 구성 에포크
  • link-state: 클러스터 버스에 사용되는 링크의 상태
  • slot: 노드가 갖고 있는 해시슬롯의 범위를 표시한다.

 

redis-cli를 이용해 클러스터 접근하기와 리디렉션

$ redis-cli
127.0.0.1:6379> set user:1 true
(error) MOVED 10778 192.168.0.22:6379

레디스에 접속한다.

 

클러스터 모드에서 redis-cli를 이용한 데이터 저장 (1)

일반적인 클라이언트를 이용해 데이터를 넣을 때에는 데이터가 저장될 수 있는 노드가 정해져 있고 해당 노드에만 키에 대한 커맨드를 수행시킬 수 있음을 의미한다.

 

$ redis-cli -c
127.0.0.1:6379> set user:1 true
-> Redirected to slot [10778] located at 192.168.0.22:6379
OK
127.0.0.1:6379>

-c 옵션을 추가해 클러스터 모드로 사용할 수 있다. 이때 리디렉션 기능이 제공된다.

 

클러스터 모드에서 redis-cli를 이용한 데이터 저장 (2)

  • 클라이언트가 연결을 192.168.0.11에서 저장하고자 하는 키가 있는 192.168.0.22로 자동으로 옮겼다.
  • 반환받은 에러를 변경된 노드로 직접 연결을 변경한 뒤 올바른 레디스 노드에서 커맨드를 다시 수행한다.

 

페일오버 테스트

커맨드를 이용한 페일오버 발생(수동 페일오버)

클러스터 페일오버 (1)

 

192.168.0.55:6379> INFO REPLICATION
# Replication
role:slave
master_host:192.168.0.11
master_port:6379
.
.
.

192.168.0.55:6379> CLUSTER FAILOVER
OK

192.168.0.55:6379> INFO REPLICATION
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.0.11,port=6379,state=online,offset613998,lag=0
  • 페일오버를 발생시킬 복제본 노드에서 cluster failover 커맨드를 실행하면 페일오버를 발생시킬 수 있다.
  • INFO REPLICATION 커맨드로 복제 연결 상태를 확인할 수 있다.

 

마스터 동작을 중지시켜 페일오버 발생(자동 페일 오버)

$ redis-cli -h <master-host> -p <master-port> shutdown

레디스의 프로세스를 직접 shutdown 시킨다.

  • cluster-node-timeout 시간 동안 마스터에서 응답이 오지 않으면 마스터의 상태가 정상적이지 않다고 판단해 페일오버를 트리거한다.

 

레디스 클러스터 운영하기

클러스터 리샤딩

리샤딩: 마스터 노드가 가지고 있는 해시슬롯 중 일부를 다른 마스터로 이동하는 것

 

$ redis-cli --cluster reshared 192.168.0.66 6379

redis-cli에서 cluster reshared 옵션을 이용해 리샤딩을 수행할 수 있다.

 

# 이동시킬 슬롯의 개수 결정
How many slots do you want to move (from 1 to 16384)? 100

# 해시슬롯을 받을 노드의 ID 입력
What is the receiving node ID? ab1b4edfa...

# all을 입력하면 모든 마스터 노드에서 조금씩 이동할 것을, done을 입력하면 가져올 마스터 ID를 지정하는 것을 의미
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:

 

클러스터 리샤딩-간단 버전

redis-cli --cluster reshared <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes
  • 사용자와의 인터렉션 없이 바로 슬롯을 이동시키는 방법도 존재한다.
  • --cluster-yes 커맨드는 모든 프롬프트에 자동으로 yes를 입력하겠다는 것을 의미한다.

 

클러스터 확장-신규 노드 추가

운영 중인 클러스터에 새로운 노드를 추가해본다. (추가하고자 하는 레디스에는 데이터가 저장되지 않은 상태여야 함)

 

마스터로 추가하기

redis-cli --cluster add-node <추가할 노드 ID:PORT> <기존 노드 IP:PORT>

--cluster add-node 커맨드로 클러스터에 신규 마스터 노드를 추가할 수 있다.

 

복제본으로 추가하기

redis-cli --cluster add-node <추가할 노드 IP:PORT> <기존 노드 IP:PORT> --cluster-slave [--cluster-master-id <기존 마스터 ID>]

--cluster-slave 옵션으로 신규 노드를 복제본으로 추가할 수 있다.

 

노드 제거하기

redis-cli --cluster del-node <기존 노드 IP:PORT> <삭제할 노드 ID>

클러스터에서 노드를 제허가 위해 del-node 커맨드를 사용한다.

  • 마스터 노드의 경우 리샤딩 작업이 선행되어야 한다. 또는 수동으로 페일오버를 진행한 뒤 노드의 역할을 복제본으로 만들어야 한다.

 

CLUSTER FORGET

클러스터를 제거하기 위해서는 제거될 노드에서 클러스터 구성 데이터를 지우는 것뿐만 아니라,

클러스터 내의 다른 노드들에게도 해당 노드를 지우라는 커맨드를 함께 보내야 한다.

 

CLUSTER FORGET <node-id> 커맨드를 수신한 노드는 노드 테이블에서 제거할 노드의 정보를 지운 뒤,

60초 동안은 이 노드 ID를 가지고 있는 노드와 신규로 연결되지 않도록 설정한다.

 

CLUSTER RESET

CLUSTER RESET [SOFT/HARD]

클러스터 리셋 커맨드는 제거될 노드에서 수행한다.

  1. 클러스터 구성에서 복제본 역할을 했었다면 노드는 마스터로 전환되고, 노드가 가지고 있던 모든 데이터셋은 삭제된다. 노드가 마스터이고 저장된 키가 있다면 리셋 작업이 중단된다.
  2. 노드가 해시슬롯을 가지고 있었다면 모든 슬롯이 해제되며, 만약 페일오버가 진행되는 과정이었다면 페일오버에 대한 진행 상태도 초기화된다.
  3. 클러스터 구성 내의 다른 노드 데이터가 초기화된다. 기존에 클러스터 버스를 통해 연결됐던 노드를 더 이상 인식할 수 없다.
  4. currentEpoch, configEpoch, lastVoteEpoch 값이 0으로 초기화된다.
  5. 노드의 ID가 새로운 임의 ID로 변경된다.

 

레디스 클러스터로의 데이터 마이그레이션

데이터 마이그레이션

데이터를 전달받을 클러스터 노드에서 소스 레디스 노드로 데이터 import 요청을 한다.

 

redis-cli --cluster import 192.168.0.11:6379 --cluster-from 192.168.0.88:6379 --cluster-copy

위 커맨드를 이용해 데이터를 마이그레이션 할 수 있다.

 

복제본을 이용한 읽기 성능 향상

복제본을 이용한 읽기

키를 저장한 마스터와 다른 마스터에서 읽어오려 하면 에러가 발생한다.

 

마스터에 데이터를 읽어가는 부하가 집중되는 경우

데이터를 쓰는 커넥션은 마스터에, 읽기는 복제본에서 수행할 수 있도록

커넥션을 분배시켜 읽기 성능을 향상시킬 수 있다.

 

$ redis-cli -h 192.168.0.55 -c
192.168.0.55:6379> readonly
OK
192.168.0.55:6379> get hello
"world"

READONLY 모드로 변경해 클라이언트가 복제본 노드에 있는 데이터를 직접 읽을 수 있게 한다.

 

레디스 클러스터 동작 방법

하트비트 패킷

레디스 클러스터 노드들은 지속적으로 서로의 상태를 확인하기 위해 PING, PONG 패킷을 주고받는다.

이 두 패킷을 묶어 하트비트 패킷이라 한다.

 

일반적으로 사용하는 패킷의 헤더는 다음 정보를 포함한다.

  • 노드 ID
  • 현재 에포크/구성 에포크: 분산 환경에서 일관성을 유지하기 위한 정보
  • 노드 플래그: 노드가 마스터인지, 복제본인지 등의 노드 정보
  • 비트맵: 마스터가 제공하는 해시슬롯의 비트맵 정보
  • TCP 포트: 발신 노드의 TCP 포트
  • 클러스터 포트: 발신 노드의 노드 간 커뮤니케티션을 위한 포트
  • 클러스터 상태: 발신 노드 관점에서 봤을 때의 클러스터 상태
  • 마스터 노드 ID: 복제본 노드인 경우 마스터의 노드 ID
  • 하트비트 패킷인 경우 가십 섹션을 추가로 포함: 패킷을 발신하는 노드가 알고 있는 클러스터 내 다른 노드 정보

 

해시슬롯 구성이 전파되는 방법

  • 하트비트 패킷: 마스터 노드가 PING, PONG 패킷을 보낼 때 항상 자기가 갖고 있는 해시슬롯을 패킷 데이터에 추가
  • 업데이트 메시지: 하트비트 패킷에는 발신하는 노드의 구성 에포크 값이 포함되어 있으며, 패킷을 보낸 노드의 에포크 값이 오래됐다면 해당 패킷을 받은 노드는 신규 에포크의 구성 정보를 포함한 업데이트 메시지를 노드에 보내 하트비트 패킷을 보낸 노드의 해시슬롯 구성을 업데이트

 

노드 핸드셰이크

CLUSTER MEET 커맨드를 수신한 노드는 자신이 알고 있는 다른 노드들에게 전파하고, 이 정보를 수신한 노드가 신규 합류한 노드를 모르는 상태라면 해당 노드와 CLUSTER MEET을 통해 신규 연결을 맺는다.

  • CLUSTER MEET: 방향성이 없기 때문에, A와 B에 커맨드로 연결됐다면 B가 A에 같은 커맨드를 보낼 필요는 없다.

 

클러스터 라이브 재구성

클러스터가 정상적으로 운영되는 동안 새로운 마스터 노드를 추가하거나 기존 마스터 노드를 제거할 수 있다.

  • 추가: 빈 노드를 클러스터에 추가한 뒤, 일부 해시슬롯을 기존 마스터에서 신규 노드로 옮긴다.
  • 제거: 해당 노드를 빈 노드로 만들기 위해, 갖고 있던 해시슬롯을 다른 노드로 보낸다.

 

MIGRATE target-host target-port key target-database id timeout
  • MIGRATE: 대상 인스턴스에 연결해서 키를 전송하고, OK 코드를 받으면 기존 데이터셋에서 키를 삭제한다.
  • 마이그레이션 프로세스가 완료되면 두 노드에게 모두 SETSLOT <slot> NODE <node-id> 커맨드를 전송한다.

 

리디렉션

MOVE 리디렉션

  • "요청하는 해시슬롯이 저 노드에 있으니 앞으로 이 키에 대한 요청은 저 노드로 보내"
  • 레디스 노드는 클라이언트가 보낸 커맨드가 단일 키 커맨드인지 혹인 다중 키인 경우 언급된 여러 키가 모두 동일한 해시슬롯에 있는지 파악한 뒤 키가 속한 해시슬롯을 포함한 마스터 노드를 찾는다.
  • MOVED 에러는 키의 해시슬롯과 해당 해시슬롯을 갖고 있는 마스터 노드의 정보를 반환한다.

 

ASK 리디렉션

  • "지금 요청한 이 쿼리는 저 노드에서 수행해. 하지만 다음 노드는 다시 나한테 보내"
  • 해시슬롯이 이동되는 과정에서만 발생한다.
    • 리디렉션 오류가 반환한 노드 정보로 쿼리를 재전송하지만, 이후에 같은 키에 대한 쿼리가 들어오면 기존에 전송한 노드에 다시 보낸다.
    • 리디렉션을 받은 값으로 클라이언트의 해시슬롯 맵을 업데이트하지 않는다.

 

ASK 리디렉션 (1)

A가 갖고 있던 해시슬롯 8을 B로 옮기는 과정이다.

  • B 노드에 이 키 값을 요청하면 B는 리디렉션 요청을 보낸다. (ASK 요청)

 

ASK 리디렉션 (2)

마이그레이션이 완료된 이후

 

MOVED 리디렉션

해시슬롯을 소유하고 있는 노드가 완전히 B로 변경됐으므로, 클라이언트의 해시슬롯 맵을 업데이트해 다음 연결이 지속적으로 B로 이뤄지게 하는 것이 적절한다.

 

장애 감지와 페일오버

PFAIL 플래그

  • Possible failure, 일부 노드에서는 해당 노드에 접근할 수 없지만, 아직 확실하지 않은 실패
  • 특정 노드에 NODE_TIMEOUT 시간 이상 도달할 수 없는 경우 표시한다.
  • 노드 간 왕복 시간(RTT) NODE_TIMEOUT 값은 항상 커야 한다.

 

FAIL 플래그

  • 대다수의 노드에서 해당 노드에 장애가 발생했음을 동의한 상태
  • 실제로 마스터 노드에 장애가 발생했다고 인지해서 페일오버를 트리거시키기 위해서 FAIL 상태여야 한다.
  • 다른 노드가 보낸 하트비트 패킷에서 B의 상태에 대한 정보를 듣는다. 이때 일정 시간 내에 다른 노드에서 B에 대한 PFAIL 또는 FAIL 알림을 받으면 이 노드를 FAIL이라 플래깅한다.

 

복제본 선출

  • 마스터가 FAIL 상태이다.
  • 마스터는 1개 이상의 해시슬롯을 갖고 있다.
  • 마스터와의 복제가 끊어진 지 오래다.

 

복제본 선출

  • 모든 마스터 노드에 FAILOVER_AUTH_REQUEST 패킷을 보내 투표를 요청한다.
  • 요청을 받은 마스터는 FAILOVER_AUTH_ACK 패킷으로 긍정적인 응답을 보내 투표에 동의함을 알린다.
  • NODE_TIMEOUT*2시간 동안은 같은 마스터로 승격되고자 하는 다른 복제본에게는 투표할 수 없다.

 

DELAY = 500ms + 랜덤 지연 시간 (0~500ms) + SLAVE_RANK * 1000ms

마스터가 FAIL 상태가 된 이후 복제본은 짧은 딜레이(DELAY)를 가진 뒤 투표를 시작한다.

  • SLAVE_RANK: 마스터에서 처리한 복제 데이터의 양과 관련된 복제본의 우선순위
반응형
LIST