Volcano Engine LAS Spark アップグレード: バケット最適化テクノロジーを明らかにする

さらに技術的な交流や仕事の機会が必要な場合は、ByteDance データ プラットフォームの WeChat 公式アカウントをフォローし、[1] と返信して公式コミュニケーション グループに参加してください。

本稿では、Volcano Engine 湖・倉庫統合分析サービス LAS(以下、LAS)を中心に、Spark Bucket の基本原理を含めた Bucket 最適化技術と実際のビジネスへの応用について紹介します Spark による Bucket 最適化の機能強化により、Bucket の使いやすさを実現使用率が大幅に改善され、最適化の対象範囲が拡大し、Byte 内での適用例が成功しました。記事内で言及されている能力強化は LAS 上で直接使用できます。どなたでも Volcano Engine 公式 Web サイトにアクセスして体験および購入できます (クリックして移動)。記事の最後には限定のイースターエッグと割引購入があります初心者向けの特典、ロック解除を待っています!

この記事の概要は次のとおりです。

  • バケット最適化テクノロジーの概要
  • LAS バケットの強化
  • バイト内でのバケット最適化の適用
  • 要約する

バケット最適化テクノロジーの概要

バケット最適化は、データをバケット化して並べ替えることによってクエリ速度を最適化するテクノロジーです。

バケット化はデータを整理する方法です。バケット フィールドとバケットの数を指定する必要があります。バケット フィールドの値をハッシュして剰余を取得し、同じ剰余を持つデータを同じバケットに保存します。バケット フィールド、バケット番号、ソート列を指定すると、バケット テーブルはシャッフルを使用して書き込まれたデータをバケットに分割し、バケットをソートしてファイルに書き込みます。

Bucket テーブルを作成するための構文は次のとおりです。clustered by (id)バケット列を指定し、sorted by (id)ソート列を指定し、into 4 buckets**** バケット数を指定します。

create table user(id Int, info String) clustered by (id) sorted by (id) into  4 buckets; 

Bucket テーブルの読み取りおよび書き込み用の SQL 構文は、非 Bucket テーブルの SQL 構文と同じであり、ユーザーによる変更は必要ありません。

insert overwrite table user select id, info from ... where ...

前述の SQL で記述されたバケット テーブルの実行計画は次のとおりですが、元のジョブ出力データの分散がバケットのバケット化要件を満たしていない場合、追加のシャッフルとソートのオーバーヘッドが発生します。

 非BucketテーブルとBucketテーブルを出力する模式図の比較は以下のとおりです。

下流タスクがバケット化された列に基づいて結合、グループ化、またはウィンドウ化する場合、シャッフルとソートのオーバーヘッドを節約できます。次の図は、Bucket 最適化を使用した場合と使用しない場合の SortMerge Join の実行計画をそれぞれ示しています。Bucket 最適化を使用すると、テーブル A と B のシャッフルとソートを省略できます。

LAS バケットの強化

LAS Spark チームは、実際のビジネス シナリオと組み合わせることで、Spark のバケットの最適化をさらに強化しました。

  • Hive Bucket の最適化と互換性があり、クロスエンジン読み取りをサポートします
  • バケット テーブルの読み取りおよび書き込み時に、より多くのシナリオでシャッフル除去をサポートします
  • 過去の非バケット パーティションとの互換性
  • パーティションレベルでのバケット数の設定をサポート

Hive バケットの最適化と互換性があります

データ ウェアハウス内のテーブルは複数のコンピューティング エンジンによって読み取られる場合があり、現在、Byte は SparkSQL エンジンと Presto OLAP エンジンの両方をサポートしています。さまざまなコンピューティング エンジンがテーブルのバケット情報を使用してクエリを最適化できるようにするには、各エンジンのバケット実装を調整する必要があります。次の図は、Hive/Presto 書き込みバケット テーブルとネイティブ Spark 書き込みバケット テーブルの比較を示しています。

