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
Compiled: v2.0-ProductionAnalyzing Schema...
Arch Note
Interactive logic enabled. Click components in expanded view for technical service definitions.
Layer.0 / Distributed_System_Viz
回避すべき落とし穴
- クロックドリフト: 分散システムは、完全に同期されたクロックを持っていません。TTLが操作に十分な長さであることを確認してください。
- ロックタイムアウト: プロセスがTTLよりも長くかかると、プロセスがまだ実行中であってもロックは自動的に解放されます。"ウォッチドッグ" パターンを使用して、ロックを定期的に更新してください。
- Redlockアルゴリズム: ミッションクリティカルなロックの場合は、ノードが故障した場合でも安全性を確保するために、複数の独立したRedisノードからロックを取得する必要があるRedlockアルゴリズムを使用してください。
分散ロックを正しく使用することは、最新のバックエンドアーキテクチャでデータの整合性を維持するために不可欠です。