[Spring Cloud シリーズ] - 分散システムで冪等性を実現するいくつかの方法

[Spring Cloud シリーズ] - 分散システムで冪等性を実現するいくつかの方法


ここに画像の説明を挿入します

I. 概要

注文システムを開発していると、よく支払いの問題に遭遇します。ユーザーが商品を購入した後、代金は正常に引き落とされるが、結果が返されるとネットワークに異常が発生します。この時点ではお金は引き落とされています。ユーザーがクリックした場合もう一度ボタンを押すと2回目の処理が行われ、引き落としが成功し、結果が返されました。ユーザーが残高を確認すると、さらに引き落とされており、取引記録も2つになりました。従来のシングルアプリケーションシステムでは、データ操作をトランザクションに落とし込み、エラー発生時に即座にロールバックするだけで済みましたが、クライアントへの応答時にネットワークの中断や異常が発生する場合もあります。注文の作成から支払いが完了するまでの注文ライフサイクル全体を通じてデータが一貫しており、例外によって変更されないことが保証されている場合。このメカニズムでは冪等性の使用が必要です。

2.冪等性とは何ですか?

冪等性は、抽象代数で一般的な数学およびコンピューターの概念です。

冪等関数または冪等メソッドは、同じパラメータを使用して繰り返し実行でき、同じ結果が得られる関数です。これらの関数はシステムの状態に影響を与えず、繰り返しの実行によるシステムの変化を心配する必要はありません。

冪等性: 複数の実行はリソース自体に 1 回の実行と同じ影響を与えます。

インターフェイスの冪等性は、実際には、インターフェイスを繰り返し呼び出すことができることを意味します。呼び出し元が複数回呼び出すと、インターフェイスの最終結果は同じになります。クエリ インターフェイスなど、一部のインターフェイスは、自然に冪等になる可能性があり、一度呼び出して複数回呼び出すことができます。回、回、システムによって得られる結果は同じです。クエリの結果は、呼び出しの数に基づいて変化しません。

挿入(INSERT) メソッドと変更(UPDATE) メソッドは冪等ではないため、複数の実行で副作用がないことを保証するメカニズムを通じて、必要なシナリオで処理される必要があります。

deleteが 1 回または複数回実行された場合、結果は空になり (つまり、結果は一貫しており)、副作用はありません。したがって、主キー ID に基づく削除は (擬似) 冪等であると考えることができます。非主キーの場合、複数回実行されますが、副作用 (データが削除される) はなく、(擬似) 冪等であると考えることもできます。

3. 冪等性にはいくつかの重要な点に注意する必要があります

  1. 冪等性は、1 つ (または複数) のリクエストがリソースに副作用を及ぼさないというだけではありません (データベース操作のクエリなど、追加、削除、変更がないため、データベースに影響を与えません)。
  2. 冪等性には、最初のリクエスト中にリソースに対する副作用も含まれますが、後続のリクエストではリソースに副作用が発生しません。
  3. 冪等性は、後続の複数のリクエストがリソースに副作用をもたらすかどうかに焦点を当てますが、結果には焦点を当てません。
  4. ネットワーク タイムアウトなどの問題は、冪等に関する議論の範囲内ではありません。

冪等性は、システム サービスによって外部世界に対して行われる約束 (実装ではなく) であり、インターフェイスが正常に呼び出される限り、複数の外部呼び出しがシステムに同じ影響を与えることを約束します。冪等として宣言されたサービスは、外部呼び出しの失敗を通常とみなし、失敗後には必ず再試行が行われます。

4. 冪等性は何に役立ちますか?

