Redis Cluster
모드 적용 이후에 대기열 진입 API 실행 시에 다음과 같이 500 에러가 발생하는 것을 확인하였다.
검색을 통해 Redis Cluster 환경에서 발생하는 CROSSSLOT
에러라는 것을 확인 할 수 있었다.
Redis Cluster는 설정된 마스터 노드의 개수에 따라 Slot을 균등하게 배분받는다. 이 때 저장되는 키들은 해당하는 Slot을 관리하는 노드에 저장되게 된다.
현재 대기열 진입 API는 작업열 인원 수에 따라 분기가 발생하므로 Lua Script
를 통해 실행되고 있는데, 스크립트에서 실행되는 연산들은 원자성을 보장받기 위해 하나의 노드에서 실행되어야 한다고 한다.
하지만 현재 사용 중인 키들이 서로 다른 해시 슬롯에 매핑되어 있어 스크립트 실행이 불가능한 것이었다.
@Getter
@RequiredArgsConstructor
public enum RedisKeyPrefix {
// 대기열
WAITING_QUEUE("WaitingQueue:"),
WORKING_QUEUE("WorkingQueue:"),
TOKEN_VALUE("UserToken:");
private final String value;
}
결국 이를 해결하려면 스크립트에서 사용하는 키들이 같은 Slot으로 계산되어 저장되게 수정하면 된다.
먼자 Redis 키의 해시 슬롯 계산 방식
에 대해 살펴보면 다음과 같다.
- 키 이름의 해시값을 계산 (CRC16)
- 해시값을 16384(총 슬롯 수)로 나눈 나머지를 구함
- 해당 나머지 값에 해당하는 슬롯을 관리하는 노드에 키가 저장된다
이때 예외적으로, 키 이름에 중괄호 형태(ex: {...})의 해시 태그가 포함되어 있을 경우 해시 태그 내부의 문자열만을 사용하여 해시값을 계산한다고 한다.
따라서 이전의 키 prefix를 다음과 같이 수정해주었다.
@Getter
@RequiredArgsConstructor
public enum RedisKeyPrefix {
// 대기열
WAITING_QUEUE("{Queue}:WaitingQueue:"),
WORKING_QUEUE("{Queue}:WorkingQueue:"),
TOKEN_VALUE("{Queue}:UserToken:");
private final String value;
}
이제 API 요청을 성공적으로 수행하는 것을 확인할 수 있다.