議論しないでください、分散ロックもロックです

議論しないでください、分散ロックもロックです

[[250750]]

トムキャットロック

Tomcat はこのシステムの中核コンポーネントです。ユーザーからのリクエストが届くたびに、Tomcat はスレッド プールからスレッドを見つけてそれを処理します。ログインを実行するものもあれば、ショッピングカートをチェックするもの、注文を行うものもあります。トムキャットは、部下たちが一生懸命働き、人間の要求をこなす姿を見て、達成感を感じます。

同時に、すべてのビジネス ロジックが制御されている点も非常に誇りです。 MySQL とは何ですか?単にデータを保存する場所ではないのですか? Redisとは?それは単に速度を上げるためのキャッシュではないのですか?

彼らがいなくても代わりの人は見つかるが、私はかけがえのない存在だとトムキャットはよく思う。

昨日、MySQL がたまたま、Node.js という人が隣のマシンに移動したと報告しました。実際には、JavaScript コードを実行し、さまざまなビジネス ロジックを実装するために 1 つのスレッドのみを使用しました。 JavaScript はバックエンドにも導入できますか?コールバックは必要ですか?これはナンセンスではないでしょうか?しかし、それによってすべてのビジネスが失われないように注意してください。

これを考えて、Tomcat はすぐに各スレッドの状況を確認し、誰かが故意に怠けているかどうかを確認しました。

スレッド 0x9527 と 0x7954 が再び争い始めています。その理由は非常に単純です。どちらも在庫を減算しようとします。つまり、在庫を読み取り、在庫を変更し、データベースに書き戻します。

スレッドの同時実行により、3 つの操作が絡み合い、データの不整合が発生しました。

Tomcat は言いました。「何をしているのですか? なぜ在庫を読み取らなければならないのですか? 在庫を直接更新するだけではだめですか? MySQL に正確性を確保させてください。責任転嫁の方法を学ぶ必要があります!」

0x7954 は次のように返信しました。「方法はありません。Zhang Dapang のコードはこのように書かれています。これはビジネス要件のようです。在庫を差し引く前に、在庫が十分にあるかどうかを確認する必要があります。」

Tomcat は歯が痛くなったので、Redis の解決策を考えずにはいられませんでした。キャッシュの読み取りおよび書き込みの各リクエストに対して、Redis はそれらをキューに入れて、1 つのスレッドで 1 つずつ処理しました。同時実行の問題は絶対に発生しません。

しかし、ここではそれは不可能です。データベースへのアクセスは非常に遅い操作です。 1 つのスレッドのみを使用してリクエストを 1 つずつ処理すると、すべてのリクエストを待機させる必要があり、ユーザーは不安でたまらなくなります。

他に方法がなかったので、Tomcat は両方に Java オブジェクトを投げました。「これはロックです。最初にこれを取得した人が、在庫を減算する 3 つの操作を実行できます。」

「もし手に入らなかったらどうしよう?」

「ブロックされて待機しているときに、誰かがロックを解除すると、JVM は自然にロックを解除して再びロックを取得します。ロックを取得したら、それを実行します。」

分散ロック

張大鵬は何かがおかしいと感じた。最近プログラムの動作が少し遅くなってきたのはなぜでしょうか?

マシンの性能が十分ではないと考えた彼は、新しいマシンを数台購入し、Tomcat を数台インストールしてクラスターを構成しました。

現在、Tomcat は 3 台あり、各 Tomcat にはインベントリへのアクセスを制御するロックがあります。

Tomcat JVM プロセス内には、同時に在庫を減算できる幸運なスレッドが 1 つしかありませんが、現在は 3 つの Tomcat があり、幸運なスレッドが 3 つ出現します。

この幸運な 3 人は、在庫を減算するときに 0x7954 や 0x9527 などのエラーに遭遇しますが、今ではお互いを知らないので、口論する機会さえありません。

3匹のトムキャットはみんな頭痛がしていました。この分散環境では複数のプロセスが実行されており、プロセス内の元のロックは有効ではなくなりました。最優先事項は、ロック機能を実装するために、客観的で公正かつ独立した第三者を見つけることでした。

MySQL は次のように提案します: 「ロックを見つけるために私のところに来てください!」

「ロックサービスを提供できますか?私たちが使用できるように公開しますか?」トムキャットAが尋ねた。

「いいえ、これはロック サービスではありません。データベース テーブルを提供します。このテーブルのフィールド lock_name には一意の制約があります。」

「つまり、スレッドがロックを取得するたびに、データベースにデータを挿入する必要があるということですか?」 Tomcat Aはすぐに応答しました。

  1. 入れる ロック(lock_name,...)( 'stock' ,...);

「はい、私のユニーク制約は 1 つの成功のみを保証し、他のすべては失敗します。これはロックを取得することと同じです。もちろん、そのスレッドの操作が完了したら、ロックを解除する必要があります。」

  1. 消去  lock_name= 'stock'ロックから 

