メッセージ キュー パルサー、ストレージ システム ブックキーパー、SQL クエリ エンジン Presto

pulsar と kafka の最も明らかな違いは、pulsar がマルチテナンシーをサポートし、アセットと名前空間の概念を備えていることです。アセットはシステム内のテナントを表します。Pulsar クラスターが複数のアプリケーション (Yahoo など) をサポートするために使用されていると仮定すると、クラスター内の各資産は組織チーム、コア機能、または製品ラインを表すことができます。アセットには複数の名前空間を含めることができ、名前空間には任意の数のテーマを含めることができます。

 

パーティション: pulsar と kafka はどちらもトピックのマルチパーティション化をサポートしています。

永続性: kafka ファイル ストレージ、パルサーは Apache BookKeeper ストレージを使用します。これは、パルサーの重要な利点でもあります。Kafka ファイル ストレージは、クラスター内の各ブローカーに分散されます。ブローカーがハングアップするか、新しいブローカーが参加すると、レプリカのリーダー選出またはパーティション バランシング操作が実行され、カフカのパフォーマンス。pulsar のブローカーはステートレスで、データは BookKeeper に保存され、サービスとデータは分離されています。したがって、この種の問題に直面することはなく、クラスターを自由に調整できます。さらに、Kafka のブローカーは、ストレージ容量が自身のハードディスクの容量を超えているかどうかも考慮します。しかし、パルサーにはこの問題はありません。

リリースされたバージョン 2.2 では、Pulsar に SQL クエリと Pulsar に保存されたデータの分析を容易にする SQL が導入されます。Pulsar SQL は Presto を活用して、目的に応じて効率的でスケーラブルなクエリを提供します。この効率的なクエリは主に、Pulsar の基盤となるストレージ システムである Apache BookKeeper によるものです。

 

「Pulsar(カフカ新世代メッセージシステムへの挑戦)公式ドキュメント翻訳~エントリーと実戦~ローカル独立クラスタ環境の構築」

「Pulsar(Challenge Kafka 新世代メッセージングシステム)公式ドキュメント翻訳~初心者必見~コンセプトとアーキテクチャ~(2) メッセージングの概念」

Apache Bookkeeper は、分散型、スケーラブル、フォールトトレラント (マルチコピー)、低遅延ストレージ システムであり、高性能、高スループットのストレージ機能を提供します。Bookkeeper は、追加モードで書き込み操作を実装します。

Bookkeeper には非常に成功したアプリケーション ケースがあります: Apache Pulsar は、Yahoo が近年オープンソース化した MQ です。Kafka と比較して、Pulsar はストレージに利点があります。Kafka の単一パーティションのストレージ容量は、パーティションのハードディスク容量によって制限されます。 Kafka をデプロイするブローカー。MQ サポートを必要とするデータが大量にある場合、パーティションがボトルネックに遭遇し、拡張できない可能性があります。もちろん、MQ のストレージ要件を満たすためにパーティションとブローカーの数を事前に増やすこともできますが、比較的長期間メッセージを保存する必要がある場合や、1 か月の保存など大量のデータを保存する必要がある場合は、データを月次ベースでプルバックして計算する必要があるタスクでは、必要なのはブローカー機能の追加ではなくストレージの追加であるため、このシナリオは Kafka クラスターにとって非常に無駄です。Bookkeeper は、ストレージとコンピューティングの分離のためのアーキテクチャ サポートを Pulsar に提供します。パルサーのブローカーは個別に拡張できますが、これはkafkaでは利用できません

