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

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

[[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は、企業のクラウドへのシームレスな移行をサポートするためにクラウド向けに誕生しました。

推薦する

ベタは堀から泳ぎ出すことができない

2019年11月21日午後11時、ある男性がパソコンの画面を更新し続けた。彼には妻と子どもがおり、大...

ferngullygraphics - $15/年/256M メモリ/15g ハードドライブ/500g トラフィック/ダラス

ferngullygraphics.com、これは本当に奇妙なもので、業界にとって恥ずかしいものです...

SEO業界の詳細な分業と責任。方向性は明確になっていますか?

インターネットの台頭とともに、SEO 業界が静かに誕生しました。多くの人は、SEO は比較的複雑な業...

Jieku.comは2年間で数千万元の資金を使い果たした:参入ポイントの不足と都市間拡大の時期尚早さ

Jieku.comは2年前に広州で立ち上げられたO2Oプロジェクトだ。同社は2011年7月の設立から...

hostodo、"unspeakable" (x) に最適な非常に安価な VPS

[hostodo]専門的な情報を得るために、海外のウェブサイトにアクセスするための x 機能を実装す...

Google ナチュラル検索パラメータ

注:この記事は非常に退屈です。特別な必要がない限り、スキップしたり無視したりすることができます。昨日...

百度K駅の各種標識と緊急対応策の分析

今の百度は批判も敗北も許されない。満足できないと、私たちウェブマスターの命をもてあそぶ。いつでもサイ...

モバイルサイト構築のプロセスと注意点

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っていますモバイル ...

WeChatが大きな動きを発表しました:500人のフォロワーを持つパブリックアカウントもトラフィックマスターを開設できます!

「フォロワー140人の私の公開アカウントがまた勢いづいてきました!」午後、公認アカウントの運営者が突...

hostdare: 信頼できる米国の小規模 VPS 販売業者、[#新しい割引コード#]、cn2 gia\cn2 gt\China Unicom\Mobile アクセスを提供

Hostdare は、2009 年にインド人によって設立されたアメリカの VPS ブランドです。サー...

P4 が NAT64 と出会うと、UCloud はどのようにして IPv4 から IPv6 に迅速に進化するのでしょうか?

IPv4 には、アドレス枯渇、セキュリティやサービス品質の確保の難しさ、経路拡張など、現時点では多く...

古いサイトから新しいサイトへの 301 リダイレクトを使用できますか?

SEO 最適化において、301 リダイレクトは頻繁に使用される機能です。その主な目的は、ウェブサイト...

標準化こそが、将来のSEO担当者にとって唯一の道である

国慶節の休暇前、誰もが、制作に3億元近くかかった列車のチケット予約サイトについて不満を漏らしていた。...

ウェブマスターネットワークからの毎日のレポート:タオバオがキャッシュバックモデルを調整、シャオミがセットトップボックスをテスト

1. タオバオは現金還元を中止し、ポイント還元を推進。タオバオの顧客還元モデルに関する新たな考え方タ...