上の図からわかるように、Bucket テーブルを書き込む前に、Hive は、reduce 操作を通じて同じバケット化されたデータをファイルに書き込みますが、Spark のネイティブの Bucket 最適化にはこのステップがないため、次の問題が発生します。

問題 1 - 小さなファイルが多すぎる: Bucket テーブルを書き込む Spark のネイティブ実装では、マッパー側のファイルにデータを書き込むことになっており、各マップ タスクには複数のデータ バケットが含まれる可能性があり、最悪の場合、M B ファイル、M はマップ タスクの数、B はバケットの数です。このロジックによれば、各バケット内のデータは M 個の部分に分割されるため、そのほとんどは小さなファイルになる可能性があります。タスクの同時実行数が 1000、バケット数が 128 の場合、最悪の場合 MB = 128000 個のファイルが生成され、このような大量のファイルが HDFS NameNode への負荷を大幅に増加させ、HDFS 読み取りのレイテンシを増加させます。

問題 2 - 単一バケット内のデータの順序を保証できない: Spark のネイティブのバケット テーブルでは、各バケットの下に複数のファイルがあり、バケット内のデータの順序は保証できないため、SortMerge を実行する前にソートが必要です。参加する。 。

Presto は Hive Bucket 最適化と互換性があり、Spark のネイティブ Bucket 最適化には上記 2 つの問題があるため、LAS Spark チームは最終的に Spark を Hive Bucket 最適化と互換性のあるものにすることを選択しました。実装手順は次のとおりです

  • バケット列をリデュースキーとし、並列度をバケットの数と同じにしてシャッフルを動的に追加し、書き出す前にデータを並べ替え、同じバケット内のデータが 1 つのファイルにのみ書き込まれるようにします。バケット内のデータは正常です。
  • Spark の HiveHash ハッシュ関数をサポートすることで、Hive と互換性のあるバケット テーブルの書き込み、Hive バケット テーブルの読み取り、バケット情報を使用してシャッフルを排除できるようになります。

より多くのシナリオでシャッフル除去をサポート

 

バケットの数は複数の関係にあります

Spark では、同じ数のバケットを持つバケット テーブルのみが ShuffledJoin の前にシャッフルを排除できることを要求します。数百 GB のディメンション テーブルと数十 TB のファクト テーブル (単一パーティション) など、サイズが大きく異なる 2 つのテーブルの場合、多くの場合、バケットの数が異なり、その数も大きく異なります。結合の前は削除できません。Shuffle によって発生するオーバーヘッドを可能な限り削減するために、LAS Spark は 2 つの方法でバケット数の倍数の関係を排除するバケット テーブルの結合前のシャッフルをサポートしています。

最初の方法では、タスクの数は小さなテーブル内のバケットの数と同じです次の図に示すように、テーブル A には 3 つのバケットが含まれ、テーブル B には 6 つのバケットが含まれます。このとき、テーブル B のバケット 0 とバケット 3 のデータ コレクションをテーブル A のバケット 0 に結合する必要があります。この場合、3 つのタスクを開始できます。タスク 0 では、テーブル A のバケット 0 とテーブル B のバケット 0 + バケット 3 を結合します。ここでは、テーブル B のバケット 0 とバケット 3 のデータに対してマージ ソートを再度実行して、コレクションが適切であることを確認する必要があります。

テーブル A とテーブル B のバケット数がそれほど変わらない場合は、上記の方法を使用できます。テーブル B のバケット数がテーブル A のバケット数の 10 倍の場合、上記の方法ではシャッフルを回避していますが、並列性が不十分なため、シャッフルを含む SortMerge Join よりも遅くなる可能性があります。このとき、別の方法を使用できます。つまり、次の図に示すように、タスクの数が大きなテーブル内のバケットの数と同じになります。

このシナリオでは、テーブル A の 3 つのバケットを複数回読み取ることができます。上の図では、BucketUnion がテーブル A に対して直接実行されています (Union に似た新しい演算子ですが、バケットの特性は保持されています)。結果は、テーブル A を 6 つのバケットに設定することと同等であり、テーブル B のバケット化と同じです。 . 数字は同じです。