基本的な考え方

  • エントリ: エントリは簿記に保存されている記録です

  • 元帳: 元帳はエントリを保存するために使用され、複数のエントリのシーケンスが元帳を形成すると考えることができます。

  • Bookie: Bookie は元帳を保存するために使用される Bookkeeper のストレージ サーバーです。一般的に言えば、元帳の一部を保存します。ストレージが分散されているため、各元帳は複数の Bookie に保存されます。

  • メタデータ ストレージ: メタデータ ストレージは、ブックキーにどの台帳があるかなど、ブックキー関連のメタデータを保存するために使用され、ブックキーパーは現在 zk ストレージを使用しています。ブックキーパーをデプロイする前に、zk クラスターが必要です。

  • データ ストレージ ファイルとキャッシュ:

  • ジャーナル: 実際には、bookkeeper のトランザクション ログを保存するために使用される bookkeeper の WAL (先書きログ) です。ジャーナル ファイルには最大サイズがあります。このサイズに達すると、新しいジャーナル ファイルが作成されます

  • エントリ ログ: エントリを保存するファイル。台帳は論理的な概念であると理解しています。異なる台帳のエントリは、まず台帳ごとに集約され、その後エントリ ログ ファイルに書き込まれます。同様に、エントリ ログには最大サイズがあり、最大サイズに達すると新しいエントリ ログ ファイルが作成されます。

  • インデックス ファイル: 台帳のインデックス ファイルです。台帳のエントリはエントリ ログ ファイルに書き込まれます。インデックス ファイルは、Deng Yingchao のエントリ ログ ファイル内の各台帳のインデックスを作成し、各台帳の保管場所を記録するために使用されます。エントリ ログとエントリ ログ内のデータ エントリ ログ ファイルの長さ

  • 台帳キャッシュ: 検索効率を向上させるためにインデックス ファイルをキャッシュするために使用されます。

  • データ ストレージ: LastLogMark はメモリに保存され、txnLogId (ジャーナル ファイルの ID) と txnLogPos (ジャーナル ファイル内の位置) が含まれます。エントリ ログ ファイルとインデックス ファイルが最初にメモリにキャッシュされます。メモリが特定の値に達するか、最後のフラッシュから一定期間 (スケジュールされたスレッド) が経過すると、エントリ ログ ファイルとインデックス ファイルのフラッシュがトリガーされ、LastLogMark が永続化されます。これは、lastLogMark より前のエントリとインデックスがすべてディスクに書き込まれていることを意味します。このとき、lastLogMark より前のジャーナル ファイルはクリアできます。LastLogMark が永続化する前にクラッシュした場合は、ジャーナル ファイルを介して復元できます。データは失われません。

  • データの圧縮: データのマージは、hbase の圧縮プロセスに似ています。ブックキーでは、ディスクがリフレッシュされる前に台帳に従ってエントリーログが集計されますが、ファクターデータは追加され続け、各リーダーのデータはエントリーログファイルに保存され、ガベージ コレクションのブックキー。スレッドは、ディスク領域を再利用するために、どの台帳にも関連付けられていないエントリ ファイルを削除します。また、圧縮の目的は、エントリ ログ内の少数のレコードだけが台帳に関連付けられる状況を回避することです。 、そのようなエントリは許可されません。ログ ファイルはディスク領域を占有しているため、ガベージ コレクション スレッドは、そのようなエントリ ログ内の台帳に関連付けられたエントリを新しいエントリ ログ ファイルにコピーします (同時にインデックスも変更します)。古いエントリ ログ ファイルを削除します。hbase と同様に、bookkeeper の圧縮も次の 2 つのタイプに分類されます。

  • マイナー コンパクション: エントリ ログ内の有効なエントリが 20# 未満の場合にコンパクションを実行します。

  • メジャーコンパクション: エントリログ内の有効なエントリが 80% 未満の場合、コンパクションを開始できます。

API提供

Bookkeeper は 2 つのレベルの API を提供します。

  • Ledger API: 台帳を直接操作するために使用されます。これは比較的複雑で、bookkeeper によって提供される基礎的な API です。
  • 分散ログ: 分散ログは、台帳 API に基づく高レベルの API であり、比較的シンプルで使いやすいです。

分散ログ アーキテクチャ:

 

分散ログ API によって書き込まれたログは、同じ書き込み順序でブックキーパーに保存されます。

 

Bookkeeper の適用可能なシナリオ

  • WAL: bookkeeper は WAL ソリューションとして使用できます
  • ストリーム ストレージ: たとえば、パルサーはブックキーパーを通じてメッセージを保存します。
  • オブジェクト/BLOB ストレージ

 

Presto は Facebook のオープンソース分散 SQL クエリ エンジンで、対話型の分析とクエリに適しており、データ量は GB ~ PB バイトをサポートしています。presto のアーキテクチャは、リレーショナル データベースのアーキテクチャから進化しました。presto がさまざまなメモリ コンピューティング データベースの中で傑出している理由は、次の点にあります。

  1. 明確なアーキテクチャとは、独立して実行でき、他の外部システムに依存しないシステムです。たとえば、スケジューリングでは、presto 自体がクラスターの監視を提供し、監視情報に基づいてスケジューリングを完了できます。
  2. シンプルなデータ構造、列形式のストレージ、論理行など、ほとんどのデータを presto に必要なデータ構造に簡単に変換できます。
  3. 豊富なプラグイン インターフェイス、外部ストレージ システムとの完璧なドッキング、またはカスタム機能の追加。

この記事ではプレストを外観から内部まで紹介します。

建築

Presto は典型的なマスター/スレーブ モデルを採用しています。

  1. コーディネーター (マスター) は、メタ管理、ワーカー管理、クエリ解析およびスケジューリングを担当します。
  2. ワーカーはコンピューティングと読み書きを担当します。
  3. 通常、コーディネーター ノードに組み込まれているディスカバリ サーバーは、ノード ハートビート用に個別に展開することもできます。以下では、デフォルトのディスカバリーとコーディネーターがマシンを共有します。

