検索結果、または25個のプロセッサコアをリリースした方法を具体化します。







少し前まで、Elasticsearchクラスターのリソース消費を最適化する問題を解決しました。 エラスティック自体の構成に失敗したため、「逆」検索またはパーコレーターと呼ばれるアプローチを使用して、検索結果のキャッシュのような処理を行いました。 カットの下で、メタデータメトリックとパーコレーター自体をどのように使用するかについてのストーリー。







私たちが開発している監視サービスの目的は、問題の原因を示すことです。そのため、クライアントインフラストラクチャのさまざまなサブシステムに関する多くの詳細なメトリックを削除します。







一方では、数千のホストから多数のメトリックを記録するという問題を解決します。他方では、メトリックはリポジトリ内で無重量ではなく、常に読み取られます。









メトリックとは何ですか?



okmeterの開発を始めたとき(当時、influxdbのパブリックバージョンはまだありませんでした)、メトリックが「フラット」であってはならないことがすぐにわかりました。 私たちの場合、メトリック識別子はキーと値のディクショナリです(私たちにとっては歴史的にlabel_setと呼ばれています)







{ "name": "nginx.requests.rate", "status": "403", "source_hostname": "front3", "file": "/var/log/access.log", "cache_status": "MISS", "url": "/order" }
      
      





このようなメトリックごとに、特定の時点(時系列)に関連付けられた値があります。







メトリックスを保存する方法



各メトリックのlabel_setからのハッシュに基づいて、文字列キーが計算され、これによりリポジトリ内のメトリックが識別されます。 そして、ここでは、キーによってメトリック値を保存するタスクと、メタメタ情報を保存および処理するタスクを分離します。













この記事ではメトリック値の保存については考慮しませんが、メタデータについて詳しく説明します。







メタメタデータは、キー自体、label_set、作成時間、更新時間、およびその他のサービスフィールドです。







この情報はcassandraに保存され、メトリックキーで受信できます。 メインのメタデータリポジトリに加えて、一部のユーザー検索クエリのメトリックキーのセットを返すインデックスがelasticsearchにあります。







記録メトリック



メトリックのパックがクライアントのサーバーにインストールされたエージェントから取得されると、各メトリックのサーバーで次のことが発生します。









指標の読み取り



メトリックを読み取るためのリクエストには、主に2つのソースがあります。グラフ化のためのユーザーリクエストとトリガー検証システムです。 このようなリクエストは、dslの一部の表現です。







 top(5, sum_by(url, metric(name=“nginx.requests.rate”, status=“5*”)))
      
      





この式には以下が含まれます。









さらに、リクエストは常に特定の時間間隔で機能します:[since_ts = X、to_ts = Y]









負荷とデータサイズ



現時点では、クラウドはレコードごとに1秒あたり10万以上のメトリックを処理しています。 Paskovyは平均で約350 rpsを要求します(トリガーの90%)。 各検索クエリは、1〜3個のESインデックス用で、各インデックスは100ミリン文書(〜30 GB)までです。







同時に、CPUエラスティックの消費により、ホスティングに費やされたお金を考慮する誰もが無関心になることはありません。













Elasticsearch



リクエストが繰り返される場合に備えて、組み込みのクエリキャッシュが作成されたことを期待して、elasticsearch設定を変更しようとしました。 これらの要求のキャッシュ無効化を防ぐために、一部の要求に対して更新が行われないインデックスをシミュレートしようとしました。







しかし、残念なことに、私たちのすべてのエクササイズは、消費されるリソースの減少も、エラスティックの応答時間の短縮ももたらしませんでした。







外部キャッシュ



ESの外部に検索結果のキャッシュを作成することを決定し、ESに関する次の要件を策定しました。









このような要件がある場合、ヒットレートがないことは明らかですが、ESレスポンスを1分間だけキャッシュすることができます。 その結果、キャッシュを行わないという結論に達しましたが、既知の各検索クエリの検索結果を含む実体化された表現のようなものです。







パーコレーター



アイデアは、メトリックの各レコードで、どの既知の検索クエリが一致するかをチェックするというものでした。 偶然の場合、メトリックはキャッシュに書き込まれます。

このようなアプローチは、 「前向き検索」、別名「逆検索」、別名「パーコレーター」と呼ばれます。

私が理解しているように、ここではプロセスの類似性のために「パーコレーション」という用語が使用されます。多くの検索クエリを通じてドキュメントの「フロー」を確認します。







