Myntra の価格設定マシンは、多様な商品の多様な割引をアップロードし、それらを複数のサービスや製品に提供する責任があります。 現在、プライシング マシンは、何千ものトラフィックに対して 150 ミリ秒のレイテンシ で、低コストの知識を提供しています。 。 ライジングスケールとマスト低コストの知識をいくつかの多様なシステムに普及させ、増加した負荷に対処するためにマシンをスケーリングする必要があります。その回復力、堅牢性、および耐障害性を宣言します。 同期フローで取得できる価格設定の知識を必要とする新しい側面が多数開発されています。 これらすべての側面を可能にするために、私たちの価格設定マシンは、10 の に対応できるように拡張する必要があります。 数千のリクエストをわずか 30 ミリ秒のレイテンシで処理.
- 価格設定ガジェットは次のパーツで構成されています:-
- 作物支援ラベルの作成者プロバイダー:- 作物支援ラベルの作成者プロバイダーは、売り手が多様な商品の割引をアップロードするための、特定の人にとって快適なインターフェース。 サービスのバックエンド レイヤーは、これらの削減を処理し、Redis Cache および Sql トランザクション ナレッジ リテール内に保存して、すぐに効率的に取得できるようにします。 さらに、このサービスは、Crop support label Injector Provider スケジュールに基づいて Kafka キューを介して、クロップ サポート ラベル インジェクター プロバイダーがサービング レイヤーに取得可能な削減を作成できるようにし、中断-顧客が正しいエントリーを取得したことを確認します-
- 作物支援ラベル インジェクター プロバイダー:- クロップ サポート ラベル インジェクター プロバイダーは、クロップ サポート ラベル クリエーター プロバイダーの間の重要な仲介者として機能します。 と 作物サポート ラベル フルフィルメント プロバイダー。 Crop サポート ラベル Creator Provider のスケジュールされたジョブによって発行された Kafka イベントを検出して処理する責任があります。 次に、このサービスは、Crop サポート ラベルの Fulfillment Provider の Redis キャッシュと MongoDB 内に適切な知識を保存し、当面の間、すべての製品の積極的な削減が維持されるようにします。 これにより、有効な時間の更新と、廃止された顧客の最新の割引の効率的な検索が可能になります。
- Crop support label Fulfillment Provider:- Crop support label Fulfillment Provider は、エントリーの正しい取得の重要なポイントとして機能します。下流のサービスと製品に削減を提供するため。 その重要な役割は、Redis キャッシュまたは MongoDB から重要なものとして知識を取得することにより、要求された削減を効果的に取得してサポートすることです。 キャッシュは クロップ サポート ラベル インジェクター プロバイダー によって読み込まれます。知識は常に最新かつ適切であり、生産中止のお客様に繊細で効率的な専門知識を提供します.
- 以前の接続の最小決定は (24 (X+Y)).
解決策:- さまざまなトラフィックが最大に処理されるため、現在、美しい量のソースを mongo クライアントに割り当て、より多くのソースをレタスに割り当てています。 Redisによって。 Mongo クライアントの最大接続プール サイズと最小接続プール サイズが 4 に減少したため、Mongo 接続の最大/最小の決定は (4 (X+Y)).
以下は、ハードル 1 とハードル 2 に対処するために現在検討しているアプローチです:-
- 手順 #1 :バッチ処理 (パイプライン処理) & フラッシングを公開する
- ユーティリティの起動ジョブまでのすべての設計、Redis への接続は一見確立され、その接続の自動フラッシュモードがオフになっているように見えます.
- 命令は、設定されたバッチサイズに沿って Redis にフラッシュされるようです。 この呼び出しは、ユーティリティ スレッドが応答の準備ができている非同期呼び出しのように見えます。
- ユーティリティ スレッドは、応答が得られるか、設定されたタイムアウトに達しました.
- さらに、リトライも実施します すべての Redis 呼び出しに対して構成されたタイムアウトを使用します。
レタス ライブラリは、パイプライン化に役立ちます。 非同期Redis呼び出しのデフォルト。 あるいは、パイプラインは 世界レベル で実装されます。ユーティリティ スレッドが同じパイプラインに命令を書き込み、レタスが 自動的にフラッシュします コミュニティ層への指示。 これは、バッチサイズとフラッシングのタイミング 命令 は アウトライン化できなくなりました ユーティリティ 。 このジョブをさらに変更するには、Redis の auto-flush モード 接続は オフ になり、フラッシュは 手動で実行された 特定の
バッチサイズまたは必要に応じて.
- 実装
ユーティリティ スレッドが次の質問を受け取ると、これは、場合によっては、クエリ内で表示されるすべての商品の説明をまとめてバッチ処理することもできます。 m 接続のパイプラインに。
これが示唆する欠点
Redis 呼び出しのタイムアウトは、バッチ サイズに合わせて構成されていますが、上記で説明したように、フラッシュされる命令に依存する理由はバッチサイズよりも大きくなり、次の要素が作成されます:
a) ますます Redis の再試行
ユーティリティ ファセットから発生し、2x または 3x の負荷 Redis サーバー上
b)ますます Redis リトライの失敗 がユーティリティ面から発生し、増加する n 呼び出しの数 Mongo へのサポートが落ちています。 私たちの Mongo インフラストラクチャと Mongo クライアントは、その価値のある負荷に対処するように構成されていないため、高い API レイテンシー で単純に中断する可能性があります。 および Redis と Mongo サーキット ブレーカー オープニング.
接続がスレッド間で共有され、1 つのスレッドがフラッシュを呼び出すと、多様なスレッドによって追加された命令もフラッシュされることを明らかにします。 あるスレッドの癖が、多様化したスレッドに影響を与えている容量はどれか。 これが示唆するように、すぐにフラッシュされる命令の決定は 動的 そして、設定されたバッチ サイズ よりも多くても、常に平和的であるべきです。要素。
- Ref :-
https://github.com/ lettuce-io/lettuce-core/wiki/Pipelining-and-describe-flushing
手順 #2 : 接続プールを使用したバッチ処理とフラッシュを公開する
- Lettuce には、非同期接続プーリングのための強化機能が組み込まれています。
実装
- ユーティリティ スレッドが質問を受け取ると、接続プールから接続を取得します (ある時点で初期化されます)。ユーティリティ起動のポイント)、その接続の自動フラッシュ特性をオフにします。
次に、その接続のパイプライン内で (クエリ内のすべての商品デモンストレーションの) 合計命令を準備およびバッチ化し、それらを Redis にフラッシュします (構成されたバッチサイズに従って)。 この呼び出しは非同期呼び出しであり、ユーティリティ スレッドは応答の準備ができています。
- スレッドは、応答が得られるか、構成されたタイムアウトが経過するまで待機します。 その後、スレッドは接続を解放し、接続は接続プールに戻されます。 再試行は、すべての Redis 呼び出しに対して構成されたタイムアウトで実装されます.
- これが示唆する欠点
これが示唆するトピックは、高質量では、ユーティリティRedis 接続の不足 を 内で体験できますプール、再試行しても。 接続の決定を増やすと、Redis とユーティリティの両方が 変更する接続の実質的な決定 、TIMED Ready スレッド の増幅につながります。 (IO スレッド)、高い CPU 使用率 (最大 98%) 、そして 増えた ユーティリティと Redis の間で 時間 前後に実行され、 で実行されます。高い APIレイテンシ.
Ref :-
https://lettuce.io/core/release/reference/#_connection_pooling
- 手順 #3 (最適な手順) : レタス公開インターフェイスによるバッチ処理の公開
- レタス インターフェースを公開するバッチ キューで複数の命令をキャッチし、トランスポートへの 1 回の書き込みでバッチをフラッシュします。
公開バッチ処理は 2 つの範囲でも有効になります :-
- describe インターフェイスに @BatchSize の注釈を付けることによるクラス レベルで、すべての解が得られます。バッチ処理の説明の一部です。
- CommandBatching を引数に追加することにより、容量レベルで。 手順はバッチ処理の記述に選択的に参加します。
この容量により、コミュニティコールの決定が必要であり、パフォーマンスを強化するために命令のバッチ処理を許可します。これが(*の説明です) これを決定することは、 シーケンシャルな同期 Redis & 多すぎるコミュニティ コールの規律を解決することを提案します. RedisFuture実装
- これにより、決定がバッチ キュー内の命令の数が構成されたバッチ サイズに達すると、フラッシュが行われるように見え、キュー内の命令の合計がコミュニティ レイヤーに書き込まれるようになります。
この容量には、レタスを実装するインターフェイスの定義が含まれています コマンド クラス lev で設定されたバッチ サイズを持つインターフェイス @BatchSize アノテーションを使用します。
そして、Redisを利用してこのインターフェースのオブジェクトを作成します。指定されたインターフェイスのプロキシ クラスを作成します。 このオブジェクトは、バッチ処理の習慣を持つ Redis 呼び出しを作成する元になります.
Redis 呼び出しは 2 つの手法で行われます:-キューイングあり: futures.add(customRedisBatchExecutor.hgetall(productDetailsCacheKey, CommandBatching.queue) ())) フラッシングあり : futures.add(customRedisBatchExecutor.hgetall(productDetailsCacheKey, CommandBatching.flush()))
/定義Commands インターフェイスを拡張し、必要なすべての重要なソリューションを 含むインターフェイスRedis Calls の製造
*/
@バッチサイズ(50)
public interface RedisBatchExecutor extends Commands {
なぜなら作物支援ラベルフルフィルメントプロバイダー は、その下流のサービスと製品に削減を提供するためのポイントへのエントリの重要な取得の正確さです。このテキストは、アーキテクチャとヒント Crop サポート ラベルの Fulfillment Provider 内に実装され、最小限の遅延で大量のトラフィックに効果的に対処できるようにします。
以下は です。遭遇したスケーリングのハードルとそのオプション:-
ハードル #1 : 順次同期 Redis 呼び出し
私たちは、Redis が私の側ですべての製品を必要とするようにするために、以前は同期容量を使用していました。 これにより、複数の商品を含む一括リクエストを処理するときに深刻な長さになりました。 50 の商品を含む一括クエリがあった場合、多様化した後に Redis への 50 の個別のリクエストを作成することになることを覚えておいてください。 これは、重要な製品に対する応答が得られるまで、2 番目の製品に対する Redis 呼び出しが行われないことを想定していました。 Redis 呼び出しごとに 3 ミリ秒の現実的なレイテンシーを使用すると、50 個の商品の一括クエリは、完全に 150 ミリ秒増加します
この分野へのアプローチについては、このテキストの後半で説明します.
ハードル #2 : コミュニティ コールが多すぎる
レタスを雇っていたので同期 Redis 呼び出しを作成するために、すべての呼び出しが一度にコミュニティ レイヤーに書き込まれていました。 すべての製品について Redis に単一のクエリを作成していたので、コミュニティ コールの決定は、クエリ内の商品デモンストレーションの決定と同等でした。 これにより、コミュニティ コールの決定率が高くなり、一括リクエストの処理が長くなる原因となりました。
この規律へのアプローチは、上記のものと同じであり、このテキストの後半で説明します. )
ハードル #3 : レイテンシ キャッピングなし
タイムアウトも再試行もありません が Redis 呼び出し 。以前は、一括リクエストの処理に一対の遅延が発生していました。 Redis 呼び出しに 100 ミリ秒かかっていた場合、2 回または 3 回の再試行で 30 ミリ秒のタイムアウトがさらに実装される可能性があることを覚えておいてください。 これにより、応答をより短い時間で受信できる可能性が高まり、おそらく遅延が減少し、全体的なパフォーマンスが向上する可能性があります.
解決策:- タイムアウトと再試行が行われました一般的な待ち時間に上限を設けるために、Redis 呼び出しのユーティリティ ファセットから追加されました。
ハードル #4 : Redisの読み取り設定
古い Redis 構成を使用 REPLICA_PREFERRED 読み取りの決定により、不均衡 読み取りトラフィックの 分布内 。 私たちのセットアップは、Redis マスター ノードの X 決定と Redis スレーブ ノードの Y 決定で構成され、マスターとスレーブの比率は 1:2 で、すべてのノードはパーティションの P 決定を持っていました。 REPLICA_PREFERRED の読み取り決定により、最大の (Y/2 P) トランスポート接続 を持つ単一のユーティリティ サーバーが得られました。 1 接続オブジェクトのジョブごと。 これは、1 つのユーティリティ サーバーからの読み取りトラフィック が は、 の代わりに Y/2 レプリカ に送信されます。 すべての Y 個の取得可能なレプリカ. この不均衡は、ユーティリティのパフォーマンスとスケーラビリティに悪影響を及ぼし、読み取りトラフィックのよりバランスの取れた分散の必要性を浮き彫りにしました.
(参照 :-
https://lettuce.io/core/release/reference/#redis-cluster.connection-rely
)
解決:- Redis 読み取り決定をレタス内で ANY に変更した結果、単一の接続オブジェクトが ((X+Y) P) トランスポート接続を持つようになりました.
ハードル #5 : より多くのソースを Mongo クライアントに割り当てる
Mongo クライアントに重要なソースよりも多くのソースを割り当てましたが、逆に最大 0.1%トラフィックの Mongo へのフォールバックが必要でした。 Mongo の最大接続プール サイズは 100 に設定され、最小プール サイズは 24 でした。X マスターと Y スレーブ Mongo ノードがあり、次の接続番号が得られました:
1 つのユーティリティ サーバーから Mongo への接続の最大の決定は、以前は (100 (X+Y)) でした。