Redis チュートリアルの次のコラムでは、ロック メカニズムを実装するためのRedisの SETNX の正しい使用方法を紹介します。困っている友達に役立ちます!
![Redis の SETNX を正しく使用してロック メカニズムを実装する方法を説明します](https://img.php.cn/upload/article/000/000/020/5f9931479395c309.jpg)
setNX は set if notowned の略で、存在しない場合にのみ設定され、設定が成功した場合は 1 を返し、設定が成功した場合は 0 を返します。設定に失敗します。ロック効果を得るために使用できますが、多くの人が使用中に考慮していないいくつかの問題を抱えています。
たとえば、データベースにクエリを実行するための特定のインターフェイスは、リクエストの数が比較的多いためキャッシュを追加し、キャッシュの有効期限が切れた後にキャッシュを更新するように設定します。同時実行の量が比較的多く、キャッシュの有効期限が切れると、多数の同時リクエストがデータベースに直接クエリを実行し、雪崩を引き起こします。ロック機構を使用してキャッシュを更新する要求を 1 つだけ制御すれば、雪崩の問題を回避できます。以下は、多くの人が無意識に考えているロック方法です。
$rs = $redis->setNX($key, $value); if ($rs) { //处理更新缓存逻辑 // ...... //删除锁 $redis->del($key); }
ログイン後にコピー
setNX でロックを取得し、成功したらキャッシュを更新し、ロックを削除します。実際、ここには重大な問題があります。何らかの理由でキャッシュが予期せず終了した場合、ロックは削除されず常に存在するため、キャッシュは更新されません。この問題を解決するために、次のようにロックの有効期限を設定することを考える人もいるかもしれません。
$redis->multi(); $redis->setNX($key, $value); $redis->expire($key, $ttl); $redis->exec();
ログイン後にコピー
setNX には有効期限を設定する機能がないため、Expire を使用して設定する必要があります。 、setNX が成功しても期限切れに失敗することを防ぐために、要求された Atomicity を確実にするには Multi/Exec を使用する必要があります。これにはまだ問題があります: 複数のリクエストが到着した場合、成功できるのは 1 つのリクエストの setNX のみですが、どのリクエストの Expire も成功する可能性があります。これは、ロックが取得できなくても、有効期限が更新される可能性があり、ロックが残ることを意味します。これは効果的ですが、それでも上記の問題は解決されません。 setNX では需要に応えられないのは明らかです。Redis 2.6.12 からは、SET が SETEX の機能をカバーします。SET 自体に有効期限を設定する機能も含まれているため、SET を使用することで上記の問題を解決できます。
$rs = $redis->set($key, $value, array('nx', 'ex' => $ttl)); if ($rs) { //处理更新缓存逻辑 // ...... //删除锁 $redis->del($key); }
ログイン後にコピー
このステップは実際には問題があり、リクエストがキャッシュの更新にロックの有効期間よりも長くかかり、キャッシュの更新プロセス中にロックが無効になった場合、別のリクエストがロックを取得しますが、前のリクエストはキャッシュを取得するときにロックを取得します。更新が完了した後、ロックを直接削除すると、他のリクエストによって作成されたロックを誤って削除してしまう可能性があります。したがって、この問題を回避するには、ロックを作成するときにランダムな値を導入し、ロックを削除するときにそれを判断することができます
$rs = $redis->set($key, $random, array('nx', 'ex' => $ttl)); if ($rs) { //处理更新缓存逻辑 // ...... //先判断随机数,是同一个则删除锁 if ($redis->get($key) == $random) { $redis->del($key); } }
ログイン後にコピー
以上がRedis の SETNX を正しく使用してロック メカニズムを実装する方法を説明しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。