Discourse는 동기화 수단으로 Redis 잠금을 광범위하게 사용합니다. 아래에 표시된 Discourse의 Redis 잠금 구현은 Redis 명령어 사용량을 줄여 Redis의 실행을 위한 왕복 시간과 비용을 절감하도록 개선할 수 있습니다.
개선 방법
lock과 unlock 모두 Redis 트랜잭션을 사용합니다. lock 프로세스는 아래 코드로 단순화할 수 있습니다.
WATCH key
GET key # 키가 만료되었는지 확인
MULTI
SET key
EXPIRE key, expire_time + 1
Redis 트랜잭션을 사용하는 이유(추측)는 키를 실제로 설정하기 전에 키가 만료되었는지 확인하기 위해서인 것 같습니다.
그러나 Redis에서 제공하는 SETEX 명령어를 사용하여 만료 시간을 지정하여 키를 설정하는 것이 더 적합하다고 생각합니다. 실제로 Redis SETEX 문서에서는 SET & EXPIRE를 SETEX로 대체하는 예시로 이를 사용하고 있습니다.
이를 대체해야 하는 이유는 다음과 같습니다.
- 값을 만료 시간으로 설정하고 키를 설정하기 전에 이를 확인하는 것은 불필요합니다. TTL 메커니즘만으로도 키가 올바르게 만료되도록 보장할 수 있기 때문입니다.
- 만료 시간을 값으로 사용하는 것을 결정하더라도 트랜잭션이 필요하지 않습니다. 위에서 언급한 코드 2번째 줄의
GET과MULTI & EXEC사이의 원자성을 제공한다고 해서 아무것도 제공하지 않기 때문입니다. 이는 잠금이 획득되지 않으면 재시도하기 때문입니다.
역사적 참고 사항
더 많은 정보를 얻기 위해 git 커밋 히스토리를 조사해 보았습니다. Redis 잠금이 도입되었을 당시에는 Redis에서 제공하는 TTL을 사용하지 않은 것으로 보입니다. TTL 기능은 훨씬 이후에 도입되었습니다.
따라서 한 단계 더 나아가 Redis 트랜잭션을 완전히 제거할 수 있을 것으로 추정됩니다.