007 Redis Cluster Migration

tech blog 글 읽고 정리하기 #

초보 개발자를 위한 Redis Cluster Migration 가이드라인 #

요청상황 #

Master/Slave 구조의 Redis에서 Cluster 구조의 Redis로 migration 되니, 관련 코드 작업을 진행해야한다. 즉, Master/Slave에는 모든 key가 한 node에 있고 Cluster는 그렇지 않은 상황이다.

Master/Slave 구조와 Cluster 구조 #

  • Master/Slave 구조

    • Master의 내용을 Slave에 복제하여 read/write 권한을 나눠 사용하는 구조
    • 어떤 key가 들어오든 간에 하나의 master에서 처리를 진행 img.png
  • Cluster 구조

    • 여러대의 Master를 두어 가용성을 높인 구조
    • 하나의 Master가 fail되면 짝을 이루고있던 Slave가 Master로 승격되어 가용성을 보장하는 구조
    • 일반적으로 Cluster 구조에서는 3개의 node를 구성해서 사용 (경우에 따라 node의 개수 변경 가능)
    • key를 hash한 값에 따라 들어가는 master node가 달라진다. img_1.png

동시에 여러 key에 접근하지 않도록 하기 #

Master/Slave에는 모든 key가 한 node에 있고 Cluster는 그렇지 않은 상황

Cluster 구조에서는 key가 한 node에 있지 않고 여러 node에 분산되어 있는데, 그렇게 되면 동시에 여러 key에 접근하는 것이 불가능하다. 여러 key에 접근한다는 의미는 Redis 연산을 수행할 때 인자로 여러 개의 key를 넘기는 상황을 의미한다. (명령어 mget, mset 등)

# redis의 현재 상황
# {key: key1, value: "first"}
# {key: key2, value: "second"}
redis-cli > SET key1 "first"
redis-cli > SET key2 "second"

# MGET으로 2개의 key에 대한 값을 동시에 가져옴
redis-cli > MGET key1 key2
1) "first"
2) "second"

mget의 파라미터로 2개의 key를 넘겨주고 있는데, 코드에서 이러한 부분이 보이면 수정을 진행해야한다.

lettuce.io 에서는 Redis 연산자명 != 메서드명이다. 아래 코드를 보면 multiGet=mget 임을 알 수 있다.

// redis 연결
RedisTemplate<String, Integer> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);

// keys : key들이 들어있는 ArrayList
redisTemplate.opsForValue().multiGet(keys);

코드를 바꾸는 간단한 방법 for(반복문)을 돌면서 하나의 key에 대한 연산을 개별적으로 진행한다.

// redis 연결 부분 생략

// keys : key들이 들어있는 ArrayList
for(var key : keys) {
    redisTemplate.opsForValue().get(key);  
}

delete의 경우도 봐야함

var keys = new ArrayList<String>(); // 생성 후 element를 넣었다고 가정
var key = "key";

redisTemplate.delete(key);   // cluster 구조에서 문제 없음 -> 변경대상 아님
redisTemplate.delete(keys);  // cluster 구조에서 문제 있음 -> 변경대상

트랜잭션 전면 재검토 #

동시에 여러 key에 접근할 수 없게 만들었던 원흉인 Cluster의 key에 따른 node 분배 때문에 ‘트랜잭션’을 신경써야한다. 트랜잭션은 같은 node 안에서만 실행할 수 있기에, key의 hash값에 따라 들어가는 node가 달라지는 Cluster 구조에서는 트랜잭션을 적용하는 것이 불가능하다. Redis는 트랜잭션을 할 수 있도록 나름의 방법인 hash tag를 제공하고있다.

하나의 node에 몰아넣는 방법 - hash tags #

Redis의 key를 중괄호로 묶으면, 중괄호 내의 key를 hash한 결과값을 바탕으로 node에 할당한다.

key:{group}:test
key:group:test
key:{group}:hello
  • hash tag : 여기서 group이라는 문자열이 중괄호로 묶여 있는 것
    • hash tag가 없는 key는 key 전체를 hash하는 반면, hash tag를 포함한 key는 hash tag 내부에 있는 문자열에만 hash를 진행한다.
    • 따라서 같은 hash tag를 가진 다른 key도 같은 node에 들어가는 것을 보장할 수 있다. img_2.png