ホームページ  >  記事  >  データベース  >  Redisをロックするにはどのような方法がありますか?

Redisをロックするにはどのような方法がありますか?

WBOY
WBOY転載
2023-05-27 12:43:061374ブラウズ

redis の一般的なロック コマンドは、INCR、SETNX、SET

1、INCR

この種のロックのロックの考え方は次のとおりです。

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

2. SETNX

この種のロックの背後にある考え方は、キーが存在しない場合、キーを値に設定するというものです。キーが存在する場合、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

3. SET

上記の 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 サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。