Skip to content
V3.0 // STABLE
LOAD 12%
LAT 24MS
SLA 99.99%

RedisとGoによる分散ロック

1 min read
3 views
redisdistributed systemsconcurrencygolang

分散システムでは、サービスの複数のインスタンスが共有リソースに同時にアクセスしようとする可能性があります。通常のミューテックスは、単一のプロセス内でのみ機能します。分散環境での安全性を確保するには、分散ロックが必要です。

競合状態の問題

10人のユーザーのみが期間限定のクーポンを請求できるプロモーションイベントを想像してください。2つのサーバーインスタンスが同じミリ秒でカウントをチェックすると、両方とも count=9 と認識し、2つのクーポンを発行してしまい、過剰な履行につながる可能性があります。

Redisを使用した実装 (SETNX)

Redisでロックを実装する最も一般的な方法は、SET コマンドを NX (存在しない場合に設定) および PX (ミリ秒単位の有効期限) と共に使用することです。

// ロックの取得
lockKey := "lock:coupon_claim_123"
requestID := uuid.New().String()
ttl := 5 * time.Second
 
ok, err := rdb.Set(ctx, lockKey, requestID, ttl).Nx().Result()
if err != nil || !ok {
    return fmt.Errorf("could not acquire lock")
}
 
// Luaを使用した解放の保証 (原子性)
defer func() {
    var luaScript = `
        if redis.call("get", KEYS[1]) == ARGV[1] then
            return redis.call("del", KEYS[1])
        else
            return 0
        end
    `
    rdb.Eval(ctx, luaScript, []string{lockKey}, requestID)
}()

ハイレベルなロックフロー

Live architecture
Analyzing Schema...

Arch Note

Interactive logic enabled. Click components in expanded view for technical service definitions.

Layer.0 / Distributed_System_Viz

回避すべき落とし穴

  1. クロックドリフト: 分散システムは、完全に同期されたクロックを持っていません。TTLが操作に十分な長さであることを確認してください。
  2. ロックタイムアウト: プロセスがTTLよりも長くかかると、プロセスがまだ実行中であってもロックは自動的に解放されます。"ウォッチドッグ" パターンを使用して、ロックを定期的に更新してください。
  3. Redlockアルゴリズム: ミッションクリティカルなロックの場合は、ノードが故障した場合でも安全性を確保するために、複数の独立したRedisノードからロックを取得する必要があるRedlockアルゴリズムを使用してください。

分散ロックを正しく使用することは、最新のバックエンドアーキテクチャでデータの整合性を維持するために不可欠です。