これはシンプルな解決策ですが、負荷も大きいです。ロックを取得するたびにデータベースにアクセスする必要があるのです。

TomcatA からの 0x9527 が最初にそこに到達し、データを挿入してロックを取得したと仮定します。すると、Tomcat B からの操作 0x7954 は失敗するはずです。このとき 0x7954 は何をすべきでしょうか?ブロックして TomcatB が起動するのを待つことはできますか?いいえ、MySQL が各 Tomcat に通知しない限り、TomcatB でさえ操作 0x9527 がいつ完了するかを知らないため、これは絶対に不可能です。

そうすると、0x7954@TomcatB ができることは 1 つだけです。しばらく待ってから再試行してください。このサイクルはロックが取得されるまで続きます。

しかし、0x9527 がロックを取得し、実行中に TomcatA がクラッシュした場合、データベース レコードは常に存在し、誰もそれを削除しないため、ロックは解除できません。また、解除されていない期限切れのロックをクリーンアップするためのクリーナーも必要ですが、これは非常に面倒です。

レディス

この時、Redis はこう言いました。「MySQL の海賊船には乗らないで!彼のやり方は面倒すぎる。ロック情報を保存するために第三者を探すだけじゃないの?私のキャッシュを使ったほうがいいよ!」

「Redis はメモリ上で動作するので、はるかに高速になります!」トムキャットBは言った。

「はい、MySQL はデータを挿入するためのテーブルを提供していませんか? ここで気にする必要はありません。すべての Tomcat スレッドは、stock_lock=true などの値をキャッシュに設定しようとすることができます。最初に設定に成功した人がロックを取得し、在庫を差し引くことができます。」

「複数のスレッドがこれを設定しようとしている場合、1 つだけが成功し、その他は失敗することを保証できますか?」

レディスは胸をたたいて言った。「絶対に保証します!」

(Coder Liu からの注記: これは実際には setnx コマンドです)

MySQL は口を尖らせてこう言いました。「それは本質的には私の解決策と同じです。Tomcat のスレッドが在庫に変更を加えた後、stock_lock をロック解除して削除する必要があります。」

Redis は次のように言っています。「ここで有効期限を設定することもできます。Tomcat A のスレッドがロックを取得し、その後 Tomcat A がクラッシュした場合、有効期限が来ると自動的に stock_lock を削除し、他のスレッドが再びロックを取得できるようになります。」

「そうですね、MySQL よりも先進的で高速です。このロックを使用しましょう。」 3匹のトムキャット全員が同意しました。

定期的な自動リリースに関する問題

「ちょっと待ってください。期限切れのロックの自動削除には問題があります。」 MySQL が突然反撃しました。

「何が問題なの?」 Redis は、古いデータベース担当者がまだ反撃しようとしているとは予想していませんでした。

「Tomcat A の 0x9527 がロックを取得し、在庫減算操作を実行したが、何らかの理由でブロックされたとします。ブロック時間が有効期限を超え、ロックが解除されました。結局、不整合が残ります。」

「あなたは細かいことにこだわりすぎです。これは間違いなく低確率の出来事です!」レディスは叫んだ!

「さらに、データベース ソリューションを使用する場合でも、これらのロックを定期的にクリーンアップする必要があります。原則は同じです。」

行ロック

翌日、MySQL は嬉しそうに Tomcat のところへ行き、「兄弟たち、私は昨夜半まで Quartz (有名な時間指定実行フレームワーク) とチャットしていました。Quartz は、データベースで分散ロックを実装する新しい方法、つまり行ロックについて教えてくれました」と言いました。

「わかりましたか? for uppate を追加することで、この SQL ステートメントはこの行をロックします。つまり、ロックを取得します。トランザクションがコミットされている限り、行ロックは自動的に解除されます。」

「ロックを取得できなかった他のスレッドはどうなりますか?」

「もちろんブロックされます。他のスレッドが行ロックを解除すると、自動的に取得できます。コード内のループで再試行する必要はありません。以前のソリューションではこれができなかったのです。」 MySQLは言った。

「スレッドが行ロックを解放するのに長い時間がかかったらどうなるでしょうか? 何が起こるでしょうか?」 Tomcat はこれを最も懸念しています。

「すると、他のスレッドが待機し、データベース接続を解放せずに占有することになります。占有されている接続が多すぎると、接続プールに問題が生じます...」MySQL は信頼性がなくなりつつあり、これは致命的な問題です。

「はは、なんて悪い考えを思いついたんだ!私の鍵を使えばいいんだよ!」レディスは笑った。

「では、なぜクォーツが使えるのでしょうか?」 MySQLは諦めませんでした。

「Quartzは単一事業なので、ロック解除も早いので問題はないと思います。」

CAS

そのとき、Node.js が静かにやって来て、データベースの老人を引き離しました。「先輩、彼らに同じビューを与えないでください。これは単に在庫を減らすだけなのに、なぜ分散ロックを使うのですか。こうしましょう:」

