ペン名:ハイビスケット
ブログパーク:https://www.cnblogs.com/haibiscuit/
Gitアドレス:https://github.com/haibiscuit?tab=repositories (ようこそスター)
プロジェクトのアドレス:https://github.com/haibiscuit/StudyBook
著者の労働成果を尊重し、許可なく転載しないでください
序文:
インタビューを受けたばかりで、もちろん電話を切ったので、この記事を書いて自分を抑え、苦しんでいる心を滑らかにしました。
テキスト:
1つ:分散ロックが直面する問題
1.1ロックは一意である必要があります
1.2デッドロックを防ぐために、ロックにはタイムアウト期間が必要です
1.3ロックの作成とロックタイムアウトの設定はアトミックである必要があります
1.4ロックのタイムアウト
1.5再入可能ロックの問題
1.6クラスター内の分散ロックの問題
1.7 redis分散ロックについて考慮すべきその他の問題
2:分散ロックが直面する問題の説明と解決策
2.1ロックは一意である必要があります
問題の説明:
まず、分散ロックによって解決される問題は、同じリソースが分散環境の複数のプロセスによってアクセスおよび操作されることです。同じリソースであるため、データのセキュリティ問題を確実に考慮する必要があります。実際、単一のプロセスでのロックとロック解除の原則は、同様に、単一のプロセスでは、複数のスレッドが同じ変数のアクセスと変更を考慮する必要があります。同じ変数が複数のスレッドによって同時にアクセスされないようにするために、変数を順番に変更するには、変数にアクセスするときにロックする必要があります。ロックは、ヘビー級のロックまたはcasに基づく楽観的ロックにすることができます。
解決策:
クライアントだけが使用できるredisコマンドsetnx(存在しない場合は設定)を使用します.redisインスタンスに一意のキーがある場合、キーに値を設定すると拒否されます。
2.2デッドロックを防ぐために、ロックにはタイムアウト期間が必要です
問題の説明:
Redisは、ロックを解除するためにクライアントの操作を必要とします。この時点でクライアントが突然ハングした場合、ロックを解除する操作はありません。また、他のクライアントが再度ロックしたいが、問題を追加できないことを意味します。
解決策:
したがって、クライアントがハングする、またはクライアントがロックを正常に解放できないという問題を回避するには、ロックを追加するときにタイムアウトをロックに追加する必要があります。
つまり、ロックの追加とタイムアウトの追加の操作は次のとおりです。
> setnx lockkey true#ロック操作
OK
>ロックキーの期限切れ5#ロックにタイムアウトを追加
...重要なことをする...
> del lockkey#ロックを解除
(整数)1
2.3ロックの作成とロックタイムアウトの設定はアトミックである必要があります
問題の説明:
2.3ロックとタイムアウト時間の設定により、setnxとexpireが操作を完了するには2つのコマンドを必要とすることがわかります。つまり、2つのRTT操作が必要です。setnxとexpireの2つのコマンドの間にクライアントが突然ハングすると、ロックを解除できず、デッドロックの問題が発生した場合。
解決策:
set extendedコマンドを使用します
次のように:
>ロックキーをtrue ex 5 nxに設定#ロック、有効期限5秒
OK
...重要なことをする...
>ロックキーを削除
上記のset lockkey true ex 5 nxコマンドは、setnxの2つの操作を完了し、一度に期限切れにすることができます。これは、原子性の問題を解決するためのものです。
2.4ロックのタイムアウト
問題の説明:
上記のロックにタイムアウトが追加されますが、クライアントは必ずしもタイムアウト内にスケジュールされたタスクを完了することができないため、現在のクライアントがタスクを完了しなくても、他のクライアントはこの時点でロックを正常に設定します。同じリソースが、複数のクライアントが同時に動作するという問題に直面します。
解決策:
ロックが正常に設定された後、クライアントはスケジュールされたタスクを実行できます。luaスクリプトを使用してロックを削除し、ロックをリセットして、ロックがタイムアウトする前にタイムアウトします。
もちろん、なぜここで操作を完了するためにluaを使用するのですか?実際、上記のアトミック問題のように、ロックの削除とロックのリセットおよびロックタイムアウトの間で、ロックリソースを占有している他のクライアントとluaに直面する可能性があります。アトミック機能である、ロックの削除と再ロックの2つの操作は、完了しているか完了していないかのどちらかです。
2.5再入可能ロックの問題
問題の説明:
上記で説明しました。ロックが一意であることを確認するために、setnx.Laterを使用する必要があります。タイムアウトで設定するには、setコマンドを選択しました。
必要なロック中に、ロックを所有しているクライアントが再度ロックを取得しようとしています。これはロックの再入です。もちろん、ここでの問題は2.5の問題と似ています。
解決策:
同様に、luaスクリプトを使用して、ロックを削除および再設定することを選択できます。
2.6クラスター内の分散ロックの問題
問題の説明:
この問題は、Redisクラスターソリューションで発生します。実際、Redisの高可用性とアクセスパフォーマンスを確保するために、Redisのマスターノードとスレーブノードがセットアップされます。マスターノードは書き込み操作を担当し、スレーブノードは読み取り操作を担当します。つまり、すべてのロックをメインのredisサーバーインスタンスに書き込む必要があります。メインのredisサーバーがダウンすると、リソースが解放されます(永続性がない場合、永続性が追加されると、この問題はさらに複雑になります)。現時点では、redisマスターノードのデータはスレーブサーバーにコピーされません。このとき、他のクライアントがロックを取得する機会を得て、以前にロックを持っていたクライアントがリソース上でまだ動作している可能性があります。このとき、複数のクライアントは同じになります。リソースのアクセスと操作の問題。
解決策:
この問題は、1つまたは2つの文では明確でないため、書面で個別に説明する準備ができています。
2.7 redis分散ロックについて考慮すべきその他の問題
上記では、redisがビジネスロジックで発生する問題について説明しました。解決策は、前述の解決策に限定される場合があります。
もちろん、プログラマー自身のシーンに応じて選択する必要があるロジックがあります。
たとえば、次のとおりです。
(1)キーを設定する場合、キーリソースの取得先
その中には、マルチクライアントリソースコンセンサスの問題が含まれます。簡単な分析は、複数のクライアントが同じリソースをロックしているときに、キーが複数のクライアントと一致している必要があると判断する方法です。それ以外の場合は、どうすれば保証できますか複数のクライアントにおけるキーの一意性。
(2)ロックが解放されると、ロックリソースを所有するクライアントのみが解放できます。
もちろん、この問題はロックおよびロック解除ロジックの誤った書き込みが原因です。上記の分析によれば、redis分散ロックに関する上記の問題をすべて解決する限り、クライアントロックの解放の問題は通常発生しません。
ただし、これは詳細事項でもあり、ビジネスロジックで考慮する必要があります。
3:まとめ
クラスター内のredis分散ロックの問題については、別の記事で説明します
私の仕事がすぐに安定することを望みます