Experience and method of improving system performance
1. 背景
資金検証用データアセンブリ実行の緊急対応リンクは、数千万 TPS の同時トランザクション量を処理しています。同時に、資金ビジネスの特性上、システムは可用性と精度に対して非常に高い要件を持っています。日々の開発プロセスでは、さまざまな高可用性の問題に直面し、システム設計とパフォーマンス最適化の取り組みを継続的に行っています。その中で、パフォーマンス最適化の経験と方法をまとめ、共有と意見交換を行い、今後も新たに遭遇する問題についてまとめと補足を続けていきます。
2. 高性能システムとは
まず、高性能設計とは何かを理解しましょう。公式な定義では、高可用性 (HA) の核心的な目標はビジネスの継続性を確保することです。ユーザーの視点では、ビジネスが常に正常かつ安定的にサービスを提供している状態です。業界では一般に、システムの可用性を「ナイン数」で尺度として衡量します。通常、冗長化やシングルポイント排除などの特別な設計を採用してビジネスのダウンタイムを削減し、コアサービスの高可用性を維持します。
高い同時実行性は、通常、システムが同時に多くのリクエストを並列処理できることを意味します。一般に応答時間、同時スループット TPS、同時接続ユーザ数などの指標で衡量されます。
高性能とは、プログラムの処理速度が非常に速く、メモリ消費が少なく、CPU 使用量が少ないことを意味します。高性能の指標は高い同時実行性の指標と密接に関連しています。パフォーマンスを向上させるには、システムの同時実行能力を向上させる必要があります。
本稿では、「高性能、高同時実行性、高可用性」サービスの設計について紹介と共有を行います。
3. パフォーマンスの向上方法
高性能設計について議論する際、IO 多重化、ゼロコピー、スレッドプール、冗長性などの用語がよく登場します。この部分に関する記事は多数ありますが、本質的にはシステム的な問題であり、コンピュータアーキテクチャの底層から考えることができます。システムの最適化は、コンピューティング性能 (CPU) とストレージ性能 (IO) の 2 つの次元から切り離すことができません。以下の方法をまとめます。
• 高性能コンピューティング (CPU) の設計方法
• 計算コストの削減:コード計算の時間計算量最適化 O(N^2) → O(N)、同期/非同期の合理的な使用、流量制限によるリクエスト数の削減
• より多くのコアを計算に参加させる:シングルスレッドからマルチスレッドへ、シングルマシンからクラスターへ
• システム IO の改善方法
• IO 速度の高速化:ランダム読み書きからシーケンシャル読み書きへ、ハードウェア面での SSD 導入など
• IO 回数の削減:インデックス/分散コンピューティングによるフルテーブルスキャンの代替、ゼロコピーによる IO コピー回数の削減、DB のバッチ読み書き、データベースとテーブル間の接続数増加
• IO ストレージの削減:データ有効期限ポリシー、メモリ、キャッシュ、DB などのミドルウェアの合理的な使用、適切なメッセージ圧縮
4. 高性能最適化戦略
1. コンピューティング性能の最適化戦略
1.1 プログラム計算の複雑さ削減
以下の擬似コードを見てみましょう(ビジネスコードは秘匿化済み)。
boolean result = true;
// リクエストの要求をループで走査し、A サービスかつ A サービスが最終状態に達していない場合は false を返し、それ以外の場合は true を返す
コードにはいくつかの明らかな問題があります。
1. リクエストが来るたびに 6 行目で DB をクエリしていますが、8 行目でリクエストの判定とフィルタリングを行っており、6 行目のコード計算リソースの無駄が生じています。さらに、6 行目の DAO データアクセスは時間のかかる操作です。まずビジネスが A に属するかを判定してから DB をクエリするようにできます。
2. 現在の要件では、1 つの A サービスが最終状態に達していないだけで false を返します。false を取得した後、11 行目は直接 break して計算回数を削減できます。
最適化後のコード
boolean result = true;
// リクエストの要求をループで走査し、A サービスかつ A サービスが最終状態に達していない場合は false を返し、それ以外の場合は true を返す
最適化後の計算時間は、平均 270.75 ms → 40.5 ms の範囲です。
日常的な最適化コードでは、ARTHAS ツールを使用してプログラムの呼び出しにかかる時間を分析できます。時間のかかるタスクは可能な限りフィルタリングし、不要なシステム呼び出しを削減する必要があります。
1.2 同期/非同期の合理的な使用
どのビジネスリンクが結果を同期的に待つ必要があり、どれが不要かを分析します。コア依存のスケジューリングは同期にでき、非コア依存のスケジューリングは可能な限り非同期にできます。
シナリオ:リンクの観点から、システム A がシステム B を呼び出し、システム B がシステム C を呼び出して計算を完了した後、システム A に結論を返します。システム A のタイムアウトは 400 ms です。通常、システム A からシステム B の呼び出しは 300 ms、システム B からシステム C の呼び出しは 200 ms です。
ここで、システム C がシステム D にも呼び出し結論を返す必要があり、150 ms かかります。
この時点で、システム A – システム B – システム C の既存の呼び出しリンクはタイムアウトで失敗する可能性があります。システム D の導入により時間消費が 150 ms 増加し、プロセス全体が同期であるため、システム D の更新結論に対する非強い依存を非同期呼び出しに変更する必要があります。
1.3 流量制限保護の徹底
障害シナリオ:システム A がシステム B を呼び出して異常データをクエリしており、日頃は約 10 TPS またはそれ以下でした。ある日、システム A がタイミングタスクのトリガーロジックを変更し、さらにコードのバグが重なり、呼び出し頻度が 500 TPS に達しました。さらに ID エラーにより、システム A がキャッシュをバイパスして直接 DB と ApsaraDB for Hbase をクエリし、ApsaraDB for Hbase の読み取りホットスポットを作成してクラスター全体を拖累し、ストレージとクエリに影響を及ぼしました。
その後、システム A に対してクエリ流量制限を実施し、同時実行数を 15 TPS 以内に収めました。コアビジネスサービスでは、クエリ流量制限保護とキャッシュ設計を徹底する必要があります。
1.4 シングルスレッドからマルチスレッドへ
シナリオ:緊急位置特定シナリオで、システム A がシステム B を呼び出して診断結論を取得します。TransitRouter のタイムアウトは 500 ms です。異常 ID イベントに対して、複数の診断サービスを実行し、診断フローを記録する必要があります。各診断は約 100 ms かかります。ビジネスの成長に伴い、5 つ以上の診断項目で 500 ms 以上の計算時間がかかるようになりました。この時点で、ピーク期間中にサービスが一時的に利用不可になります。
このコードを非同期実行に変更することで、診断時間が最も時間のかかる診断サービスの時間に収まります。
1.5 シングルマシンコンピューティングからクラスターコンピューティングへ
ここでは、3 層の分散を使用してコンピューティングタスクを分割し、実行できます。MapReduce は、シングルマシンの計算プレッシャーを軽減する 1 つの考え方です。
2. システム IO 性能の最適化戦略
2.1 一般的な Full GC の対策
システムでは一般的な Full GC 問題が多数存在します。まず、JVM のガベージコレクションメカニズムについて説明します。ヒープ領域は世代別に設計されており、Eden、Survivor、Tenured/Old に分割されます。Eden と Survivor は新世代に属し、Tenured/Old は旧世代に属します。一般に、新世代での GC を Minor GC、旧世代での GC を Major GC、ヒープ全体での GC を Full GC と呼びます。
メモリ割り当て戦略:1. オブジェクトはまず Eden 領域に割り当てられます。2. 大きなオブジェクトは直接旧世代に入ります。3. 長期間生存するオブジェクトは旧世代に入ります。4. 動的オブジェクトの年齢判定(仮想マシンは常にオブジェクトが MaxTenuringThreshold に達することを要求するわけではなく、Survivor 領域内の同じ年齢のすべてのオブジェクトのサイズ合計が Survivor の半分より大きい場合、その年齢以上のオブジェクトは直接旧世代に入ることができます)。5. 旧世代の連続空き領域が(新世代の全オブジェクトの合計サイズまたは過去の全プロモーションの平均サイズ)より大きい場合は Minor GC が実行され、それ以外の場合は Full GC が実行されます。
システムで Full GC が一般的にトリガーされるケース:
(1) 大きなオブジェクトのクエリ:ビジネス内の過去の巡回データは定期的にクリーンアップする必要があります。削除戦略は、毎日先月以前のデータを削除し(ビジネスではソフトデリートマークでマーク)、データベースの定期クリーンアップ時にデータを完全に回収します。
ある日、削除ポリシーが「先月以前のデータを削除」から「先週以前のデータを削除」に変更されました。その結果、削除されるデータが 1,000 件から 150,000 件に拡大し、データオブジェクトがメモリの 80% 以上を占有し、システムの Full GC が直接引き起こされ、他のタスクにも影響が及ぼされました。
多くのシステムコードでは、クエリするデータ件数に上限が設定されていません。ビジネスの継続的な成長に伴い、システムキャパシティの増加に対してアップグレードが追いつかず、大量のラージオブジェクトリストがクエリされ、ラージオブジェクトが頻繁に GC されます。
(2) 回収されない静的メソッドの設定
システム A では静的 List オブジェクトを設定し、DRM 設定読み取りに使用していました。しかし、設定情報をクエリしてから Put 操作を実行するロジックが存在しました。ビジネスの成長に伴い、静的オブジェクトはますます大きくなり、クラスオブジェクトに属するため回収できず、最終的にシステムで頻繁な GC が発生しました。
オブジェクトをマップのキーとして使用するのは不合理です。同時に、キー内のオブジェクトは回収できず、GC が発生します。
Full GC 実行後でも空き領域が不十分な場合、次のエラー [java.lang.OutOfMemoryError: Java heap space] がスローされます。上記 2 つの状況による Full GC を回避するため、チューニングでは Minor GC 段階で可能な限りオブジェクトを回収し、オブジェクトは新世代で一定期間生存させ、過度なオブジェクトや配列を作成しないようにする必要があります。
2.2 ランダム読み書きからシーケンシャル読み書きへ
一般的なメカニカルハードディスクでは、ランダム書き込みの性能は非常に悪く、長時間使用後に断片化が発生します。シーケンシャル書き込みは、ディスクのシーク時間とディスク回転時間を大幅に節約し、性能を大幅に向上させます。この層は実際にはミドルウェア自体によって実装されています。たとえば、ApsaraMQ for Kafka のログファイルは、メッセージをシーケンシャルに書き込み、ファイル末尾に追加することでメッセージを保存しています。
2.3 DB インデックス設計
テーブル構造を設計する際は、後段階でのテーブルデータに対するクエリ操作を考慮し、合理的なインデックス構造を設計する必要があります。テーブルのインデックスを確立した後は、後続のクエリ操作がインデックスの無効化を招かないよう注意する必要もあります。
(1) キー値の少ない列は選択しないようにしてください。つまり、明らかな識別性がない場合や、重複データが少ない場合はインデックスを作成しないでください。たとえば、is_delete 列にインデックスを作成して 100,000 件のデータをクエリする場合、is_delete=0 のデータが 90,000 件あると、インデックスブロックへのアクセスコストを考慮すると、フルテーブルスキャンですべてのデータブロックを走査する方が効率的です。
(2) 先頭の like "%***" や like "%***%" の使用は避けてください。前方のマッチングがあいまいなため、インデックス順序を使用してデータブロックにアクセスすることが難しく、フルテーブルスキャンが発生します。ただし、like "A***%" の使用には影響がありません。"B" で始まるデータに遭遇した時点で列の検索を停止できるからです。ユーザー情報に基づくあいまい検索でデータを探す際に、インデックスの無効化に遭遇しました。
(3) その他の可能なシナリオとして、OR クエリ、複数列インデックスでクエリの最初の部分を使用しない場合、クエリ条件に計算操作がある場合、またはフルテーブルスキャンがインデックスクエリよりも速い場合があります。
現在、AntMonitor や Tars などのツールが、長時間かかる SQL や CPU を多く消費する SQL をスキャンしてくれています。実行計画に従ってクエリロジックを調整できます。少量データに対する頻繁なクエリでは、インデックスを有効活用できます。もちろん、インデックスを多く構築しすぎるとストレージコストもかかります。INSERT や DELETE が頻繁なビジネスでは、不要なインデックス設計を削減することも考慮する必要があります。
2.4 データベース分割・テーブル分割の設計
ビジネスの成長に伴い、クラスター内のノード数が多くなりすぎると、最終的にデータベース接続の上限に達します。その結果、クラスター内のノード数がデータベース接続数に制限され、クラスターノードを増やして拡張できなくなり、ビジネストラフィックの継続的な成長に対応できなくなります。これは Ant が LDC アーキテクチャを採用する理由の 1 つです。ビジネス層で水平分割と拡張を行い、各 cell のノードが現在のノードに対応するデータベースのみにアクセスするようにしています。
2.5 大量のテーブル JOIN の回避
Alibaba コーディング仕様では、3 つ以上のテーブルの JOIN は禁止されています。3 つのテーブルのデカルト積計算により、演算の複雑さが幾何学的に増加するためです。複数のテーブルを JOIN する場合は、関連フィールドにインデックスがあることを確認してください。
ビジネスでデータをカスケードしたい場合は、プライマリキーに基づいてメモリ内でネストされたクエリと計算を適切に実行できます。操作が非常に頻繁なパイプラインテーブルでは、一部のフィールドを冗長化して、空間計算量を時間計算量と交換することをお勧めします。
2.6 ビジネスフローテーブルでの時間のかかる計算の削減
ビジネスレコードでは count 操作を実行することがあります。適時性の要件が高くない統計や計算については、定期タスクがビジネスの低ピーク期間に計算を実行し、計算結果をキャッシュに保存することをお勧めします。
複数のテーブルの JOIN が伴う場合は、オフラインテーブルを使用して MapReduce 計算を行い、計算結果をオンラインテーブルに戻して表示することをお勧めします。
2.5 データ有効期限ポリシー
テーブルのデータ量が大きすぎる場合、インデックスと日付に基づく部分スキャンが行われず、フルテーブルスキャンが発生すると、DB のクエリ性能が大幅に低下します。合理的なデータ有効期限戦略を設計することをお勧めします。既存データは定期的に履歴テーブルに配置するか、オフラインテーブルにコピーして、大量のデータのオンラインストレージを削減する必要があります。
2.6 メモリの合理的な使用
よく知られているように、リレーショナルデータベース DB のクエリの底層はディスクストレージであり、メモリキャッシュよりも低速です。キャッシュ DB とビジネスシステムの間の接続には一定の呼び出し時間がかかり、ローカルメモリよりも低速です。ただし、ストレージ容量の面では、メモリのデータ保存容量はキャッシュよりも低くなります。長期的な永続データはディスク上の DB に保存することをお勧めします。設計プロセスでは、コストとクエリ性能のバランスを考慮する必要があります。
メモリに関しては、データ整合性の問題が発生します。DB データとメモリデータの整合性をどのように確保するか、強力な整合性か弱い整合性か、データの保存順序とトランザクションをどのように制御するか、ユーザーにできるだけ意識させないようにするかを検討する必要があります。
2.7 データ圧縮
多くのミドルウェアは、データのストレージと転送に圧縮と展開の操作を採用して、データ転送時の帯域幅コストを削減しています。ここではデータ圧縮について詳しくは紹介しません。1 つ触れておきたいのは、高い同時実行性で稼働するビジネスのログ出力です。トラブルシューティングを容易にするために、JSON.toJSONString(Object) をあまり多く出力しすぎると、ディスクが簡単にいっぱいになります。ログの容量有効期限ポリシーに基づくと回収も簡単になり、問題のトラブルシューティングがさらに不便になります。したがって、ログを合理的に使用することをお勧めします。エラーコードは簡略化し、コアビジネスロジックはサマリーログを出力できます。構造化データは、後続のモニタリングとデータ分析を容易にすることもできます。
ログを出力する際、いくつかの質問を考慮してください。誰かがログを見る可能性があるか、ログを見て何ができるか、各フィールドは必ず出力する必要があるか、問題がある場合にトラブルシューティングの効率を向上できるか。
2.8 ApsaraDB for Hbase のホットキー問題
ApsaraDB for Hbase は、高い信頼性、高性能、カラム指向、スケーラビリティを備えた分散型ストレージシステムであり、非リレーショナルデータベースです。ApsaraDB for Hbase のストレージ特性は以下の通りです。
1. 列数は動的に追加できます。列が空の場合はデータが保存されず、ストレージ容量を節約できます。
2. ApsaraDB for Hbase はデータを自動的に分割するため、データストレージは自動的に水平方向のスケーラビリティを確保できます。
3. ApsaraDB for Hbase は高い同時実行性の読み書き操作をサポートできます。分散アーキテクチャでは、読み書きロックの待機確率が大幅に低下します。
4. 条件付きクエリはサポートされておらず、RowKey によるクエリのみサポートされています。
5. Master サーバーのフェールオーバーは一時的にサポートされておらず、Master サーバーがダウンするとストレージシステム全体が利用不可になります。
ApsaraDB for Hbase のストレージ構造は以下の通りです。テーブルは行方向に複数の HRegion に分割されます。HRegion は ApsaraDB for Hbase における分散ストレージと負荷分散の最小単位です。つまり、異なる HRegion は異なる HRegionServer 上に配置できますが、同じ HRegion を複数の HRegionServer に分割することはできません。HRegion はサイズに基づいて分割されます。各テーブルは通常 1 つの HRegion から始まります。テーブルにデータが挿入されるにつれて、HRegion は増加します。HRegion の列ファミリーがしきい値 (デフォルト 256 MB) に達すると、2 つの新しい HRegion に分割されます。
ApsaraDB for Hbase の行は RowKey の辞書順でソートされています。この設計によりスキャン操作が最適化され、関連する行や一緒に読み取られる行が近くに配置されるため、効率的なスキャンが可能になります。RowKey のこの設計がホットスポット障害の原因でもあります。ホットスポットとは、大量のクライアントがクラスター内の 1 つまたは少数のノードに直接アクセスする状態を指します(アクセスは読み取り、書き込み、またはその他の操作の可能性があります)。
大量のアクセスにより、ホットスポットが存在する単一マシンのキャパシティを超え、パフォーマンスの低下やリージョンの利用不可を引き起こす可能性があります。これは同じ RegionServer 上の他のリージョンにも影響を及ぼします。ホストが他のリージョンからのリクエストを処理できなくなるため、データホットスポット(データスキュー)が発生します。
したがって、ApsaraDB for Hbase にデータを挿入する際は、RowKey の設計を最適化して、データがクラスター内の複数のリージョンに書き込まれるようにする必要があります。レコードを異なるリージョンに均等に分散し、各リージョンの負荷を平準化するよう努める必要があります。
ホットキー回避の一般的な方法:反転、加塩、ハッシュ化
• 反転:たとえば、ユーザー ID のプレフィックス 2088 や BBCRL の先頭の同じプレフィックスを反転させて後ろに移動します。
• 加塩:RowKey の先頭にタイムスタンプ Hash などのプレフィックスを追加します。追加するプレフィックスの種類が多いほど、ランダムに生成されたプレフィックスに従って各リージョンに分散され、ホットスポットを回避できますが、スキャンの利便性も考慮する必要があります。
• ハッシュ化:ビジネス上で RowKey を完全に再構築するため、プレフィックスをランダムにできません。そのため、元の RowKey またはその一部を使ってハッシュ値を計算し、そのハッシュ値をプレフィックスとして使用します。
一言で言えば、RowKey の設計では、長さの原則、一意性の原則、ソートの原則、ハッシュの原則を可能な限り保証する必要があります。
5. 実戦での緊急対応リンクシステム設計
サービス全体の高可用性を確保するには、フルリンクの視点から高可用性システムの設計を考える必要があります。ここでは、複数のアップストリームシステムが例外処理システムを呼び出して緊急対応を実行するビジネスシナリオを簡単に共有し、パフォーマンスの最適化と改造を分析します。
資金緊急対応システムを例に、システム設計プロセスでのパフォーマンス最適化を分析します。下図に示すように、例外処理システムには複数のアップストリームアプリ (1–N) が関与し、これらは「差異ログデータ」をメッセージキューに送信します。例外処理システムはメッセージキュー内の「エラーログデータ」を購読して消費し、このデータの解析、処理、集約などの操作を実行して、例外送信と緊急対応を完了します。
• 送信フェーズでの高可用性設計
• メッセージ生成段階:ローカルキューで例外詳細をキャッシュし、デーモンスレッドが定期的にプルしてバッチで送信します(最適化方案 1 の単一アイテム報告のパフォーマンス問題)
• メッセージ圧縮と送信:例外ルールの再利用に集約モデルを使用し、ルールに基づいてコードの集約、圧縮、レポートを行います(ビジネス層のデータ圧縮と再利用機能の最適化)
• ミドルウェアによる効率的なメッセージシリアル化メカニズムとゼロコピー送信技術
• ストレージフェーズ
• 現在、ApsaraMQ for Kafka などのミドルウェアは IO 多重化 + ディスクシーケンシャルデータ書き込みのメカニズムを採用して IO パフォーマンスを確保しています
• 同時に、パーティションとセグメントストレージメカニズムを使用してストレージパフォーマンスを向上させています
• 消費フェーズ
• 定期的にデータのバッチを取得してバッチ処理を行い、消費サイトにレポートしてさらなる計算を行います
• 内部でデータの冪等制御を行いやすくし、リリースプロセス中のジッターやシングルマシン障害時でもデータが再計算されないことを保証します
• DB の COUNT パフォーマンス向上のため、まず ApsaraDB for Hbase を使用して例外数を蓄積し、タイミングスレッドを使用してデータのバッチ更新を取得します
• DB の設定クエリパフォーマンス向上のため、初回クエリの設定をローカルメモリに 20 分間保存し、データ更新時にメモリを無効化します
• Explorer を統計計算の保存に、ApsaraDB for Hbase を非構造化例外詳細の保存に、OB を構造化された高信頼性例外データの保存に使用します
1. 次に、システムパフォーマンスに対して負荷テストとキャパシティ評価を実施し、テストデータ量が異常データの 3–5 倍の場合のフローを分離し、パイプラインを分割し、消費リンクのスレッドプールを分離します。
2. シングルポイントの計算モジュールに対して冗長性とフェールオーバーを行い、流量制限対策を施します。
流量制限キャパシティとして、レポート側ではスイッチで流量制限とサーキットブレーカーを制御します。
フェールオーバー機能。
3. システム内で改善可能な領域については、高可用性パフォーマンス最適化戦略を参照して、一つずつ突破を図ります。
6. 高性能設計のまとめ
1. アーキテクチャ設計
1.1 冗長性
クラスターの 3 レプリカまたは 5 レプリカのアクティブレプリケーションを行い、すべてのデータ冗長化シナリオの成功を確認してからタスクを続行します。可用性要件が高い場合は、レプリカ数を減らしてタスク送信実行の制約を緩和できます。
冗長性は理解しやすい概念です。1 つのシステムの可用性が 90% の場合、2 台の可用性は 1 - 0.1 × 0.1 = 99% になり、マシン数が多いほど可用性は高くなります。接続数にボトルネックがある DB では、データベース分割・テーブル分割のビジネスを徹底する必要があります。これも冗長性の水平方向スケーラビリティの一種です。
1.2 フェールオーバー機能
一部のビジネスシナリオは DB に強く依存しています。DB が利用不可になった場合、FO データベースに切り替えるか、一時的にサイトを中断し、コンテキストを保存して、現在のビジネスシナリオのコンテキストを遅延キューに書き込み、障害回復後にデータを消費して計算できます。
一部の不可抗力やサードパーティの問題は、ビジネス全体の可用性に深刻な影響を与える可能性があります。そのため、リモートマルチトーク、冗長ディザスタリカバリ、定期的な訓練を徹底する必要があります。
1.3 システムリソース分離
例外処理のケースでは、上流からの大量データレポートによりキューが詰まることが多く、適時性に影響します。そのため、コアビジネスと非コアビジネスのリソースを分離できます。セカンドキルシナリオでは、独立したクラスターをデプロイしてビジネスをサポートすることもできます。
システム A の可用性が 90%、システム B の可用性が 40% で、システム A のサービスがシステム B に強く依存している場合、システム A の可用性は P(A|B) となり、可用性が大幅に低下します。
2. 事前防御
2.1 モニタリング
システムの CPU、スレッド、IO、サービス呼び出し TPS、DB 計算時間などに対して合理的なモニタリングしきい値を設定し、問題発生時に緊急対応を行います。
2.2 流量制限/サーキットブレーカー/デグレード
上流ビジネストラフィックが急増した場合、一定の自己保護とサーキットブレーカーの仕組みが必要です。その前提として、ビジネスへの強い依存を避け、シングルポイント問題を解決する必要があります。異常消費リンクでは、上流に対して DRM 制御を行い、下流にも一定の迅速な負荷軽減能力を持たせ、単一のビジネス例外によりクラスター全体が利用不可になることを防ぎます。
瞬時のフロー問題は障害を引き起こしやすいため、電圧測定とサーキットブレーカーを確実に実施する必要があります。タイムセールビジネスではコアシステムへの強い依存を低減する必要があります。事前に計画の管理と制御を徹底し、キャッシュアバランシェに対するウォームアップと保護メカニズムも備える必要があります。
同時に、一部のビジネスでは不合理なインターフェースを公開しており、クローラーなどで大量のウェブインターフェースリクエストを行っています。これらにも識別とフューズの能力を持つ必要があります。
2.3 コード品質の向上
プロモーション期間中はコアビジネスのコードフリーズを行い、資金セキュリティを事前にデプロイしてアクティブ検証コードの信頼性を確認し、コードが仕様に準拠していることを確認します。これらはすべてオンライン問題を回避するための防御策です。
コードの Full GC やメモリリークはシステムを利用不可にします。特にビジネスの低ピーク期には目立たない場合があり、ビジネストラフィックが増加するとパフォーマンスが悪化します。事前に負荷テストとコードレビューを確実に実施してください。
3. 事後防御と回復
事前にモニタリングとグレーリリースを行い、事後はあらゆるシナリオで障害をロールバックします。
その他の防御機能には以下が含まれます。デプロイ中にコードのスムーズなリリースをどのように行うか、問題のあるコードマシンからトラフィックを迅速に切り上げる方法。上流・下流システム呼び出しのリリースについて依存順序をどのように確保するか。デプロイプロセス中、公開済みコードで正常なビジネスが実行され、未公開マシンで逆操作が実行されます。ビジネスの整合性をどのように確保するかを十分に考慮する必要があります。
資金検証用データアセンブリ実行の緊急対応リンクは、数千万 TPS の同時トランザクション量を処理しています。同時に、資金ビジネスの特性上、システムは可用性と精度に対して非常に高い要件を持っています。日々の開発プロセスでは、さまざまな高可用性の問題に直面し、システム設計とパフォーマンス最適化の取り組みを継続的に行っています。その中で、パフォーマンス最適化の経験と方法をまとめ、共有と意見交換を行い、今後も新たに遭遇する問題についてまとめと補足を続けていきます。
2. 高性能システムとは
まず、高性能設計とは何かを理解しましょう。公式な定義では、高可用性 (HA) の核心的な目標はビジネスの継続性を確保することです。ユーザーの視点では、ビジネスが常に正常かつ安定的にサービスを提供している状態です。業界では一般に、システムの可用性を「ナイン数」で尺度として衡量します。通常、冗長化やシングルポイント排除などの特別な設計を採用してビジネスのダウンタイムを削減し、コアサービスの高可用性を維持します。
高い同時実行性は、通常、システムが同時に多くのリクエストを並列処理できることを意味します。一般に応答時間、同時スループット TPS、同時接続ユーザ数などの指標で衡量されます。
高性能とは、プログラムの処理速度が非常に速く、メモリ消費が少なく、CPU 使用量が少ないことを意味します。高性能の指標は高い同時実行性の指標と密接に関連しています。パフォーマンスを向上させるには、システムの同時実行能力を向上させる必要があります。
本稿では、「高性能、高同時実行性、高可用性」サービスの設計について紹介と共有を行います。
3. パフォーマンスの向上方法
高性能設計について議論する際、IO 多重化、ゼロコピー、スレッドプール、冗長性などの用語がよく登場します。この部分に関する記事は多数ありますが、本質的にはシステム的な問題であり、コンピュータアーキテクチャの底層から考えることができます。システムの最適化は、コンピューティング性能 (CPU) とストレージ性能 (IO) の 2 つの次元から切り離すことができません。以下の方法をまとめます。
• 高性能コンピューティング (CPU) の設計方法
• 計算コストの削減:コード計算の時間計算量最適化 O(N^2) → O(N)、同期/非同期の合理的な使用、流量制限によるリクエスト数の削減
• より多くのコアを計算に参加させる:シングルスレッドからマルチスレッドへ、シングルマシンからクラスターへ
• システム IO の改善方法
• IO 速度の高速化:ランダム読み書きからシーケンシャル読み書きへ、ハードウェア面での SSD 導入など
• IO 回数の削減:インデックス/分散コンピューティングによるフルテーブルスキャンの代替、ゼロコピーによる IO コピー回数の削減、DB のバッチ読み書き、データベースとテーブル間の接続数増加
• IO ストレージの削減:データ有効期限ポリシー、メモリ、キャッシュ、DB などのミドルウェアの合理的な使用、適切なメッセージ圧縮
4. 高性能最適化戦略
1. コンピューティング性能の最適化戦略
1.1 プログラム計算の複雑さ削減
以下の擬似コードを見てみましょう(ビジネスコードは秘匿化済み)。
boolean result = true;
// リクエストの要求をループで走査し、A サービスかつ A サービスが最終状態に達していない場合は false を返し、それ以外の場合は true を返す
コードにはいくつかの明らかな問題があります。
1. リクエストが来るたびに 6 行目で DB をクエリしていますが、8 行目でリクエストの判定とフィルタリングを行っており、6 行目のコード計算リソースの無駄が生じています。さらに、6 行目の DAO データアクセスは時間のかかる操作です。まずビジネスが A に属するかを判定してから DB をクエリするようにできます。
2. 現在の要件では、1 つの A サービスが最終状態に達していないだけで false を返します。false を取得した後、11 行目は直接 break して計算回数を削減できます。
最適化後のコード
boolean result = true;
// リクエストの要求をループで走査し、A サービスかつ A サービスが最終状態に達していない場合は false を返し、それ以外の場合は true を返す
最適化後の計算時間は、平均 270.75 ms → 40.5 ms の範囲です。
日常的な最適化コードでは、ARTHAS ツールを使用してプログラムの呼び出しにかかる時間を分析できます。時間のかかるタスクは可能な限りフィルタリングし、不要なシステム呼び出しを削減する必要があります。
1.2 同期/非同期の合理的な使用
どのビジネスリンクが結果を同期的に待つ必要があり、どれが不要かを分析します。コア依存のスケジューリングは同期にでき、非コア依存のスケジューリングは可能な限り非同期にできます。
シナリオ:リンクの観点から、システム A がシステム B を呼び出し、システム B がシステム C を呼び出して計算を完了した後、システム A に結論を返します。システム A のタイムアウトは 400 ms です。通常、システム A からシステム B の呼び出しは 300 ms、システム B からシステム C の呼び出しは 200 ms です。
ここで、システム C がシステム D にも呼び出し結論を返す必要があり、150 ms かかります。
この時点で、システム A – システム B – システム C の既存の呼び出しリンクはタイムアウトで失敗する可能性があります。システム D の導入により時間消費が 150 ms 増加し、プロセス全体が同期であるため、システム D の更新結論に対する非強い依存を非同期呼び出しに変更する必要があります。
1.3 流量制限保護の徹底
障害シナリオ:システム A がシステム B を呼び出して異常データをクエリしており、日頃は約 10 TPS またはそれ以下でした。ある日、システム A がタイミングタスクのトリガーロジックを変更し、さらにコードのバグが重なり、呼び出し頻度が 500 TPS に達しました。さらに ID エラーにより、システム A がキャッシュをバイパスして直接 DB と ApsaraDB for Hbase をクエリし、ApsaraDB for Hbase の読み取りホットスポットを作成してクラスター全体を拖累し、ストレージとクエリに影響を及ぼしました。
その後、システム A に対してクエリ流量制限を実施し、同時実行数を 15 TPS 以内に収めました。コアビジネスサービスでは、クエリ流量制限保護とキャッシュ設計を徹底する必要があります。
1.4 シングルスレッドからマルチスレッドへ
シナリオ:緊急位置特定シナリオで、システム A がシステム B を呼び出して診断結論を取得します。TransitRouter のタイムアウトは 500 ms です。異常 ID イベントに対して、複数の診断サービスを実行し、診断フローを記録する必要があります。各診断は約 100 ms かかります。ビジネスの成長に伴い、5 つ以上の診断項目で 500 ms 以上の計算時間がかかるようになりました。この時点で、ピーク期間中にサービスが一時的に利用不可になります。
このコードを非同期実行に変更することで、診断時間が最も時間のかかる診断サービスの時間に収まります。
1.5 シングルマシンコンピューティングからクラスターコンピューティングへ
ここでは、3 層の分散を使用してコンピューティングタスクを分割し、実行できます。MapReduce は、シングルマシンの計算プレッシャーを軽減する 1 つの考え方です。
2. システム IO 性能の最適化戦略
2.1 一般的な Full GC の対策
システムでは一般的な Full GC 問題が多数存在します。まず、JVM のガベージコレクションメカニズムについて説明します。ヒープ領域は世代別に設計されており、Eden、Survivor、Tenured/Old に分割されます。Eden と Survivor は新世代に属し、Tenured/Old は旧世代に属します。一般に、新世代での GC を Minor GC、旧世代での GC を Major GC、ヒープ全体での GC を Full GC と呼びます。
メモリ割り当て戦略:1. オブジェクトはまず Eden 領域に割り当てられます。2. 大きなオブジェクトは直接旧世代に入ります。3. 長期間生存するオブジェクトは旧世代に入ります。4. 動的オブジェクトの年齢判定(仮想マシンは常にオブジェクトが MaxTenuringThreshold に達することを要求するわけではなく、Survivor 領域内の同じ年齢のすべてのオブジェクトのサイズ合計が Survivor の半分より大きい場合、その年齢以上のオブジェクトは直接旧世代に入ることができます)。5. 旧世代の連続空き領域が(新世代の全オブジェクトの合計サイズまたは過去の全プロモーションの平均サイズ)より大きい場合は Minor GC が実行され、それ以外の場合は Full GC が実行されます。
システムで Full GC が一般的にトリガーされるケース:
(1) 大きなオブジェクトのクエリ:ビジネス内の過去の巡回データは定期的にクリーンアップする必要があります。削除戦略は、毎日先月以前のデータを削除し(ビジネスではソフトデリートマークでマーク)、データベースの定期クリーンアップ時にデータを完全に回収します。
ある日、削除ポリシーが「先月以前のデータを削除」から「先週以前のデータを削除」に変更されました。その結果、削除されるデータが 1,000 件から 150,000 件に拡大し、データオブジェクトがメモリの 80% 以上を占有し、システムの Full GC が直接引き起こされ、他のタスクにも影響が及ぼされました。
多くのシステムコードでは、クエリするデータ件数に上限が設定されていません。ビジネスの継続的な成長に伴い、システムキャパシティの増加に対してアップグレードが追いつかず、大量のラージオブジェクトリストがクエリされ、ラージオブジェクトが頻繁に GC されます。
(2) 回収されない静的メソッドの設定
システム A では静的 List オブジェクトを設定し、DRM 設定読み取りに使用していました。しかし、設定情報をクエリしてから Put 操作を実行するロジックが存在しました。ビジネスの成長に伴い、静的オブジェクトはますます大きくなり、クラスオブジェクトに属するため回収できず、最終的にシステムで頻繁な GC が発生しました。
オブジェクトをマップのキーとして使用するのは不合理です。同時に、キー内のオブジェクトは回収できず、GC が発生します。
Full GC 実行後でも空き領域が不十分な場合、次のエラー [java.lang.OutOfMemoryError: Java heap space] がスローされます。上記 2 つの状況による Full GC を回避するため、チューニングでは Minor GC 段階で可能な限りオブジェクトを回収し、オブジェクトは新世代で一定期間生存させ、過度なオブジェクトや配列を作成しないようにする必要があります。
2.2 ランダム読み書きからシーケンシャル読み書きへ
一般的なメカニカルハードディスクでは、ランダム書き込みの性能は非常に悪く、長時間使用後に断片化が発生します。シーケンシャル書き込みは、ディスクのシーク時間とディスク回転時間を大幅に節約し、性能を大幅に向上させます。この層は実際にはミドルウェア自体によって実装されています。たとえば、ApsaraMQ for Kafka のログファイルは、メッセージをシーケンシャルに書き込み、ファイル末尾に追加することでメッセージを保存しています。
2.3 DB インデックス設計
テーブル構造を設計する際は、後段階でのテーブルデータに対するクエリ操作を考慮し、合理的なインデックス構造を設計する必要があります。テーブルのインデックスを確立した後は、後続のクエリ操作がインデックスの無効化を招かないよう注意する必要もあります。
(1) キー値の少ない列は選択しないようにしてください。つまり、明らかな識別性がない場合や、重複データが少ない場合はインデックスを作成しないでください。たとえば、is_delete 列にインデックスを作成して 100,000 件のデータをクエリする場合、is_delete=0 のデータが 90,000 件あると、インデックスブロックへのアクセスコストを考慮すると、フルテーブルスキャンですべてのデータブロックを走査する方が効率的です。
(2) 先頭の like "%***" や like "%***%" の使用は避けてください。前方のマッチングがあいまいなため、インデックス順序を使用してデータブロックにアクセスすることが難しく、フルテーブルスキャンが発生します。ただし、like "A***%" の使用には影響がありません。"B" で始まるデータに遭遇した時点で列の検索を停止できるからです。ユーザー情報に基づくあいまい検索でデータを探す際に、インデックスの無効化に遭遇しました。
(3) その他の可能なシナリオとして、OR クエリ、複数列インデックスでクエリの最初の部分を使用しない場合、クエリ条件に計算操作がある場合、またはフルテーブルスキャンがインデックスクエリよりも速い場合があります。
現在、AntMonitor や Tars などのツールが、長時間かかる SQL や CPU を多く消費する SQL をスキャンしてくれています。実行計画に従ってクエリロジックを調整できます。少量データに対する頻繁なクエリでは、インデックスを有効活用できます。もちろん、インデックスを多く構築しすぎるとストレージコストもかかります。INSERT や DELETE が頻繁なビジネスでは、不要なインデックス設計を削減することも考慮する必要があります。
2.4 データベース分割・テーブル分割の設計
ビジネスの成長に伴い、クラスター内のノード数が多くなりすぎると、最終的にデータベース接続の上限に達します。その結果、クラスター内のノード数がデータベース接続数に制限され、クラスターノードを増やして拡張できなくなり、ビジネストラフィックの継続的な成長に対応できなくなります。これは Ant が LDC アーキテクチャを採用する理由の 1 つです。ビジネス層で水平分割と拡張を行い、各 cell のノードが現在のノードに対応するデータベースのみにアクセスするようにしています。
2.5 大量のテーブル JOIN の回避
Alibaba コーディング仕様では、3 つ以上のテーブルの JOIN は禁止されています。3 つのテーブルのデカルト積計算により、演算の複雑さが幾何学的に増加するためです。複数のテーブルを JOIN する場合は、関連フィールドにインデックスがあることを確認してください。
ビジネスでデータをカスケードしたい場合は、プライマリキーに基づいてメモリ内でネストされたクエリと計算を適切に実行できます。操作が非常に頻繁なパイプラインテーブルでは、一部のフィールドを冗長化して、空間計算量を時間計算量と交換することをお勧めします。
2.6 ビジネスフローテーブルでの時間のかかる計算の削減
ビジネスレコードでは count 操作を実行することがあります。適時性の要件が高くない統計や計算については、定期タスクがビジネスの低ピーク期間に計算を実行し、計算結果をキャッシュに保存することをお勧めします。
複数のテーブルの JOIN が伴う場合は、オフラインテーブルを使用して MapReduce 計算を行い、計算結果をオンラインテーブルに戻して表示することをお勧めします。
2.5 データ有効期限ポリシー
テーブルのデータ量が大きすぎる場合、インデックスと日付に基づく部分スキャンが行われず、フルテーブルスキャンが発生すると、DB のクエリ性能が大幅に低下します。合理的なデータ有効期限戦略を設計することをお勧めします。既存データは定期的に履歴テーブルに配置するか、オフラインテーブルにコピーして、大量のデータのオンラインストレージを削減する必要があります。
2.6 メモリの合理的な使用
よく知られているように、リレーショナルデータベース DB のクエリの底層はディスクストレージであり、メモリキャッシュよりも低速です。キャッシュ DB とビジネスシステムの間の接続には一定の呼び出し時間がかかり、ローカルメモリよりも低速です。ただし、ストレージ容量の面では、メモリのデータ保存容量はキャッシュよりも低くなります。長期的な永続データはディスク上の DB に保存することをお勧めします。設計プロセスでは、コストとクエリ性能のバランスを考慮する必要があります。
メモリに関しては、データ整合性の問題が発生します。DB データとメモリデータの整合性をどのように確保するか、強力な整合性か弱い整合性か、データの保存順序とトランザクションをどのように制御するか、ユーザーにできるだけ意識させないようにするかを検討する必要があります。
2.7 データ圧縮
多くのミドルウェアは、データのストレージと転送に圧縮と展開の操作を採用して、データ転送時の帯域幅コストを削減しています。ここではデータ圧縮について詳しくは紹介しません。1 つ触れておきたいのは、高い同時実行性で稼働するビジネスのログ出力です。トラブルシューティングを容易にするために、JSON.toJSONString(Object) をあまり多く出力しすぎると、ディスクが簡単にいっぱいになります。ログの容量有効期限ポリシーに基づくと回収も簡単になり、問題のトラブルシューティングがさらに不便になります。したがって、ログを合理的に使用することをお勧めします。エラーコードは簡略化し、コアビジネスロジックはサマリーログを出力できます。構造化データは、後続のモニタリングとデータ分析を容易にすることもできます。
ログを出力する際、いくつかの質問を考慮してください。誰かがログを見る可能性があるか、ログを見て何ができるか、各フィールドは必ず出力する必要があるか、問題がある場合にトラブルシューティングの効率を向上できるか。
2.8 ApsaraDB for Hbase のホットキー問題
ApsaraDB for Hbase は、高い信頼性、高性能、カラム指向、スケーラビリティを備えた分散型ストレージシステムであり、非リレーショナルデータベースです。ApsaraDB for Hbase のストレージ特性は以下の通りです。
1. 列数は動的に追加できます。列が空の場合はデータが保存されず、ストレージ容量を節約できます。
2. ApsaraDB for Hbase はデータを自動的に分割するため、データストレージは自動的に水平方向のスケーラビリティを確保できます。
3. ApsaraDB for Hbase は高い同時実行性の読み書き操作をサポートできます。分散アーキテクチャでは、読み書きロックの待機確率が大幅に低下します。
4. 条件付きクエリはサポートされておらず、RowKey によるクエリのみサポートされています。
5. Master サーバーのフェールオーバーは一時的にサポートされておらず、Master サーバーがダウンするとストレージシステム全体が利用不可になります。
ApsaraDB for Hbase のストレージ構造は以下の通りです。テーブルは行方向に複数の HRegion に分割されます。HRegion は ApsaraDB for Hbase における分散ストレージと負荷分散の最小単位です。つまり、異なる HRegion は異なる HRegionServer 上に配置できますが、同じ HRegion を複数の HRegionServer に分割することはできません。HRegion はサイズに基づいて分割されます。各テーブルは通常 1 つの HRegion から始まります。テーブルにデータが挿入されるにつれて、HRegion は増加します。HRegion の列ファミリーがしきい値 (デフォルト 256 MB) に達すると、2 つの新しい HRegion に分割されます。
ApsaraDB for Hbase の行は RowKey の辞書順でソートされています。この設計によりスキャン操作が最適化され、関連する行や一緒に読み取られる行が近くに配置されるため、効率的なスキャンが可能になります。RowKey のこの設計がホットスポット障害の原因でもあります。ホットスポットとは、大量のクライアントがクラスター内の 1 つまたは少数のノードに直接アクセスする状態を指します(アクセスは読み取り、書き込み、またはその他の操作の可能性があります)。
大量のアクセスにより、ホットスポットが存在する単一マシンのキャパシティを超え、パフォーマンスの低下やリージョンの利用不可を引き起こす可能性があります。これは同じ RegionServer 上の他のリージョンにも影響を及ぼします。ホストが他のリージョンからのリクエストを処理できなくなるため、データホットスポット(データスキュー)が発生します。
したがって、ApsaraDB for Hbase にデータを挿入する際は、RowKey の設計を最適化して、データがクラスター内の複数のリージョンに書き込まれるようにする必要があります。レコードを異なるリージョンに均等に分散し、各リージョンの負荷を平準化するよう努める必要があります。
ホットキー回避の一般的な方法:反転、加塩、ハッシュ化
• 反転:たとえば、ユーザー ID のプレフィックス 2088 や BBCRL の先頭の同じプレフィックスを反転させて後ろに移動します。
• 加塩:RowKey の先頭にタイムスタンプ Hash などのプレフィックスを追加します。追加するプレフィックスの種類が多いほど、ランダムに生成されたプレフィックスに従って各リージョンに分散され、ホットスポットを回避できますが、スキャンの利便性も考慮する必要があります。
• ハッシュ化:ビジネス上で RowKey を完全に再構築するため、プレフィックスをランダムにできません。そのため、元の RowKey またはその一部を使ってハッシュ値を計算し、そのハッシュ値をプレフィックスとして使用します。
一言で言えば、RowKey の設計では、長さの原則、一意性の原則、ソートの原則、ハッシュの原則を可能な限り保証する必要があります。
5. 実戦での緊急対応リンクシステム設計
サービス全体の高可用性を確保するには、フルリンクの視点から高可用性システムの設計を考える必要があります。ここでは、複数のアップストリームシステムが例外処理システムを呼び出して緊急対応を実行するビジネスシナリオを簡単に共有し、パフォーマンスの最適化と改造を分析します。
資金緊急対応システムを例に、システム設計プロセスでのパフォーマンス最適化を分析します。下図に示すように、例外処理システムには複数のアップストリームアプリ (1–N) が関与し、これらは「差異ログデータ」をメッセージキューに送信します。例外処理システムはメッセージキュー内の「エラーログデータ」を購読して消費し、このデータの解析、処理、集約などの操作を実行して、例外送信と緊急対応を完了します。
• 送信フェーズでの高可用性設計
• メッセージ生成段階:ローカルキューで例外詳細をキャッシュし、デーモンスレッドが定期的にプルしてバッチで送信します(最適化方案 1 の単一アイテム報告のパフォーマンス問題)
• メッセージ圧縮と送信:例外ルールの再利用に集約モデルを使用し、ルールに基づいてコードの集約、圧縮、レポートを行います(ビジネス層のデータ圧縮と再利用機能の最適化)
• ミドルウェアによる効率的なメッセージシリアル化メカニズムとゼロコピー送信技術
• ストレージフェーズ
• 現在、ApsaraMQ for Kafka などのミドルウェアは IO 多重化 + ディスクシーケンシャルデータ書き込みのメカニズムを採用して IO パフォーマンスを確保しています
• 同時に、パーティションとセグメントストレージメカニズムを使用してストレージパフォーマンスを向上させています
• 消費フェーズ
• 定期的にデータのバッチを取得してバッチ処理を行い、消費サイトにレポートしてさらなる計算を行います
• 内部でデータの冪等制御を行いやすくし、リリースプロセス中のジッターやシングルマシン障害時でもデータが再計算されないことを保証します
• DB の COUNT パフォーマンス向上のため、まず ApsaraDB for Hbase を使用して例外数を蓄積し、タイミングスレッドを使用してデータのバッチ更新を取得します
• DB の設定クエリパフォーマンス向上のため、初回クエリの設定をローカルメモリに 20 分間保存し、データ更新時にメモリを無効化します
• Explorer を統計計算の保存に、ApsaraDB for Hbase を非構造化例外詳細の保存に、OB を構造化された高信頼性例外データの保存に使用します
1. 次に、システムパフォーマンスに対して負荷テストとキャパシティ評価を実施し、テストデータ量が異常データの 3–5 倍の場合のフローを分離し、パイプラインを分割し、消費リンクのスレッドプールを分離します。
2. シングルポイントの計算モジュールに対して冗長性とフェールオーバーを行い、流量制限対策を施します。
流量制限キャパシティとして、レポート側ではスイッチで流量制限とサーキットブレーカーを制御します。
フェールオーバー機能。
3. システム内で改善可能な領域については、高可用性パフォーマンス最適化戦略を参照して、一つずつ突破を図ります。
6. 高性能設計のまとめ
1. アーキテクチャ設計
1.1 冗長性
クラスターの 3 レプリカまたは 5 レプリカのアクティブレプリケーションを行い、すべてのデータ冗長化シナリオの成功を確認してからタスクを続行します。可用性要件が高い場合は、レプリカ数を減らしてタスク送信実行の制約を緩和できます。
冗長性は理解しやすい概念です。1 つのシステムの可用性が 90% の場合、2 台の可用性は 1 - 0.1 × 0.1 = 99% になり、マシン数が多いほど可用性は高くなります。接続数にボトルネックがある DB では、データベース分割・テーブル分割のビジネスを徹底する必要があります。これも冗長性の水平方向スケーラビリティの一種です。
1.2 フェールオーバー機能
一部のビジネスシナリオは DB に強く依存しています。DB が利用不可になった場合、FO データベースに切り替えるか、一時的にサイトを中断し、コンテキストを保存して、現在のビジネスシナリオのコンテキストを遅延キューに書き込み、障害回復後にデータを消費して計算できます。
一部の不可抗力やサードパーティの問題は、ビジネス全体の可用性に深刻な影響を与える可能性があります。そのため、リモートマルチトーク、冗長ディザスタリカバリ、定期的な訓練を徹底する必要があります。
1.3 システムリソース分離
例外処理のケースでは、上流からの大量データレポートによりキューが詰まることが多く、適時性に影響します。そのため、コアビジネスと非コアビジネスのリソースを分離できます。セカンドキルシナリオでは、独立したクラスターをデプロイしてビジネスをサポートすることもできます。
システム A の可用性が 90%、システム B の可用性が 40% で、システム A のサービスがシステム B に強く依存している場合、システム A の可用性は P(A|B) となり、可用性が大幅に低下します。
2. 事前防御
2.1 モニタリング
システムの CPU、スレッド、IO、サービス呼び出し TPS、DB 計算時間などに対して合理的なモニタリングしきい値を設定し、問題発生時に緊急対応を行います。
2.2 流量制限/サーキットブレーカー/デグレード
上流ビジネストラフィックが急増した場合、一定の自己保護とサーキットブレーカーの仕組みが必要です。その前提として、ビジネスへの強い依存を避け、シングルポイント問題を解決する必要があります。異常消費リンクでは、上流に対して DRM 制御を行い、下流にも一定の迅速な負荷軽減能力を持たせ、単一のビジネス例外によりクラスター全体が利用不可になることを防ぎます。
瞬時のフロー問題は障害を引き起こしやすいため、電圧測定とサーキットブレーカーを確実に実施する必要があります。タイムセールビジネスではコアシステムへの強い依存を低減する必要があります。事前に計画の管理と制御を徹底し、キャッシュアバランシェに対するウォームアップと保護メカニズムも備える必要があります。
同時に、一部のビジネスでは不合理なインターフェースを公開しており、クローラーなどで大量のウェブインターフェースリクエストを行っています。これらにも識別とフューズの能力を持つ必要があります。
2.3 コード品質の向上
プロモーション期間中はコアビジネスのコードフリーズを行い、資金セキュリティを事前にデプロイしてアクティブ検証コードの信頼性を確認し、コードが仕様に準拠していることを確認します。これらはすべてオンライン問題を回避するための防御策です。
コードの Full GC やメモリリークはシステムを利用不可にします。特にビジネスの低ピーク期には目立たない場合があり、ビジネストラフィックが増加するとパフォーマンスが悪化します。事前に負荷テストとコードレビューを確実に実施してください。
3. 事後防御と回復
事前にモニタリングとグレーリリースを行い、事後はあらゆるシナリオで障害をロールバックします。
その他の防御機能には以下が含まれます。デプロイ中にコードのスムーズなリリースをどのように行うか、問題のあるコードマシンからトラフィックを迅速に切り上げる方法。上流・下流システム呼び出しのリリースについて依存順序をどのように確保するか。デプロイプロセス中、公開済みコードで正常なビジネスが実行され、未公開マシンで逆操作が実行されます。ビジネスの整合性をどのように確保するかを十分に考慮する必要があります。
Related Articles
-
A detailed explanation of Hadoop core architecture HDFS
Knowledge Base Team
-
What Does IOT Mean
Knowledge Base Team
-
6 Optional Technologies for Data Storage
Knowledge Base Team
-
What Is Blockchain Technology
Knowledge Base Team
Explore More Special Offers
-
Short Message Service(SMS) & Mail Service
50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00
