redis の一般的なロック コマンドは、INCR、SETNX、SET
この種のロックのロックの考え方は次のとおりです。
key が存在しない場合、まず key の値が 0 に初期化され、次に INCR 操作が実行されて 1 ずつ増加します。
その後、他のユーザーが INCR 操作を実行して 1 を追加したときに、返された値が 1 より大きい場合、そのキーは使用のためにロックされていることを意味します。
1. クライアント A は、ロックが取得されたことを示すキー値 1 の取得をサーバーに要求します。
2. クライアント B もサーバーにキー値 2 の取得を要求します。
3. クライアント A はコードの実行を完了し、ロックを削除します
4. クライアント B は一定時間待機し、次のキー値を取得しますリクエストを行うときは 1 で、ロックが正常に取得されたことを示します
5. クライアント B がコードを実行し、ロックを削除します
$redis->incr($key); $redis->expire($key, $ttl); //设置生成时间为1秒
特定のコマンド:
127.0.0.1:6379>INCR keyName
この種のロックの背後にある考え方は、キーが存在しない場合、キーを値に設定するというものです。キーが存在する場合、SETNX は何もアクションを実行しません。
SETNX は、SET if Not eXists の略称です。
1. クライアント A はサーバーにキー値の設定を要求します。設定が成功した場合は、ロックが成功したことを意味します。
2. クライアント B もサーバーに次のことを要求します。キー値を設定します。 if リターンが失敗した場合は、ロックが失敗したことを意味します
3. クライアント A はコードの実行を完了し、ロックを削除します
4. クライアント B はキー値の設定を要求します一定時間待機すると、設定が成功しました。
5. クライアント B がコードを実行し、ロックを削除します
$redis->setNX($key, $value); $redis->expire($key, $ttl);
特定のコマンド:
redis> SETNX keyName value (integer) 1
設定は成功しました1 が返され、設定は失敗し、ロックが返されます 0
上記の 2 つのメソッドには問題があり、キーの有効期限を設定する必要があることがわかります。
では、なぜキーの有効期限を設定する必要があるのでしょうか?
リクエストの実行が何らかの理由で予期せず終了し、ロックが作成されても削除されなかった場合、ロックは常に存在するため、今後キャッシュが更新されることはありません。
したがって、事故を防ぐためにロックに有効期限を追加する必要があります。
ただし、Expire を使用して設定することはアトミックな操作ではありません。
トランザクションによるアトミック性も確保できますが、まだいくつか問題があるため、公式は別の問題を引用しています SET コマンド自体を使用することで、バージョン 2.6.12 から有効期限を設定する機能が追加されました。
1. クライアント A は、サーバーにキー値の設定を要求します。設定が成功すると、ロックは成功します。
2. クライアント B も、サーバーにキー値の設定を要求します。戻りが失敗した場合は、ロックが失敗したことを意味します。
3. クライアント A はコードの実行を完了し、ロックを削除します。
4. クライアント B は一定時間待機します。
5. クライアント B がコードを実行し、ロックを削除します
$redis->set($key, $value, array('nx', 'ex' => $ttl)); //ex表示秒
具体的な使用法:
redis>set key value NX EX max-lock-time 实现加锁
コマンドの説明:
key
: キーはロックの識別子としての redis のキー値であり、値はここでクライアントの識別子として使用されます。キーと値の一致により、ロックを削除する権限が得られます [セキュリティの確保]
max-lock-time
: max-lock-time までの有効期限を設定します。デッドロックが発生しないことを確認します [デッドロックの回避]
NX
: キーが存在しない場合、キーが存在しない場合にのみ操作が実行されます;
EX
: キーの有効期限を秒に設定します。具体的な時間は 5 番目のパラメータ
## によって決まります。ロック コード:
Jedis jedis = new Jedis("127.0.0.1", 6379); private static final String SUCCESS = "OK"; /** * 加锁操作 * @param key 锁标识 * @param value 客户端标识 * @param timeOut 过期时间 */ public Boolean lock(String key,String value,Long timeOut){ String var1 = jedis.set(key,value,"NX","EX",timeOut); if(LOCK_SUCCESS.equals(var1)){ return true; } return false; }
アンロック コード:
Jedis jedis = new Jedis("127.0.0.1", 6379); private static final Long UNLOCK_SUCCESS = 1L; /** * 解锁操作 * @param key 锁标识 * @param value 客户端标识 * @return */ public static Boolean unLock(String key,String value){ String luaScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end"; Object var2 = jedis.eval(luaScript,Collections.singletonList(key), Collections.singletonList(value)); if (UNLOCK_SUCCESS == var2) { return true; } return false; }luaScript この文字列は lua スクリプトです。つまり、キーに従って取得された値が渡された値と同じ場合は、del を実行し、それ以外の場合は 0 を返します [セキュリティの保証]jedis .eval(String,list,list); このコマンドは、lua スクリプトを実行するためのものです。 2 番目のパラメータ、ARGV のセットが 3 番目のパラメータです [確実にロックを解除するためのアトミック操作] 上記は Redis を使用して分散ロックを正しく実装する方法ですが、ロックの有効期限が切れるという小さな欠陥があります。時間は適切な値に設定する必要がありますが、実際にはビジネス シナリオに基づいて検討する必要があります。
以上がRedisをロックするにはどのような方法がありますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。