マイクロサービス面接質問#
** 面接官:**Spring Cloud の 5 大コンポーネントは何ですか?
候補者:
初期に一般的に考えられていた Spring Cloud の 5 大コンポーネントは
- Eureka : レジストリ
- Ribbon : 負荷分散
- Feign : リモート呼び出し
- Hystrix : サービスサーキットブレーカー
- Zuul/Gateway : ゲートウェイ
SpringCloudAlibba が国内で盛り上がるにつれて、私たちのプロジェクトではいくつかのアリババのコンポーネントを使用しました
レジストリ / 設定センター Nacos
負荷分散 Ribbon
サービス呼び出し Feign
サービス保護 sentinel
サービスゲートウェイ Gateway
** 面接官:** サービス登録と発見とは何ですか?Spring Cloud はどのようにサービス登録と発見を実現していますか?
候補者:
私の理解では、主に 3 つの大きな機能があり、それぞれサービス登録、サービス発見、サービス状態監視です。
私たちのプロジェクトでは eureka をレジストリとして使用しており、これは spring cloud システムの中核コンポーネントの 1 つです。
サービス登録:サービス提供者は自分の情報を eureka に登録する必要があり、eureka がこれらの情報を保存します。例えば、サービス名、IP、ポートなどです。
サービス発見:消費者は eureka からサービスリスト情報を取得します。サービス提供者がクラスターを持っている場合、消費者は負荷分散アルゴリズムを利用して 1 つを選択し、呼び出しを開始します。
サービス監視:サービス提供者は 30 秒ごとに eureka にハートビートを送信し、健康状態を報告します。もし eureka が 90 秒間ハートビートを受信しなければ、eureka から削除されます。
** 面接官:** あなたは以前 nacos を使用していたようですが、nacos と eureka の違いについて教えていただけますか?
候補者:
私たちのプロジェクト xx では nacos をレジストリとして採用しました。nacos を選んだもう 1 つの重要な理由は、設定センターをサポートしているからです。ただし、nacos はレジストリとしても eureka より便利で使いやすいです。主な相違点は以下の通りです:
- 共通点
Nacos と eureka はどちらもサービス登録とサービス取得をサポートし、サービス提供者のハートビート方式で健康チェックを行います。
- Nacos と Eureka の違い
①Nacos はサービス側が提供者の状態を積極的に検出することをサポートします:一時的インスタンスはハートビートモードを使用し、非一時的インスタンスは積極的検出モードを使用します。
②一時的インスタンスのハートビートが正常でない場合は削除されますが、非一時的インスタンスは削除されません。
③Nacos はサービスリストの変更に関するメッセージプッシュモードをサポートし、サービスリストの更新がより迅速です。
④Nacos クラスターはデフォルトで AP 方式を採用し、クラスター内に非一時的インスタンスが存在する場合は CP モードを採用します。Eureka は AP 方式を採用しています。
** 面接官:** あなたたちのプロジェクトでは負荷分散をどのように実現していますか?
候補者:
そうですね~~
サービス呼び出しプロセスでの負荷分散は一般的に SpringCloud の Ribbon コンポーネントを使用して実現されます。Feign の下層はすでに Ribbon を自動的に統合しており、非常に簡単に使用できます。
リモート呼び出しを開始する際、ribbon は最初にレジストリからサービスアドレスリストを取得し、一定のルーティング戦略に従って 1 つを選択してリモート呼び出しを開始します。一般的な呼び出し戦略はラウンドロビンです。
** 面接官:**Ribbon の負荷分散戦略にはどのようなものがありますか?
候補者:
考えてみますね、いくつかあります。いくつか覚えています:
RoundRobinRule:サービスリストを単純にラウンドロビンで選択します。
WeightedResponseTimeRule:重みを基にサーバーを選択し、応答時間が長いほど重みが小さくなります。
RandomRule:利用可能なサーバーをランダムに選択します。
ZoneAvoidanceRule:地域に敏感な戦略で、地域で利用可能なサーバーを基にサーバーを選択します。Zone を使用してサーバーを分類し、この Zone はデータセンターやラックなどと理解できます。その後、Zone 内の複数のサービスに対してラウンドロビンを行います(デフォルト)。
** 面接官:** 負荷分散戦略をカスタマイズしたい場合、どのように実現しますか?
候補者:
2 つの方法が提供されています:
1、IRule インターフェースを実装するクラスを作成し、負荷分散戦略を指定できます。これはグローバルで、すべてのリモート呼び出しに影響します。
2、クライアントの設定ファイルで、特定のサービス呼び出しの負荷分散戦略を設定できます。これは設定されたサービスにのみ有効です。
** 面接官:** サービスアバランチとは何ですか?この問題をどのように解決しますか?
候補者:
サービスアバランチとは、1 つのサービスが失敗することで、全体のチェーンのサービスがすべて失敗する状況を指します。一般的に、プロジェクトで解決する方法は 2 つの提案があります。1 つはサービスのダウングレード、もう 1 つはサービスのサーキットブレーカーです。トラフィックが非常に多い場合は、スロットリングを検討できます。
サービスダウングレード:サービスが自己保護する方法、または下流サービスを保護する方法であり、リクエストの急増によってサービスが利用できなくなることを防ぎ、サービスがクラッシュしないようにします。一般的に、実際の開発では feign インターフェースと統合し、ダウングレードロジックを記述します。
サービスサーキットブレーカー:デフォルトではオフになっており、手動でオンにする必要があります。10 秒以内にリクエストの失敗率が 50%を超えると、サーキットブレーカー機構がトリガーされます。その後、5 秒ごとにマイクロサービスへのリクエストを再試行します。マイクロサービスが応答しない場合は、サーキットブレーカー機構を継続します。マイクロサービスが到達可能な場合は、サーキットブレーカー機構をオフにし、通常のリクエストを回復します。
** 面接官:** あなたたちのマイクロサービスはどのように監視されていますか?
候補者:
私たちのプロジェクトでは skywalking を使用して監視しています。
1、skywalking は主にインターフェース、サービス、物理インスタンスの状態を監視できます。特に負荷テスト中に、多くのサービスの中でどのサービスやインターフェースが遅いかを確認でき、ターゲットを絞った分析と最適化が可能です。
2、私たちは skywalking にアラートルールを設定しました。特にプロジェクトが立ち上がった後にエラーが発生した場合、関連する責任者に SMS やメールを送信するように設定し、プロジェクトのバグ状況を即座に把握し、迅速に修正します。
** 面接官:** あなたたちのプロジェクトでスロットリングを行ったことはありますか?どのように行いましたか?
候補者:
私が当時行った xx プロジェクトは、マイクロサービスアーキテクチャを採用していました。xx のため、突発的なトラフィックが発生する可能性があり、最大 QPS は 2000 に達する可能性がありますが、サービスはそれに耐えられません。私たちのプロジェクトは、負荷テストを通じて最大 1200QPS を支えることができました。普段の QPS は 100 未満です。これらの突発的なトラフィックを解決するために、スロットリングを採用しました。
【バージョン 1】
私たちが当時採用した nginx のスロットリング操作は、nginx が漏れバケツアルゴリズムを使用してリクエストをフィルタリングし、リクエストを固定の速度で処理できるようにし、突発的なトラフィックに対応します。私たちが制御した速度は IP に基づいてスロットリングし、制限されたトラフィックは毎秒 20 です。
【バージョン 2】
私たちが当時採用したのは、spring cloud gateway でサポートされている部分フィルター RequestRateLimiter を使用してスロットリングを行い、トークンバケツアルゴリズムを使用して IP またはパスに基づいてスロットリングを行い、毎秒の平均充填速度とトークンバケツの総容量を設定できます。
** 面接官:** スロットリングの一般的なアルゴリズムにはどのようなものがありますか?
候補者:
一般的なスロットリングアルゴリズムには漏れバケツアルゴリズムとトークンバケツアルゴリズムがあります。
漏れバケツアルゴリズムはリクエストをバケツに格納し、固定の速度でバケツから流出させることで、サービスが絶対的な平均を実現し、良好なスロットリング効果を発揮します。
トークンバケツアルゴリズムでは、バケツにトークンを格納し、一定の速度でトークンを生成します。各リクエストは最初にトークンを申請し、トークンを取得した後に正常にリクエストを行うことができ、良好なスロットリング効果を発揮します。
彼らの違いは、漏れバケツとトークンバケツはどちらも突発的なトラフィックを処理できますが、漏れバケツは絶対的なスムーズさを実現でき、トークンバケツは突発的に大量のリクエストが発生する可能性があります。一般的に nginx のスロットリングは漏れバケツを使用し、spring cloud gateway ではトークンバケツアルゴリズムをサポートしています。
面接官:CAP 理論とは何ですか?
候補者:
CAP は主に分散プロジェクトにおける理論です。3 つの要素を含みます:一貫性、可用性、分割耐障害性。
一貫性(Consistency)は、更新操作が成功し、クライアントに完了を返した後、すべてのノードのデータが同時に完全に一致することを指します(強い一貫性)。中間状態が存在してはいけません。
可用性(Availability)は、システムが提供するサービスが常に利用可能な状態でなければならず、ユーザーの各操作リクエストは常に限られた時間内に結果を返すことができることを指します。
分割耐障害性(Partition tolerance)は、分散システムがネットワークの分割障害に遭遇した場合でも、一貫性と可用性を満たすサービスを外部に提供できることを指します。全体のネットワーク環境が故障しない限り。
面接官:なぜ分散システムでは一貫性と可用性を同時に保証できないのですか?
候補者:
うん、そうですね~~
まず前提として、分散システムにおいて分割耐障害性は最も基本的な要求です。したがって、分散システムを設計する際には、一貫性(C)と可用性(A)の間で妥協する必要があります。
一貫性(C)を保証する場合:ノード N1 と N2 に対して、N1 にデータを書き込むとき、N2 での操作は一時停止しなければなりません。N1 がデータを N2 に同期するまで、N2 に対する読み書きリクエストはできません。N2 が操作を一時停止している間、クライアントが送信したリクエストは失敗またはタイムアウトの応答を受け取ります。明らかに、これは可用性と矛盾します。
可用性(A)を保証する場合:N2 の読み書き操作を一時停止することはできませんが、同時に N1 がデータを書き込む場合、これは一貫性の要求に反します。
面接官:BASE 理論とは何ですか?
候補者:
うん、これも CAP の分散システム設計理論です。
BASE は CAP 理論の AP アプローチの延長であり、核心的な考え方は、強い一貫性(StrongConsistency、CAP の一貫性は強い一貫性)を実現できなくても、アプリケーションが適切な方法で最終的な一貫性(Eventual Consistency)を達成できるということです。この考え方は 3 つの側面を含みます:
1、Basically Available(基本的に利用可能):基本的に利用可能とは、分散システムが予測できない障害が発生した場合に、一部の可用性を失うことを許容しますが、システムが利用できないことを意味するわけではありません。
2、Soft state(ソフトステート):システム内のデータが中間状態を持つことを許可し、その中間状態の存在がシステム全体の可用性に影響を与えないと見なします。つまり、異なるノード間でデータの同期プロセスに遅延が存在することを許可します。
3、Eventually consistent(最終的一貫性):システム内のすべてのデータのコピーが、一定の時間の同期後に最終的に一貫した状態に達することを強調します。本質的には、システムが最終的にデータが一貫性を持つことを保証する必要があり、リアルタイムで強い一貫性を保証する必要はありません。
** 面接官:** あなたたちはどのような分散トランザクション解決策を採用していますか?
候補者:
私たちは当時の xx プロジェクトで、主に seata の at モードを使用して分散トランザクションを解決しました。
seata の AT モデルは 2 つの段階に分かれています:
1、段階 1 の RM の作業:① 分岐トランザクションを登録 ② undo-log(データスナップショット)を記録 ③ ビジネス SQL を実行し、コミット ④ トランザクション状態を報告
2、段階 2 のコミット時の RM の作業:undo-log を削除するだけです。
3、段階 2 のロールバック時の RM の作業:undo-log に基づいてデータを更新前に復元します。
at モードは一貫性を犠牲にし、可用性を保証しますが、最終的な一貫性を保証します。
** 面接官:** 分散サービスのインターフェースの冪等性はどのように設計されていますか?
候補者:
うん、私たちの xx プロジェクトの注文操作では、token+redis を使用して実現しました。プロセスは次のようになります。
最初のリクエスト、つまりユーザーが商品詳細ページを開いたとき、私たちはリクエストを発起し、バックエンドで一意のトークンを生成して redis に保存します。キーはユーザーの ID、値はこのトークンです。同時に、このトークンをフロントエンドに返します。
2 回目のリクエスト、ユーザーが注文操作をクリックすると、以前のトークンを持ってバックエンドは最初に redis で検証します。トークンが存在する場合、ビジネスを実行し、トークンを削除します。存在しない場合は、直接返し、ビジネスを処理せず、同じトークンが 1 回だけビジネスを処理することを保証し、冪等性を保証します。
** 面接官:**xxl-job のルーティング戦略にはどのようなものがありますか?
候補者:
xxl-job は多くのルーティング戦略を提供しており、私たちが普段よく使用するのは:ラウンドロビン、フェイルオーバー、シャーディングブロードキャスト…
** 面接官:**xxl-job のタスク実行失敗をどのように解決しますか?
候補者:
いくつかの操作があります。
第一に、ルーティング戦略としてフェイルオーバーを選択し、健康なインスタンスを優先してタスクを実行します。
第二に、まだ失敗がある場合、タスクを作成する際に再試行回数を設定できます。
第三に、まだ失敗がある場合は、ログを確認するか、メールアラートを設定して関連する責任者に通知し、解決を促します。
** 面接官:** 大量のデータを持つタスクを同時に実行する必要がある場合、どのように解決しますか?
候補者:
私たちは複数のインスタンスを展開し、これらのバッチタスクを共同で実行します。その際、タスクのルーティング戦略はシャーディングブロードキャストです。
タスク実行のコード内で、シャードの総数と現在のシャードを取得し、モジュロ演算の方法で各インスタンスに分配して実行できます。