シャッフル キーはバケット化された列のスーパーセットです

共通テーブルの場合、「ユーザー」フィールドに基づいて別のテーブルと結合したり、「ユーザー」フィールドと「アプリ」フィールドに基づいて別のテーブルと結合したり、「ユーザー」フィールドと「アイテム」フィールドに基づいて他のテーブルと結合したりできます。Spark のネイティブ バケット最適化では、ShuffledJoin 前のシャッフルを排除するために、結合キー セットがテーブルのバケット列とまったく同じである必要があります。このシナリオでは、異なる結合のキー セットが異なるため、バケットの最適化を同時に使用することはできません。これにより、バケット最適化の適用可能なシナリオが大幅に制限されます。

この問題に対処するために、LAS Spark チームはスーパーセット シナリオでのバケット最適化をサポートしています。結合キー セットにバケット列が含まれている限り、シャッフル結合前のシャッフルを省略できます。

次の図に示すように、テーブル X と Y はフィールド A に従ってバケット化されます。クエリはテーブル X とテーブル Y を結合する必要があり、結合キー セットは A と B です。このとき、A の等しいデータは 2 つのテーブルで同じバケット ID を持つため、A と B の等しいデータも 2 つのテーブルで同じバケット ID を持つ必要があるため、データの分散は結合要件を満たし、シャッフルを必要としません。同時に、バケットの最適化では、2 つのテーブル (A と B) が結合キー セットに従ってソートされていることを確認する必要もあります。現時点では、パーティション内でソートする必要があるのはテーブル X とテーブル Y のみです。両側がフィールド A によってソートされているため、フィールド A とフィールド B によるソートのコストは比較的低くなります。

バケットテーブル書き込み時のシャッフル除去

Hive Bucket の最適化と互換性があるようになった後は、Bucket テーブルに書き込む前にもう 1 回シャッフルが必要になります。ただし、書き込まれたデータの配布がバケット化の要件を満たしている場合は、追加のシャッフルは必要ありません。LAS Spark は、そのような 2 つのシナリオを特定します

  • ケース 1: Bucket テーブルに書き込まれる前の演算子が Group By/Window/Inner Join/Left Join/Right Join である場合、シャッフル除去がサポートされます。シナリオによっては、Bucket テーブルに書き込まれる前の演算子は Full Out です。参加中にもサポートされます。上記の結合はシャッフル結合を指します。
  • ケース 2: Bucket テーブルに書き込まれる前の演算子が Group By である場合に限り、書き込みスーパーセット シャッフル除去がサポートされます。

過去の非バケット パーティションとの互換性

より多くのタスクをカバーするためにバケットの最適化を推進する過程で、ユーザーは在庫テーブルもバケットの最適化を活用できるように変換できることを望んでいます。バケット情報をテーブルのメタ情報に直接書き込むと、履歴パーティション データがバケット テーブルの要件に従って分散されていないため、クエリを実行するときにエラーが報告されます。しかし、在庫テーブルの履歴データは比較的大きく、バケット分布に従って再生成するオーバーヘッドが高すぎるため、実装が困難です。上記の問題を解決するために、LAS Spark チームは SparkSQL の構文を拡張して、DDL を介してテーブル属性を変更できるようにし、テーブルが特定の時点からバケット テーブルになることをサポートできるようにしました。

alter table tbl clustered by (a) sorted by (a) into 8 buckets;

前述の ddl が実行されると、テーブルのメタ情報に ddl 実行日とバケット情報が記録されます。その後データが書き込まれるとき、データはバケット分散に準拠するようにシャッフルされます。ShuffledJoin を実行するときは、クエリされたデータに ddl 実行日以降のパーティションのみが含まれているかどうかを最初に確認します。そうである場合、それはバケット テーブルとして扱われ、バケットの最適化をサポートします。そうでない場合、それは通常のテーブルとして扱われます。

