반응형
첫 번째 방법
Redis에서 트랜잭션을 위한 커맨드를 제공한다.
(MULTI/EXEC/DISCARD/WATCH)
- MUlTI: 트랜잭션 진입
- EXEC: 커밋
- DISCARD: 롤백
Watch의 경우 get & set과 같이 락이 필요한 경우, WATCH 명령을 통해 낙관적 락을 사용할 수 있음.
- WATCH 사용 시, Race Condition이 발생하면, 트랜잭션이 실패해서 재처리가 필요함.
한계점
1. 해당 명령을 통해, 트랜잭션 내의 중간 명령의 결과를 받아서, 다음 명령에 대한 분기처리를 할 수 없다
- 무슨 말 이냐면, 예를 들어서 다음과 같이 incr 명령의 결괏값에 따른 분기 처리 등을 할 수 없는 한계가 존재한다
# 수도 코드
if (incr, "key" > 1 ) {
pexpire("key", 1000)
}
2. Redis Transaction 커맨드의 경우 Redis Cluster Mode에서는 지원하지 않음.
- 관련 내용: https://stackoverflow.com/a/42091605
- Redis cluster는 16384개의 hash slot에 나눠서 데이터를 저장하는데, 대상 키들이 모두 같은 슬롯에 있는 경우에만 트랜잭션을 실행할 수 있고, 다중 슬롯에 키가 나눠져 있는 경우 트랜잭션을 실행할 수 없음
Redis Cluster에서 트랜잭션이 필요하거나, 트랜잭션 내의 중간 연산 결과에 따른 분기처리가 필요한 경우는 어떻게 처리할까?
두 번째 방법
- Redis 2.6부터 Lua script를 실행할 수 있는 커맨드를 제공한다.
- 한 스크립트 내의 명령들은 Atomic 하게 처리된다.
EVAL: Lua script를 실행하는 연산 (readonly로 EVAL_RO 등 다른 연산도 존재함)
EVAL 명령을 통해 Lua scipts를 실행할 수 있기 때문에
if (redis.call('incr', KEYS[1]) > 100) then
redis.call('pexpire', KEYS[1], ARGV[2]]);
return 1;
else
return 0;
end
이런 식의 중간 incr 연산의 결과에 따른 분기 처리도 가능하다.
EVAL 동작 방식이, 레디스 노드를 블로킹해서, 다른 연산이 처리되지 않게 한 후, 스크립트 내의 요청을 처리한다.
- 레디스는 싱글 스레드이기 때문에, 무거운 쿼리들이 나가지 않게 주의해야 하는데.. (싱글 스레드이기 때문에, 한 시점의 하나의 요청만 처리가 가능하기 때문에, 쿼리 처리 시간이 길면 뒤의 요청이 밀릴 수 있음)
- 특히나 Lua script을 실행하는 경우는 여러 쿼리들을 블로킹해서 실행하기 때문에, 특히나 더욱 무거운 쿼리가 나가지 않게 주의해야 한다.
한계점
- 타입 체크도 안되고 기타 등등으로 High Level 입장에서 사용하기 불편하기 때문에, 꼭 필요한 곳에서만 사용하는 것이 좋음.
- 예를 들어 키가 존재하지 않는 경우에만 set 하는 경우, setnx 연산을 사용할 수 있고 기타 등등을 사용할 수 있음.
- 분산 락 구현을 위한 레디스 라이브러리들 내부를 보면 대다수 EVAL 명령을 통해 Lua script를 실행하는 방법으로 구현되어 있는 듯
- EVAL 명령으로 MULTI 관련된 기능들은 왠만한건 구현할 수 있는데, WATCH 명령을 통한 낙관적 락 같은 기능은 구현이 힘들듯..
반응형
'DBMS > Redis' 카테고리의 다른 글
[Redis] Redis 운영 관리 정리 (0) | 2021.10.26 |
---|---|
[Redis] Redis 세미나 정리 (0) | 2021.09.15 |