ビジネス開発では、ネットワークの問題によりリクエスト結果を受信して​​リクエストを再開始できないため、またはフロントエンド操作のジッターにより繰り返し送信が発生したため、繰り返し送信が発生することがよくあります。取引システムや決済システムでは、次のような繰り返しの送信によって引き起こされる問題が特に顕著です。

  1. ユーザーがアプリを複数回クリックして注文を送信した場合、バックグラウンドで生成される注文は 1 つだけです。
  2. Alipay への支払いリクエストを開始します。ネットワークの問題またはシステムのバグにより、Alipay による金額の引き落としは 1 回のみとなります。明らかに、冪等と宣言されたサービスは、外部の呼び出し元が複数の呼び出しを行うと考えられており、複数の外部呼び出しによってシステム データの状態が複数回変更されることを防ぐために、サービスは冪等になるように設計されています。
  3. アウトバウンド注文の繰り返しリクエストにより、複数のアウトバウンド注文情報が生成されます。

5.べき等性を確保するために使用される一般的な手段

5.1 MVCC ソリューション

マルチバージョン同時実行制御。この戦略は主に条件付き更新 (防止する条件付き更新) を使用して、複数の外部要求呼び出しがシステムに一貫した影響を与えることを保証します。システム設計の際には合理的に楽観ロックを使用し、バージョンやupdateTime(タイムスタンプ)などの条件を考慮して楽観ロックの条件を決定することで、更新操作が大きな影響を与えないようにする必要があります。同時多発的な状況の質問です。例えば

select * from tablename where condition=#condition# //取出要跟新的对象,带有版本versoin
update tableName set name=#name#,version=version+1 where version=#version#

更新プロセス中にバージョンを使用すると、他の操作によってオブジェクトが同時に更新され、更新が失われることを防ぎます。失敗を回避するには、通常、特定の再試行メカニズムが必要です。

5.2 重複排除テーブル

データを挿入するときは、重複排除テーブルを挿入し、データベースの一意のインデックス機能を使用して、一意のロジックを確保します。

この方法は、ビジネス内に固有のターゲットが存在するシナリオに適しています。たとえば、上記の支払いシナリオでは、注文の支払いが 1 回のみである場合、注文 ID を一意の識別子として使用できます。このとき、重複排除テーブルを構築し、一意の識別子を一意のインデックスとして使用できます。これを実装すると、支払い文書を作成し、1 回のトランザクションで重複排除テーブルに書き込みます。繰り返し作成されると、データベースが一意制約例外がスローされた場合、操作はロールバックされます。

5.3 重複排除テーブル

更新用に選択すると、注文に対応するレコードは実行プロセス全体にわたってロックされます。注: DB の読み取りが書き込みよりも多い場合は、これをできるだけ使用しないでください。

5.4 選択+挿入

同時実行性が低いバックグラウンド システムや一部のタスク JOB の場合、冪等性と反復実行をサポートするための簡単な処理方法は、ビジネス処理を続行する前に、最初にいくつかのキー データをクエリして、それが実行されたかどうかを判断することです。注: このメソッドは、コアの同時実行性の高いプロセスには使用しないでください。

5.5 ステートマシンのべき等

ドキュメント関連のビジネスやタスク関連のビジネスを設計する場合、必ずステート マシンが関与します。つまり、ビジネス ドキュメントには状態があり、その状態はさまざまな状況で変化します。一般に、有限ステート マシンが存在します。このとき、ステート マシンがすでに次の状態にあり、この時点で前の状態への変更が発生した場合、理論的には変更することはできませんが、この場合、有限ステート マシンの冪等性が保証されます。

このメソッドは、注文の作成と支払いなどのステート マシン フローがある場合に適しています。注文の支払いが前である必要があります。このとき、ステータス フィールドの設計時に int 型を使用し、値のタイプ サイズは冪等です。たとえば、注文の作成は 1000、支払いの成功は 1 です。999の支払いに失敗しました。

5.6 ページの繰り返し送信を防止するトークン メカニズム

ビジネス要件: ページ上のデータは 1 回のみクリックして送信できます。

原因: クリックの繰り返し、ネットワークの再送信、または nginx の再送信により、データが繰り返し送信されます。

