더 효율적인 Redis 잠금

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로 대체하는 예시로 이를 사용하고 있습니다.

이를 대체해야 하는 이유는 다음과 같습니다.

  1. 값을 만료 시간으로 설정하고 키를 설정하기 전에 이를 확인하는 것은 불필요합니다. TTL 메커니즘만으로도 키가 올바르게 만료되도록 보장할 수 있기 때문입니다.
  2. 만료 시간을 값으로 사용하는 것을 결정하더라도 트랜잭션이 필요하지 않습니다. 위에서 언급한 코드 2번째 줄의 GET과 MULTI & EXEC 사이의 원자성을 제공한다고 해서 아무것도 제공하지 않기 때문입니다. 이는 잠금이 획득되지 않으면 재시도하기 때문입니다.

역사적 참고 사항

더 많은 정보를 얻기 위해 git 커밋 히스토리를 조사해 보았습니다. Redis 잠금이 도입되었을 당시에는 Redis에서 제공하는 TTL을 사용하지 않은 것으로 보입니다. TTL 기능은 훨씬 이후에 도입되었습니다.

따라서 한 단계 더 나아가 Redis 트랜잭션을 완전히 제거할 수 있을 것으로 추정됩니다.

Develop with Redis | Docs 참고

거래(트랜잭션)를 모두 폐기하고, px와 nx 옵션을 사용하여 set을 수행하는 것이 더 나을 것 같습니다.