ワーカーの構成では、次の構成を選択できます。

  1. 発見のip:ポート。
  2. http アドレス。コンテンツは、検出アドレスを含むサービス インベントリです。
  3. ローカルファイルアドレス
{
"environment": "production",
    "services": [
    {   
        "id": "ffffffff-ffff-ffff-ffff-ffffffffffff",
        "type": "discovery",
        "location": "/ffffffff-ffff-ffff-ffff-ffffffffffff",
        "pool": "general",
        "state": "RUNNING",
        "properties": {
            "http": "http://192.168.1.1:8080"
        }   
    }   
]   
}

2 と 3 の原則はサービス インベントリに基づいています。ワーカーはこのファイルを動的に監視します。変更がある場合は、最新の構成をロードし、最新の検出ノードをポイントします。

設計では、ディスカバリーとコーディネーターは両方とも単一ノードです。複数のコーディネーターが同時に生存している場合、ワーカーはそのうちの 1 人にプロセスとタスクのステータスをランダムに報告し、結果としてスプリット ブレインが発生します。クエリをスケジュールするときにデッドロックが発生する場合があります。

ディスカバリーとコーディネーターの使いやすさのデザイン。サービス インベントリを使用するため、監視プログラムは、ディスカバリが停止していることを検出した後、スタンバイ マシンのディスカバリを指すようにサービス インベントリの内容を変更できます。シームレスに切り替えます。コーディネーターの構成はプロセスの開始時に指定する必要があり、複数のコーディネーターが同じクラスター内で存続することはできません。したがって、最善の方法は、同じマシン上で検出を使用して構成することです。セカンダリ マシンはスタンバイ ディスカバリとコーディネータを展開します。通常、セカンダリ マシンは 1 台のマシンのみからなるクラスタですが、プライマリ マシンがダウンすると、ワーカーのハートビートは即座にセカンダリ マシンに切り替わります。


データ・モデル

Presto は 3 層のテーブル構造を採用しています。

  1. カタログは、Hive データや mysql データなどの特定のタイプのデータ ソースに対応します。
  2. スキーマはmysqlのデータベースに対応します
  3. テーブルはmysqlのテーブルに対応します

Presto ストレージ ユニットには次のものが含まれます。

  1. ページ: 複数の列のデータを含む、複数行のデータのコレクション。内部的には論理行のみが提供され、実際には列に格納されます。
  2. ブロック: データの列。通常、データの種類に応じて異なるエンコード方式が採用されます。これらのエンコード方式を理解すると、ストレージ システムを Presto に接続するのに役立ちます。

さまざまなタイプのブロック:

  1. int、long、double などの固定幅型に適用される配列型ブロック。ブロックは 2 つの部分で構成されます
  • boolean valueIsNull[] は、各行に値があるかどうかを示します。
  • T 値[] 各行の特定の値。

2. 文字列データに適用される可変幅ブロックは、3 つの情報部分で構成されます。

    • スライス : すべての行からの連結されたデータの文字列。
    • int offsets[] : データの各行の開始安価な位置。各行の長さは、次の行の開始オフセットから現在の行の開始オフセットを引いたものと等しくなります。
    • boolean valueIsNull[] 行に値があるかどうかを示します。値のない行がある場合、この行のオフセットは前の行のオフセットと等しくなります。

3. 固定幅の文字列型のブロック。すべての行のデータが一連の長いスライスに結合され、各行の長さは固定されています。

4. ディクショナリ ブロック: 一部の列では個別の値が少ないため、ディクショナリを使用して保存するのが適しています。主に次の 2 つの部分があります。

    • 辞書は任意のタイプのブロックにすることができ (辞書ブロックをネストすることもできます)、ブロック内の各行はソートされ、順番に番号が付けられます。
    • int ids[] は、辞書内のデータの各行に対応する値の番号を示します。検索するときは、まず特定の行の ID を見つけてから、辞書内の実際の値を取得します。

プラグイン

presto のデータ モデルを理解したら、presto のプラグインを作成して独自のストレージ システムに接続できます。Presto は、カスタム ストレージからメタデータを読み取り、データを列に保存するための一連のコネクタ インターフェイスを提供します。まずコネクタの基本概念を見てみましょう。

  1. ConnectorMetadata: テーブルのメタデータ、テーブルのメタデータ、パーティションなどの情報を管理します。リクエストを処理する際には、読み込んだデータの所在を確認するためにメタ情報を取得する必要があります。Presto は、読み取られるデータの範囲を減らすためにフィルター条件を渡します。メタ情報はディスクから読み取ることも、メモリにキャッシュすることもできます。
  2. ConnectorSplit: IO タスクによって処理されるデータの集合。スケジューリングの単位です。スプリットは 1 つまたは複数のパーティションに対応します。
  3. SplitManager : テーブルのメタに従って、分割を構築します。
  4. SlsPageSource : 計算エンジンによる計算のために読み込まれる分割情報と列情報に従って、ディスクから 0 ページ以上を読み取ります。

