より効率的なRedisロック

Discourse は同期手段として Redis ロックを広く利用しています。以下に示す Discourse の Redis ロックの実装は、使用する Redis コマンド数を減らすことで改善でき、ラウンドトリップ時間の短縮や Redis 実行コストの削減が期待できます。

改善方法

lockunlock の両方で Redis トランザクション が使用されていますが、lock プロセスは以下のコードのように簡略化できます。

WATCH key
GET key # キーの有効期限切れ判定
MULTI
SET key
EXPIRE key, expire_time + 1

Redis トランザクションを使用する理由(私の推測では)は、実際にキーを設定する前にそのキーの有効期限が切れていないかを確認するためだと思われます。

しかし、Redis が提供する SETEX コマンドを使用すれば、有効期限付きでキーを設定できるため、この手順は不要だと考えられます。実際、Redis SETEX ドキュメント でも、SETEXPIRESETEX で置き換える例が示されています。

以下に、置き換えるべき理由を挙げます。

  1. キーを設定する前に値を有効期限として設定し、それを確認する必要はありません。TTL メカニズムだけで、キーが正しく期限切れになることを保証できます。
  2. 仮に有効期限を値として使用すると決めても、トランザクションは不要です。上記コードの 2 行目にある GETMULTI & EXEC の間に原子性を提供しても意味がないからです。なぜなら、ロックが取得できなければリトライされるためです。

歴史的な注記

より詳しい情報を得るために、Git のコミット履歴を調査しました。Redis ロックが 導入 された当初は、Redis が提供する TTL は使用されていなかったようです。TTL 機能はその後 はるかに遅れて 追加されました。

したがって、一歩進んで Redis トランザクションを完全に削除することも可能だと考えられます。

おそらく、トランザクション全体を破棄し、px および nx オプションを使用して set を実行すればよいでしょう。