通常の検索問題では、ドキュメントがあり、それらからインデックスを構築します。インデックスは、(非常に単純化された)各「単語」がこの単語が出現するドキュメントのリストに対応します。













パーコレーションの場合、以前に既知の検索クエリがあり、各ドキュメントは検索クエリです。













パーコレーターの実装:









パーコレーターが将来のドキュメントの構造を記述する特別なタイプのインデックスであるelasticsearchのみを考慮しました:ドキュメントが持つフィールドの種類とそのタイプ(マッピング)。 このインデックスにさらにリクエストを保存し、その後ドキュメントを入力に送信して検索します。







ES内では、各パーコレーションリクエストで、一時インデックスがメモリに作成されます。これは、提出した1つのドキュメントのみで構成されています。 保存されたすべてのクエリのうち、明らかにフィールドセットドキュメントに適さないクエリは破棄されます。 次に、残りの候補リクエストごとに、一時インデックスによって検索が実行されます。







単純なベンチマークでは、パーコレーターでの1つの要求への準拠について1つのドキュメントをチェックするために2〜10ミリ秒を受け取りました。 ドキュメントのストリームでは、これは非常に高価になります。 さらに、elasticsearchを「クック」する方法を学んだことはありません。







自家製ナイーブパーコレーター



メトリックに戻りましょう。 上で言ったように、私たちのドキュメントはキーバリュー辞書です。 検索クエリは、完全一致またはプレフィックスフィールドの一致による検索です。 つまり、そのため、全文検索は必要ありません。







パーコレーターの「単純な」実装、つまり、額の既知のすべての要求に対する各メトリックの対応を確認することにしました。 1秒あたり約10万メトリックの書き込みストリームがあり、各メトリックは約100クエリに準拠しているかどうかを確認する必要があります。







1つのチェックのベンチマーク(このコードの一部はgolangで動作し、プロトタイプを作成しました)は約300nsを示しました。 これは完全にCPUにバインドされたタスクであるため、時間を合計する権利があります。







100k * 100 = 10M





10M * 300ns = 3 = 3









キャッシュのロジックは次のようなものでした:











メトリックを記録するプロセスに追加の手順が追加されました。









新しいリクエストを登録した後、そのリクエストのキャッシュがすぐに有効にならないことに注意してください。 すでに開始されていて、既知の要求のリストに新しい要求が表示されていない書き込み要求が終了するまで待機する必要があります。 したがって、メトリックの書き込み要求のタイムアウトまでにキャッシュの初期化を延期します。







キャッシュはどのように配置されますか?



キャッシュをcassandraに保存します。各リクエストの結果は時間ごとに分割されます(各ピースは24時間です)。 これは、結果から停止したメトリックが確実に洗い落とされるようにするために行われます。









リクエストに応じて、関心のある時間間隔に該当する毎日のチャンクをすべて減算し、結果をメモリに結合します。







値は、メトリックキーディクショナリとlabel_setのjson表現です。 したがって、キャッシュからの結果を使用する場合、ESから結果を受信した後に行ったように、キーごとのメトリックデータについてもcassandraに追加で移動する必要はありません。







生産で展開



キャッシュをバトルに展開し、ほとんどのリクエストで有効になった後、ESの負荷が大幅に低下しました。













同時に、cassandraによるリソースの消費は変更されていません。













そして、パーコレーションを実行するバックエンドは、予測された〜3コアだけ成長しました。













おまけとして、キャッシュからの結果がESに移動してからCからメタ情報を取得するよりも5倍高速であることが判明したため、優れたレイテンシ最適化が得られました。













一貫性チェック



キャッシュロジックを混乱させないように、最初の数日間は検索結果をESとキャッシュの両方で調べ、結果を比較して適切なメトリックを作成しました。 負荷をキャッシュに切り替えた後、キャッシュ検証ロジックをカットアウトせず、リクエストの1%に対してESで投機的なリクエストを行いました。 同じリクエストはESにとっても「ウォーマー」です。そうしないと、ロードインデックスがなければページキャッシュに入らず、ユーザーリクエストはバカになります。







合計



外部キャッシュを作成するのではなく、ESが内部キャッシュを使用するように強制しました。 しかし、私はサイクリングに対処しなければなりませんでした。 しかし、プラスもあります。パーコレーターに追加のロジックを掛けます。







結果によると、私たちは腺でかなりうまくいきましたが、自家製のパーコレーターは非常にうまくスケーリングします。 これは、クライアントの数と各クライアントサーバーからのメトリックの数の両方で急速に成長しているため、私たちにとって十分に重要です。








All Articles