#old_num = まず現在の在庫数を取得します

  1. #新しい番号 = #古い番号 - 10  
  2. 在庫更新します。stock_num = #new_numを設定します。ただし、product_id=#product_id stock_num = #old_num です。

MySQL の目が輝きます。はい、更新ステートメントを呼び出す条件として #old_num を渡すたびに、それが成功した場合は、この期間中に他のスレッドが在庫を更新していないことを意味します。

失敗した場合は、成功するまでこれらの 3 つのステートメントを再実行します。とてもシンプルで、ロックもまったく必要ありません。とてもクールです。

数日後、Tomcat もこの解決策について聞いて、驚いて言いました。「これは Java でよく使用される Compare And Set (CAS) ではないのですか?」

要約する

同時に、張大雁氏は、分散ロックとインプロセスロックは本質的に同じであるとまとめ始めました。

1. 相互に排他的であるため、一度にマシン上の 1 つのスレッドによってのみ取得できます。

2. *** ブロックしてから起動することをサポートするので、待機中のスレッドがループ内で再試行する必要がありません。

3. *** は再入可能 (この記事では説明されていません。「プログラミングの世界のロック」を参照してください)

4. ロックを素早く取得して解除する

5. 分散ロックの場合、ロックを保存するための集中化された「場所」(データベース、Redis、Zookeeper など)を見つける必要があり、この場所は高可用性である必要があります。

6. 「信頼性の低い」分散環境を考慮すると、分散ロックは有効期限を設定する必要がある

7. CASの考え方は非常に重要です。

【この記事は51CTOコラムニスト「Liu Xin」によるオリジナル記事です。転載する場合は著者のWeChat公開アカウントcoderisingを通じて許可を得てください]

この著者の他の記事を見るにはここをクリックしてください

<<:  VMware NSX-V と NSX-T を比較する方法

>>:  CynosDBは、企業のクラウドへのシームレスな移行をサポートするためにクラウド向けに誕生しました。

推薦する

サムスンの携帯電話が頻繁に爆発、韓国の専門家が中国製バッテリーの禁止を勧告

韓国のアジア経済が10月17日に報じたところによると、サムスンのGalaxy S4スマートフォンは発...

justhost: $19.99/OpenStack クラウド/(商用) 安定したウェブサイト構築の推奨

Justhost は、cpanel 仮想ホスティングで有名な、米国で非常に有名なホスティング会社です...

vsyshost: ウクライナ VPS/オランダ VPS、苦情防止、月額 18 ドル、帯域幅 1Gbps、トラフィック無制限

vsys.host は 2009 年に設立されたウクライナの商人です。主にウクライナのキエフとオラン...

ウェブサイト設定の最適化: サイト内調整のヒントの共有

オンサイト調整はSEO最適化の真髄です。オンサイト調整とは何ですか?オンサイト調整の目的は何ですか?...

検索エンジンがオリジナルだと判断するようなソフトな記事を書くにはどうすればよいでしょうか?

検索エンジンがオリジナルだと判断するようなソフトな記事を書くにはどうすればよいでしょうか?今朝、ウェ...

主要な

前回ジュニアSEOERの基準を書いて以来、皆様からの評価と期待をいただいております。ここに感謝申し上...

SEO とユーザー エクスペリエンスのどちらがより重要ですか?

SEOキーワードランキングとユーザーエクスペリエンスのどちらが重要でしょうか?この記事はウェブサイト...

ブログの人気を高める5つの方法

ブログ記事を公開しても誰も読まなければ、ブログが存在する意味がありません。個人ブログやビジネスブログ...

ParaScaleがクラウドストレージプラットフォームを立ち上げ、顧客から好意的なフィードバックを受ける

クラウド ストレージは過去 1 年間で大きな注目を集めました。クラウド ストレージという用語は新しい...

注目に値するコンテンツライティングテクニックをカウントダウン

記事はウェブサイトの生命線です。すべてのウェブサイトは記事で構成されていますが、うまく組み合わされて...

昔ながらの外部リンク方式はまだ役に立つのでしょうか?

最近、多くのウェブマスターが不満を漏らしているのを見ました。彼らは皆、外部リンク構築の範囲がどんどん...

技術共有: KVM 仮想化を使用して証拠を収集するにはどうすればよいでしょうか?

仮想化技術はますます広く使用されるようになっています。国内の仮想化市場においては、5年間で売上が2桁...

訪問者のニーズを理解することは検索エンジンに応えるための基礎である

私たちはいつも、サイト開発の原動力は何だろうと考えてきました。ランキングでしょうか、それとも利益でし...

マルチチャネル統合マーケティング知識システムを構築するにはどうすればよいでしょうか?

インターネットとモバイルインターネットの急速な発展に伴い、新しいマーケティング手法とマーケティングキ...