この記事では、主に PHP redis によって実装される悲観的ロック メカニズムを紹介し、redis ロック メカニズム、楽観的ロック、悲観的ロックなどの概念を簡単に紹介し、PHP redis によって実装される悲観的ロックの関連操作テクニックを例の形で分析します。必要な友達 次を参照してください。
この記事の例では、PHP redis によって実装された悲観的ロックについて説明します。参考までに皆さんと共有してください。詳細は次のとおりです。
ロックの仕組み
一般的に使用されるロックは、楽観的ロックと楽観的ロックに分けられます。悲観的なロックについては、この記事の背景知識としてこれら 2 つのタイプのロックについて簡単に説明します。このタイプの知識をすでに持っている学生は、この部分をスキップしてください。
Optimistic Lock
まず、百度百科事典の説明を見てみましょう。ほとんどの説明はデータのバージョン (バージョン) に基づいています。 )記録機構。データバージョンとは何ですか?つまり、データベース テーブルに基づくバージョン ソリューションでは、通常、データベース テーブルに「バージョン」フィールドを追加することでバージョン識別子を追加します。データを読み出す際にはこのバージョン番号も読み出され、その後更新されるとこのバージョン番号が1つインクリメントされる。このとき、入稿データのバージョン情報とデータベーステーブルの該当レコードの現在のバージョン情報とを比較し、入稿データのバージョン番号がデータベーステーブルの現在のバージョン番号より大きい場合には、更新されていない場合は、期限切れのデータとみなされます。
実際、率直に言うと、ジムにはトレッドミルが 1 台しかなく、ジムの入り口には番号を付けるマシンがあるようなものです。ジムに入る人は全員、番号を付ける必要があります。ランニングしている場合は、トレッドミルに人がいる場合は、ウォームアップして水を飲み、トレッドミルに現在表示されている番号(最後に使用した人の番号)を確認してください。トレッドミル) が持っているものより小さい場合は、使用できます。そうでない場合は、その番号を通過するか、再配置する必要があることは誰もが知っていますが、ジャンプすることはできません。システムでも同様で、通常はエラーが返されます。
悲観的ロック
同様に、百度百科事典の説明を見てみましょう。これには、強力な独占的および排他的な特徴があります。これは、外部 (システムの他の現在のトランザクションや外部システムからのトランザクション処理を含む) によって変更されるデータに対する保守的な態度を指します。そのため、データはデータ処理プロセス全体を通じてロックされた状態に保たれます。悲観的ロックの実装は、多くの場合、データベースによって提供されるロック メカニズムに依存します (データ アクセスの排他性を真に保証できるのは、データベース層によって提供されるロック メカニズムだけです。それ以外の場合、ロック メカニズムがこのシステムに実装されている場合でも、外部システムがデータを変更しないことを保証します)。
そして、同じ一般的な説明では、やはりジムです。今回は、入り口に並ぶ必要はなく、その代わりに鍵があり、入りたい人はその鍵を受け取らなければなりません。彼が出てきて鍵を壁に掛け直すまで、あなたはまだ走ることができ、次の鍵を求めて戦うことができ、それを手に入れて初めて再び入ることができます。少し非人道的に聞こえるため、ペシミスティック ロックは強整合性のシナリオに適していますが、効率は比較的低く、特に読み取りの同時実行性が低くなります。オプティミスティック ロックは、読み取りが多く書き込みが少なく、同時実行性の競合が少ないシナリオに適しています。
背景
まず、なぜ悲観的なのかを誰もが理解できるように、この記事の開発背景について話しましょう。ロックの使用と記事の内容 ロックの詳細な設計。
タスク分散システム: タスクプール(mysql)内に多数のタスク(記事)があり、ユーザーが編集を支援する必要があるシステムの基本要件は以下の通りです(簡易版)。 ):
1. カテゴリ内のタスクに興味のあるユーザーをユーザー エディターにプッシュします。ユーザーがタスクを編集して送信すると、次のタスクが自動的にプッシュされます。 . ユーザーに割り当てられるタスクは一度に 1 つだけです。
4. ユーザーが一定期間以上タスクを占有している場合、そのタスクは自動的に解放され、そのタスクに追加されます。プールと再循環;
5、...
目標 目標は 2 つあります:
1。タスクは同時に 1 人のユーザーのみが保持できます。
2. デッドタスクを回避します。つまり、ユーザーが長時間保持し、解放できないタスクを回避します。
アイデアシステムの同時実行性が高く、書き込み操作が頻繁に行われるため、各タスクを制御するために悲観的ロックを選択すると、1 つのタスクしか受信できなくなります。同時にユーザーでもあります。主なアイデアは次のとおりです。
1. タスク プールから割り当て可能なタスクをいくつか見つけます。
#2. プッシュ タスクの候補としてタスクを選択します。候補を一致させます。4. ロックが成功した場合は、タスクをユーザーにプッシュし、ロックが失敗した場合は、タスクのステータスを変更します。を受信したら、プッシュが成功するまで 2 ~ 5 を繰り返します。 ############成し遂げる#########
ここではロックの実装メカニズムのみを紹介し、残りのビジネス ロジックは省略します。ロック プロセスは逆アセンブルされるべきではなく (アトミック操作と呼ばれることが多い)、redis の setnx 操作がロック方法として選択されます。
コードの簡略版は次のとおりです。
function lock($strMutex, $intTimeout) { $objRedis = new Redis(); //使用setnx原子型操作加锁 $intRet = $objRedis->setnx($strMutex, 1); if ($intRet) { //设置过期时间,防止死任务的出现 $objRedis->expire($strMutex, $intTimeout); return true; } return false; }
このコードには問題があります。つまり、setnx は成功しますが、期限切れは失敗します。これはデッドミッション状況が存在する可能性があります。この問題を解決する一般的な方法は、次のように setnx の代わりに incr メソッドを使用することです。
function lock($strMutex, $intTimeout, $intMaxTimes = 0) { $objRedis = new Redis(); //使用incr原子型操作加锁 $intRet = $objRedis->incr($strMutex); if ($intRet === 1) { //设置过期时间,防止死任务的出现 $objRedis->expire($strMutex, $intTimeout); return true; } if ($intMaxTimes > 0 && $intRet >= $intMaxTimes && $objRedis->ttl($strMutex) === -1) { //当设置了最大加锁次数时,如果尝试加锁次数大于最大加锁次数并且无过期时间则强制解锁 $objRedis->del($strMutex); } return false; }
このコードは $intMaxTimes を渡します。期限切れに失敗した場合でも強制的にロックを解除し、システム内にデッドタスクが存在しないことを保証することができます。
もっと良い方法はありますか?
実際、redis の set 操作は setnx と互換性があり、有効期限の設定をサポートしています。
function lock($strMutex, $intTimeout) { $objRedis = new Redis(); //使用setnx操作加锁,同时设置过期时间 $strRet = $objRedis->set($strMutex, 1, 'ex', $intTimeout, 'nx'); if ($strRet === 'OK') { return true; } return false; }
この方法が現時点でベストだと思っているのですが、なぜこの方法が直接紹介されず、incrメソッドが先に紹介されるのでしょうか?実際、注意深い学生であれば、上記の側面に「一般」という 2 つの太字の単語があることがわかります。なぜこれを言うかというと、setメソッドはredis2.6.12バージョンからの複数のパラメータのみをサポートしているためです。
レベルは限られています、修正は歓迎です~
上記はこの記事の全内容です。その他の関連コンテンツについては、ご注目ください。 PHP中国語ウェブサイトです!
関連する推奨事項:
PHP を使用してユーザー クライアントの実際の IP を取得する方法
以上がPHP と Redis によって実装された悲観的ロック機構の分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。