解決策:

  • クラスター環境: トークンと redis を使用します (redis はシングルスレッドなので、処理をキューに入れる必要があります)
  • 単一 JVM 環境: トークンと Redis、またはトークンと JVM メモリを使用します。

処理の流れ

  • データを送信する前に、サービスからトークンを申請する必要があります。トークンは redis または jvm メモリに配置され、トークンは次の期間有効です。
  • 送信後、トークンはバックグラウンドで検証され、トークンが削除され、新しいトークンが生成されて返されます。
  • トークンの特徴:適用するには1回限り有効で、現在のフローを制限することができます

5.7 外部インターフェースを提供する API の冪等性を確保する方法

たとえば、WeChat が提供する支払いインターフェイスは、ソース ソースとシーケンス シリアル番号を使用して支払いリクエストを送信するために販売者に接続する必要があります。source+seq は、複数の支払いを防ぐためにデータベース内に一意のインデックスを作成します (同時実行中に処理できるリクエストは 1 つだけです)

**要約:** 冪等性は、有能なプログラマの遺伝子であるべきです。システムを設計するとき、特に Alipay、銀行、インターネット金融会社など、すべてお金が関係するシステムでは、冪等性が最優先に考慮されます。効率的でなければなりません。また、データが正確である必要があるため、過剰な控除や過払いなどの問題が発生してはなりませんが、これでは対処が難しく、ユーザーエクスペリエンスも良くありません。

5.7 グローバルにユニークなID

世界一意IDを使用する場合は、業務内容や業務内容に基づいてグローバルIDが生成され、業務実行前に世界一意IDが存在するか否かで業務が実行されたかどうかが判断されます。存在しない場合は、データベースや Redis などのストレージ システムにグローバル ID を保存します。存在する場合、メソッドが実行されたことを意味します。

エンジニアリングの観点から見ると、グローバルIDを冪等にすることでビジネスの根幹となるマイクロサービスとして存在できますが、そのようなサービスは多くのマイクロサービスで利用されており、そのような機能が各マイクロサービス内で完結すると作業負荷の重複が発生します。また、信頼性の高い冪等サービスを実現するには、最初にマシンがグローバル ID をストレージに書き込むが、書き込み後にハングするなど、グローバル ID のタイムアウト機構の導入が必要になるなど、多くの点を考慮する必要があります。

グローバルに一意な ID の使用は、ビジネス操作の挿入、更新、削除をサポートできる一般的なソリューションです。ただし、このソリューションは見た目は美しいですが、実装は面倒です。次のソリューションは特定のシナリオに適していますが、実装は比較的簡単です。

5.8 分散ロック

メソッドに入るとまずロックを取得し、ロックが取得できたら以降の処理を続行します。ロックが取得されていない場合は、ロックが取得されるまでロックが解除されるのを待ちます。メソッドの実行が終了すると、ロックが解放されます。もちろん、ロックが誤って解放されるのを防ぐために、ロックにはタイムアウト期間が必要です。分散システムの冪等性を解決するために使用され、一般的に使用される実装ソリューションは、redis や Zookeeper などのツールです。

6. まとめ

べき等性は、べき等性を制御するためのビジネス ロジックを追加し、ビジネス機能を複雑にし、並列実行機能を逐次実行に変更し、実行効率を低下させます。

冪等性はビジネス機能を複雑にし、実行効率を低下させますが、システムの正確性を保証する必要があります。上記の X の更新例を単一サーバー上で取り上げると、そのコードにロックを追加し、X を揮発性に設定することで、受信データの正確性が保証されます。分散環境でデータベースやファイルからXを問い合わせる場合、上記のロック方法ではデータの正当性が保証できないため、分散ロックを使用する必要があります。したがって、データに問題があるはずがないため、メソッドまたはインターフェイスの冪等性を確保することが非常に必要です。

おすすめ

転載: blog.csdn.net/songjianlong/article/details/132553052