著者について Leng Zhenglei は2018 年 2 月に Qunar.com DBA チームに加わりました。彼は主に、航空券業務の MySQL および Redis データベースの運用と保守管理、およびデータベース自動化運用および保守プラットフォームの一部の機能の開発を担当しています。彼はデータベース技術に強い関心を持ち、MySQL と Redis の運用・保守管理、パフォーマンス最適化において長年の経験を持っています。 1. 背景電子商取引のウェブサイトで買い物をするとき、電子商取引アプリによく見られるフラッシュセールや限定版クーポン購入、Qunar.com の列車チケット取得システムなど、同時実行性の高いシナリオに遭遇することがよくあります。これらのシナリオには、訪問者数の急増という共通の特徴があります。システム設計時に電流制限、非同期、キューイングなどによって最適化されますが、全体的な同時実行性は通常よりも数倍高くなります。同時実行の問題を回避し、在庫の過剰販売を防ぎ、ユーザーに快適なショッピング体験を提供するために、これらのシステムではロック メカニズムが使用されます。 単一プロセスの同時実行シナリオでは、同時実行の問題を回避するために、プログラミング言語と対応するクラス ライブラリ (Java の synchronized 構文や ReentrantLock クラスなど) によって提供されるロックを使用できます。 分散シナリオで異なるクライアントのスレッドによるコードとリソースへの同期アクセスを実現し、複数のスレッドで共有データを処理するセキュリティを確保するには、分散ロック テクノロジを使用する必要があります。 では、分散ロックとは何でしょうか?分散ロックは、分散システム間または異なるシステム間の共有リソースへのアクセスを制御するロック実装です。リソースが異なるシステム間または同じシステムの異なるホスト間で共有される場合、相互の干渉を防ぎ一貫性を確保するために、相互排他制御が必要になることがよくあります。 比較的安全な分散ロックには、通常、次の特性が必要です。
分散ロックを実装するには、リソースをロックするだけでなく、デッドロックやロックの失敗などの問題を回避するためにいくつかの追加機能も満たす必要があることがわかります。 2. 分散ロックの実装分散ロックを実装する方法は多数あります。最も一般的なものは次のとおりです。
Memcached の add コマンドを使用します。このコマンドはアトミック操作です。キーが存在しない場合にのみ追加が成功します。これは、スレッドがロックを取得したことを意味します。
Zookeeper の連続した一時ノードを使用して、分散ロックと待機キューを実装します。 ZooKeeper は分散アプリケーション向けに特別に設計されたフレームワークとして、一時的な znode の自動削除など、非常に優れた機能を提供します。 ZooKeeper は、分散ロックをローカル ロックのようにクライアントで使用できるようにする監視メカニズムも提供します。ロックが失敗した場合、ロックが取得されるまでブロックされます。
Google が実装した粗粒度の分散ロック サービスは、ZooKeeper と多少似ていますが、違いも多くあります。 Chubby は、シーケンサー メカニズムを通じて、要求の遅延によって発生するロック障害の問題を解決します。
単一の Redis マシンに基づいて実装された分散ロックは、やはりアトミック操作である Redis SETNX コマンドを使用する Memcached の実装に似ています。キーが存在しない場合にのみ正常に設定できます。 Redis マルチマシン実装に基づく分散ロック Redlock は、Redis 分散ロックの実装を標準化するために Redis の作者 antirez によって提案された、より安全で効果的な実装メカニズムです。 この記事では主に、Redis に基づく分散ロックのいくつかの実装方法と既存の問題について説明し、分析します。 3. Redis分散ロックRedis を分散ロックとして使用する場合、重要な目標は、プロセスが Redis 内の唯一の「トイレ」を占有することです。他のプロセスがトイレを占有しようとすると、すでに誰かがそこにしゃがんでいることがわかり、諦めるか、待ってからもう一度試す必要があります。 現在、Redis に基づく分散ロックには主に 2 つの種類があります。 1 つは単一のマシンに基づいており、もう 1 つは複数の Redis マシンに基づいています。実装方法に関係なく、分散ロックの 3 つのコア要素、つまりロック、ロック解除、ロック タイムアウトを実装する必要があります。 1. Redisスタンドアロンベースの分散ロック 1) SETNX命令を使用する ロックする最も簡単な方法は、Redis SETNX 命令を直接使用することです。この命令は、キーが存在しない場合にのみ、キーの値を value に設定します。キーがすでに存在する場合、SETNX コマンドは何もアクションを実行しません。キーはロックの一意の識別子であり、ビジネス ニーズに応じてロックされるリソースに応じて名前を付けることができます。 たとえば、特定のショッピングモールのフラッシュセールイベントで商品をロックする場合、キーを lock_resource_id に設定し、値を任意の値に設定できます。リソースが使用された後は、DEL を使用してキーを削除し、ロックを解除します。全体のプロセスは次のとおりです。 明らかに、ロックを取得するこの方法は非常に簡単ですが、前述の分散ロックの 3 つのコア要素の 1 つであるロック タイムアウトの問題という問題もあります。つまり、ビジネスロジック処理中にロックを取得するプロセスで例外が発生すると、DEL 命令が実行されず、ロックを解除できず、リソースが永久にロックされたままになる可能性があります。 そのため、SETNX を使用してロックを取得した後は、キーに有効期限を設定し、明示的に解放しなくても、一定期間後に自動的に解放されるようにして、リソースが長時間独占されるのを防ぐ必要があります。 SETNX は有効期限の設定をサポートしていないため、追加の EXPIRE 命令が必要です。全体のプロセスは次のとおりです。 このように実装された分散ロックには依然として重大な問題が残っています。 SETNX と EXPIRE の 2 つの操作は非アトミックであるため、SETNX と EXPIRE の実行の間に例外が発生すると、SETNX は正常に実行されますが、EXPIRE は実行されず、ロックが「不滅」になります。この場合、前述のロックタイムアウトの問題が発生し、他のプロセスが正常にロックを取得できなくなります。 2) SET拡張コマンドを使用する SETNX および EXPIRE 操作の非アトミック問題を解決するために、Redis SET 命令の拡張パラメータを使用して、SETNX および EXPIRE 操作をアトミックにすることができます。全体のプロセスは次のとおりです。 このSET命令では、
ただし、このアプローチでは、分散ロックのタイムアウトの問題を完全に解決することはできません。
上記の状況を回避するには、実行時間が長すぎるシナリオでは Redis 分散ロックを使用しないことをお勧めします。同時に、より安全な方法は、DEL を実行してロックを解除する前にロックを判断し、現在のロック保持者が自分自身であるかどうかを確認することです。 具体的な実装としては、ロック時に値を一意の乱数(またはスレッド ID)に設定し、ロックを解除する際には乱数が一貫しているかどうかをまず判断し、その後、ロックの有効期限が切れてサーバーによって自動的に解除されない限り、他のスレッドによって保持されているロックが誤って解除されないように解除操作を実行します。全体のプロセスは次のとおりです。 ただし、値の決定とキーの削除は 2 つの独立した操作であり、アトミックではないため、Lua スクリプトを使用して処理する必要があります。これは、Lua スクリプトを使用すると、複数の連続した命令のアトミック実行を保証できるためです。 Redis 単一ノードに基づく分散ロックは基本的に完成していますが、他のスレッドが現在のスレッド実行タイムアウトロックを事前に解放して利用してしまう問題を完全に解決していないため、完全なソリューションではなく、相対的に完成しているにすぎません。 3) Redissonの分散ロックを使用する ロックが早期に解除される問題をどのように解決できますか? ロックの再入可能機能を使用すると、ロックを取得したスレッドがタイマー付きのデーモン スレッドを開始し、expireTime/3 ごとに実行してスレッドのロックが存在するかどうかをチェックすることができます。存在する場合、ロックの有効期限は expireTime にリセットされます。つまり、デーモン スレッドは、ロックの有効期限が切れてロックが早期に解放されるのを防ぐために、ロックの「寿命を延ばす」ために使用されます。 もちろん、このデーモン プロセスのロジックをビジネスで実装するのは比較的複雑であり、未知の問題が発生する可能性があります。 現在、インターネット企業の実稼働環境で広く使用されているオープンソース フレームワークである Redisson は、この問題を非常にうまく解決します。非常にシンプルで使いやすく、Redis シングルインスタンス、Redis MS、Redis Sentinel、Redis Cluster などの複数のデプロイメント アーキテクチャをサポートしています。 興味のある方は、公式ドキュメントまたはソースコードを参照してください。 https://github.com/redisson/redisson/wiki 実装原理を図に示します (図では Redis クラスターを例にしています)。 2. Redisマルチマシン実装に基づく分散ロック、Redlock 上記の Redis スタンドアロン実装に基づく分散ロックには、実際には問題があります。つまり、ロックは 1 つの Redis ノードでのみ機能します。 Redis は Sentinel を通じて高可用性を確保していますが、Redis のレプリケーションは非同期であるため、マスターノードがロックを取得した後、データ同期が完了せずにフェイルオーバーが発生します。この時点では、他のクライアントのスレッドは引き続きロックを取得できるため、ロックのセキュリティが失われます。 全体のプロセスは次のとおりです。
このため、Redis の分散環境では、Redis の作者 antirez が分散ロックを実装するための RedLock アルゴリズムを提供しています。アルゴリズムはおおよそ次のようになります。 互いに完全に独立した N (N>=5) 個の Redis ノードがあると仮定します。マスター/スレーブ レプリケーションやその他のクラスター調整メカニズムはありません。これらの N 個のノードでロックを取得および解放するには、単一の Redis インスタンスの場合と同じ方法を使用するようにしてください。 ロックを取得するには、クライアントは次の操作を実行する必要があります。
ロックを解除するプロセスは比較的簡単です。クライアントは、ロックに失敗したノードを含むすべての Redis ノードに対してロック解除操作を開始し、ロック解除操作も実行する必要があります。 Antirez はアルゴリズムの説明でこの点を特に強調しています。何故ですか? その理由は、ノードが正常にロックされた後にクライアントに返される応答パケットが失われる可能性があるためです。この状況は非同期通信モデルで発生する可能性があります。クライアントはサーバーと正常に通信できますが、逆方向に問題が発生します。クライアントの応答タイムアウトによりロックは失敗しますが、Redis ノードに対して SET 命令が正常に実行され、ロックは成功したことを意味します。したがって、ロックを解放するときに、クライアントは、その時点でロックを取得できなかった Redis ノードに対してもリクエストを開始する必要があります。 さらに、Redis ノードがクラッシュして再起動した後にロックが失われ、ロックのセキュリティに影響が及ぶのを避けるために、antirez は遅延再起動の概念も提案しました。つまり、クラッシュ後すぐにノードを再起動せず、再起動する前に一定時間待機します。この期間は、ロックの有効期間よりも長くする必要があります。 Redlock についてさらに詳しく知りたい方は、公式ドキュメントを参照してください: https://redis.io/topics/distlock IV.結論分散システムの設計では、複雑さと利点のバランスをとることが重要です。過剰な設計を避けながら、可能な限り安全で信頼できるものにする必要があります。 Redlock は確かにより安全な分散ロックを提供できますが、それにはコストがかかり、より多くの Redis ノードが必要になります。実際のビジネスでは、単一ポイントの Redis を使用して分散ロックを実装すると、通常、ほとんどのニーズを満たすことができます。場合によっては、手動で介入してデータを入力することで、データの不整合を解決できることがあります。諺にもあるように、「テクノロジーが不十分なら、人間の介入で補うことができます!」 。 |
<<: クラウドネイティブアプリケーションを構築するために知っておくべきこと
>>: PaaS、IaaS、SaaS、Bass、Fass、サーバーレスの理解と違い
大手検索エンジンがインターネットのスパムサイトを一掃するにつれ、特に一部の個人サイトにとって、ランキ...
Ctrip.comは同城旅行に2億ドル以上を投資し、同社の第2位の株主となった。 4月28日、Ctr...
IBM Institute for Business Value のデータによると、実際には大多数の...
11月24日から、10年以上の歴史を持つドイツの老舗ホスティング会社が所有するVPSブランドであるu...
本稿では、主にTiantian Ptuの「小学校卒業写真」、「みんなで呉美娘のコスプレ」、「神経質な...
高速シンガポール VPS、最速シンガポール VPS、最速シンガポール VPS。シンガポールの VPS...
大きな帯域幅を持つアジアの VPS を見つけるのは簡単ではありません。また、大きな帯域幅と無制限のト...
ブログにタグを追加することは、ブログ記事を書くときに最も基本的な習慣の 1 つになっています。これに...
iniz は英国で正式に登録された会社です: 会社番号 08199520、登録事務所住所 45-15...
ウェブマスターネットワークが10月15日に報じたところによると、今年8月に公安部が全国に公安機関を派...
Amazon Aurora Serverless は、Amazon Aurora (MySQL 互換...
最近、市場調査会社IDCは、中国のクラウド市場全体の規模が2024年までに1,000億米ドルを超える...
私たちの生活は、個人的にも職業的にも、COVID-19パンデミックの影響を受けています。レストランな...
4月25日午後、「ファーウェイクラウド広東専属月例電子商取引業界ハイエンドCXOプライベートミーティ...
SEO 担当者なら誰でも、この文を知っています。「人々が情報を入手し、探しているものを見つけやすくす...