プラグインは、開発者が次の機能を追加するのに役立ちます。

  1. 独自のストレージ システムに接続します。
  2. カスタム データ型を追加します。
  3. カスタムハンドラーを追加します。
  4. カスタム権限制御。
  5. カスタムリソースコントロール。
  6. クエリ イベント処理ロジックを追加します。

Presto は、単純なコネクタであるローカル ファイル コネクタを提供します。これは、独自のコネクタの実装方法を参照するために使用できます。ただし、ローカル ファイル コネクタで使用されるデータの走査単位はカーソル、つまりページではなくデータの行です。hive コネクタ、parquet コネクタ、orc コネクタ、rc ファイル コネクタには 3 つのタイプが実装されています。

上記では、マクロの観点から presto の原理をいくつか紹介しましたが、次のいくつかの記事では、presto の内部を深く掘り下げ、いくつかの内部設計を理解します。これは、パフォーマンスのチューニングに非常に役立ち、カスタム オペレーターの追加にも役立ちます。


メモリ管理

Presto はインメモリ コンピューティング エンジンであるため、クエリを秩序正しくスムーズに実行するにはメモリ管理をきめ細かく行う必要があり、場合によってはスタベーションやデッドロックが発生する可能性があります。

メモリプール

Presto は論理メモリ プールを使用して、さまざまな種類のメモリ要件を管理します。

Presto はメモリ全体を 3 つのメモリ プール、つまりシステム プール、予約プール、および一般プールに分割します。

  1. システム プールはシステム用に予約されており、デフォルトではメモリ領域の 40% がシステム用に予約されています。
  2. 予約プールと一般プールは、クエリ ランタイム メモリを割り当てるために使用されます。
  3. ほとんどのクエリは一般プールを使用します。最大のクエリは予約プールを使用するため、予約プールのスペースはマシン上で実行されているクエリで使用される最大スペースと等しく、デフォルトはスペースの 10% です。
  4. 一般は、システム プールと一般プール以外のメモリ領域を利用します。

メンプールを使用する理由

システム プールは、マシン間のデータ転送など、システムが使用するメモリに使用され、メモリ上にバッファが保持され、メモリのこの部分はシステム名でマウントされます。

では、なぜ予約領域メモリが必要なのでしょうか? そして、予約領域のメモリは、マシン上のクエリで使用される最大メモリとまったく同じですか?

Reserved Pool がない場合、クエリが大量に発生してメモリ領域がほぼ使い尽くされたときに、比較的メモリ消費量の多い特定のクエリが実行され始めます。しかし、現時点では、このクエリを実行するためのメモリ領域がなく、このクエリは一時停止状態にあり、使用可能なメモリを待っています。ただし、他の低メモリ クエリが実行された後は、新しい低メモリ クエリが追加されます。小規模メモリ クエリは占有するメモリが少ないため、利用可能なメモリを簡単に見つけることができます。この場合、大規模なメモリのクエリは餓死するまでハングします。

したがって、この枯渇状態を防ぐために、大規模なメモリ クエリを実行するためのスペースを予約する必要があります。予約されたスペースのサイズは、クエリで許可される最大メモリと同じです。Presto は毎秒、メモリ使用量が最大のクエリを選択し、クエリの実行に利用可能なメモリがなくなることを避けるために予約プールの使用を許可します。

メモリ管理

Presto のメモリ管理は 2 つの部分に分かれています。

  • クエリメモリ管理
    • クエリは多くのタスクに分割され、各タスクにはスレッド ループがあり、タスクが使用するメモリなどのタスクのステータスを取得します。クエリによって使用されるメモリを要約します。
    • クエリの総メモリが一定のサイズを超えると、クエリは強制的に終了されます。
  • マシンのメモリ管理
    • コーディネーターには、各マシンをローテーションで定期的にトレーニングし、マシンの現在のメモリ状態をチェックするスレッドがあります。

クエリ メモリとマシン メモリが集約されると、コーディネーターはメモリ使用量が最も大きいクエリを選択し、それを予約プールに割り当てます。

メモリ管理はコーディネータによって管理され、コーディネータは毎秒判断して、特定のクエリがすべてのマシン上の予約メモリを使用できることを指定します。そこで質問は、クエリが特定のマシンで実行されていない場合、そのマシンによって予約されているメモリが無駄になっていないかということです。単一マシン上で実行される最大のタスクを選択してみてはいかがでしょうか。理由はデッドロックです。クエリが他のマシンで予約されたメモリを利用している場合、実行はすぐに終了します。ただし、これは特定のマシン上で最大のタスクではなく、実行されていないため、クエリを終了できません。

おすすめ

転載: blog.csdn.net/qq_35240226/article/details/107974165