パーティションレベルでのバケット数の設定をサポート

ビジネスの成長に伴ってデータ量が増加するため、1 つのタスクで処理できるデータ量が過剰になります。したがって、LAS Spark はパーティション レベルごとのバケット数の設定をサポートしており、大量のビジネス データを含むパーティションの場合は、バケットの数を大きく設定して、Shuffle のオーバーヘッドを削減し、同時実行性を向上させることができます。

同じ部門内の複数の事業部門で使用されるバケット テーブルがあり、テーブル レベルで定義されたバケットの数が 1024 であるとします。

create table department (
    user_id int ,
    user_info string
) partitioned by ( date string, business string)
clustered by(user_id) sorted by(user_id) into 1024 buckets;

このうち、business=' hot 'パーティションには人気のあるビジネスのデータが格納されており、そのデータ量は他のビジネスの約 2 倍ですLAS Spark は、次のように SparkSQL の構文を拡張することで、このパーティションに対するより多くのバケットの設定をサポートします。

ALTER TABLE department PARTITION(business='hot') SET NUM_BUCKETS = 2048;

データの書き込み: テーブルにデータを書き込むとき、現在のパーティションにパーティション レベルのバケット数に関する情報がある場合、データはパーティション レベルのバケット数に従って書き込まれます。それ以外の場合、データは次に従って書き出されます。テーブルレベルのバケットの数。

データ読み取り:

  • 単一パーティションを読み取る場合の状況を理解しやすく、読み取りの場合はパーティション レベルのバケット情報が優先され、そうでない場合はテーブル レベルのバケット情報が選択されます。
  • 複数のパーティションを読み取るとき、すべてのパーティションのバケット数が同じであれば、それらは通常のバケット テーブルとして扱われます。そうでない場合は、バケット数が最も多いパーティションがバケット情報を保持し、残りのパーティションのデータは次のように読み取られます。普通のパーティション。下図は例です 部門テーブルのホットパーティションとコールドパーティションを同時に読み込みます 前者は2048バケット、後者は1024バケットあります パーティションを読み込む際に、ホットパーティションのバケット情報とデータが読み込まれますシャッフルを実行し、データの 2 つの部分に対して BucketUnion (バケット情報を保持するユニオン演算子) を実行して、部門テーブルをバケット番号 2048 のバケット テーブルのように見せます。後で使用します。

バイト内でのバケット最適化の適用

 

ビジネスの背景

データ生成リンクの安定性は特に重要であり、リンク内のタスクが失敗したり出力が遅れたりすると、ビジネスに多くの問題が発生します。動画データを例に挙げると、動画データ生成リンクの安定性が保証できない場合、以下のようなリスクが生じます。

  • データ量が多く、リソースを消費し、1 回の実行に時間がかかるため、SLA 違反のリスクが高く、一度失敗して再実行すると、SLA 違反を引き起こしやすくなります。
  • 運用コストとメンテナンスコストが高い: 夜間はアラームが発生しやすく、タスクの準備時間が大幅に遅れる場合、キューの混雑を避けるためにスケジューリングの下流で手動介入が必要になります。プロセス全体には多くの人手が必要です。

Byte 内の特定のリンク タスクで、時間がかかりリスクの高いプロセスは主にシャッフル リンクです。現在、タスクのシャッフルデータ量が多いため、さまざまな問題ノードに遭遇する可能性が高く、不良ノードや遅いノードなどの問題が発生し、シャッフルが失敗することがよくあります。同時に、Shuffle サービスのノードがいっぱいになりやすく、タスクが Fetch Fail で再試行され、再試行が 3 回を超えると、Spark アプリケーション全体が強制終了されます。

バケット変換

リンク タスクの論理分析とバケットの特性との組み合わせを通じて、バケットの最適化がリンク全体に適用されます。ここでの完全なリンクは、ODS 層から DM 層までを指します。バケット機能は、リンク内で使用できる限り変換されており、合計すると、リンク内のテーブルの半分以上がバケット テーブルに変換されています。変換するときは、次の方法で可能な限りバケットの最適化を利用します。

  1. リンク内のタスクの分析により、ほとんどの Join および Group By 操作のキーに作業 ID が含まれていることが判明したため、作業 ID がバケット列として選択され、Join/ によって導入された Shuffle のキーが使用されます。 Group By/Window はバケット列のスーパーセットであり、これらのシャッフルを排除します。
  2. アップストリーム リンクとダウンストリーム リンク間のバケットの数が倍数であることを確認して、シャッフルの可能性をすべて排除します。具体的には、設定する必要があるバケットの数は 2 の累乗である必要があり、これにより、異なるバケット テーブル内のバケットの数が複数の関係にあることが保証されます。

リノベーション特典

フルリンク バケット変換後、フルリンク レベルでの利点は次のとおりです

  • 大規模タスク Shuffleの削減 :大規模なテーブル Shuffle の問題を解決し、大量の Shuffle データを削減します。
  • リンク動作の安定性が向上しました。夜間の実稼働リンクでのシャッフル障害の問題は発生しません。

個々のタスク レベルでの利点は次のとおりです。

  • ロングテール タスクの削減: 1 つのタスクの時間を平均 20% 短縮できます。
  • リソースの節約: CPU とメモリのリソースを 10% ~ 20% 節約できます。
  • 実行時間:タスクの実行時間はこれ以上増加しません。ロングテール タスクの削減により、一部のタスクは 20% 短縮される可能性があります。

要約する

バケットの最適化は、Exchange の排除とシャッフル レベルの最適化において非常に効果的な技術的手段ですが、ネイティブの Spark バケットはインベントリ テーブルの移行をサポートしておらず、データ量が増加した後にバケットの数を拡張することもできず、最適化の対象範囲のシナリオも比較的限られています。上記に対して、Scenario LAS Spark チームは一連の改善を行い、Bucket の使いやすさを大幅に向上させ、最適化の範囲を拡大しました。上記の強化された機能は LAS 上で直接使用できます。どなたでも積極的にお試しください。貴重なご意見やご提案。

Lakehouse Analytics Service LAS (Lakehouse Analytics Service) は、Lakehouse 統合アーキテクチャ向けのサーバーレス データ処理および分析サービスです。ByteDance のベスト プラクティスに基づいた、ワンストップの EB レベルの大規模データ ストレージ コンピューティングと対話型分析機能を提供します。Spark と互換性があり、 Presto Ecology は、企業がインテリジェントなリアルタイムのレイク ウェアハウスを簡単に構築できるように支援します。新規割引実施中!新規ユーザー全員にプレゼントされる限定特典はこちら LAS Dataの中国・台湾の新規ユーザー向け特別1元フラッシュセールイベントが新たにスタート!スタッキング割引も多数ご用意してお待ちしております!今後ともより良いコンテンツをお届けしてまいりますので、今後とも変わらぬご支援とご愛顧を賜りますようお願い申し上げます。(リンクをクリックするとスムーズに操作できます)

リンク: zjsms.com/jVCr5bp/

Microsoft、新しい「Windowsアプリ」を発表 Xiaomi、Xiaomi Velaが完全オープンソース、基盤となるカーネルはNuttX Vite 5 であることを正式発表 Alibaba Cloud 11.12が正式リリース 障害の原因が判明:アクセスキーサービス(アクセスキー)の異常 GitHub レポート: TypeScript が Java に代わって 3 番目に人気になる 言語オペレータの奇跡的な操作 : バックグラウンドでネットワークを切断し、ブロードバンド アカウントを無効にし、ユーザーに光モデムの変更を強制する ByteDance: AI を使用して Linux カーネル パラメータを自動的に調整する Microsoft オープン ソースTerminal Chat Spring Framework 6.1 が正式に GA OpenAI の元 CEO 兼社長の Sam Altman 氏と Greg Brockman 氏が Microsoft に入社
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/u/5588928/blog/10122956