最近自宅で、これまでにやった仕事をいくつかまとめてみます。たまたま、Doris コミュニティの小規模なパートナーが、ベクトル化されたインポートのパフォーマンスがあまり満足のいくものではないと不満を漏らしていたため、この機会を利用して、以前に開発されたベクトル化されたインポート作業のパフォーマンスを最適化し、良好な最適化結果を達成しました。このメモを借りて、パフォーマンス最適化のアイデアをいくつか記録し、レンガを投げて翡翠を引き寄せてください。皆さんがパフォーマンス最適化の作業に参加してくれることを願っています。
1. 一見遅いように見えるベクトル化されたインポート
問題発見
コミュニティ ユーザーからの Tucao:ベクトル化のインポートが遅すぎます。xx データベースをテストしたところ、Doris よりもはるかに高速でした。コツはありますか?
ああ?それほど遅いのでしょうか?その場合は必ず確認してみます。
そこでユーザー ケースを再現したところ、ユーザーがコード ベースで ClickBench のストリーム ロード (約 80 G のデータ) をテストし、ベクトル化されたインポートには 1200 秒近くかかったのに対し、非ベクトル化インポートには 1400 秒かかったことがわかりました。
ベクトル化 | 非ベクトル化 |
---|---|
1230年代 | 1450年代 |
ClickBench は、大きくて広いテーブルの典型的なシーンであり、Duplicate Key のモデルであり、原理的にはベクトル化されたインポートの利点を最大限に発揮できます。したがって、いくつかの問題があるようです。地図に従ってホット スポットを特定する必要があります。
ホットスポットを見つけるためのヒント
通常、作成者は Doris コードのホット スポットを特定するいくつかの方法を持っており、これらの方法を組み合わせることで、コードの本当のボトルネックを迅速に特定することができます。
-
プロファイル: ドリス自身の記録に時間がかかっていることをプロファイルを使用してコード部分のボトルネック ポイントを大まかに分析することができます。欠点は、柔軟性が十分ではないことであり、多くの場合、ホットスポットを観察するために必要なコードを追加するには、手動でコードを作成し、再コンパイルする必要があります。
-
FlameGraph : プロファイルを通じておおよそのホット スポットが分析されると、作成者は通常、コードをすばやく読み、フレーム グラフを組み合わせて関数のホット スポットを特定し、最適化の対象となるようにします。フレーム グラフの使用については、 Doris の公式ドキュメントの開発者マニュアルを簡単に参照できます。
-
Perf : フレーム グラフは集計関数のホットスポットを大まかに特定することしかできず、コンパイラがインライン化され、コンパイルおよび最適化された後は、フレーム グラフの機能レベルだけでは十分ではない可能性があります。通常、アセンブリ コードの問題をさらに分析する必要がありますが、このとき、開発ノート 2に記載されている perf を使用して、アセンブリ言語のホット スポットを特定できます。もちろん、perf は万能薬ではなく、多くの場合、コード自体の知識と最適化の経験に基づいてさらに調整する必要があります。
次に、上記のチューニングのアイデアに基づいてこの問題を分析します。
2. 最適化とコード分析
フレーム グラフに基づいて、著者はベクトル化インポート中にいくつかのコア ホットスポットを分類します。対象を絞った問題の分析と解決策:
遅いキャストと文字列の処理
CSV を Doris にインポートするプロセスでは、テキスト データ分析と式 CAST 計算のプロセスを通過する必要があります。明らかに、このジョブはフレーム グラフから観察され、CPU を大量に消費します。
上記のフレーム グラフから、時間のかかるFunctionCast::prepare_remove_prepare を呼び出す非常に異常な関数があることがわかります。これは、ソース コードに従ってさらに分析する必要があります。
キャストの過程では、次の図に示すように、null 値を分割する作業が完了する必要があります。たとえば、 String Cast Intの演算プロセスはここで完了する必要があります。
ここでは、元のブロックとキャストされる列を使用して、キャスト関数を計算するための新しい一時ブロックを作成します。
上で赤でマークされたコードは、std::set に対して多くの CPU コンピューティング作業を実行するため、ベクトル化されたインポートのパフォーマンスに影響します。インポートされたテーブル自体が大きく幅の広いテーブルであるシナリオでは、この問題の重大度はさらに大きくなります。
問題を特定した後の最適化作業は非常に簡単です。明らかに、キャストを実行するときは、キャスト計算の関連する列を実行するだけでよく、ブロック全体のすべての列が参加する必要はありません。そこで、作者は create_block_with_nested_columns_only_args
それを置き換えるためにここに新しい関数を実装create_block_with_nested_columns_impl
しました . 100 列を超える元のカウントの問題は 1 列の処理に減らされ、問題は大幅に改善されました。
最適化前 | 最適化された |
---|---|
1230年代 | 980年代 |
ページフォールトの最適化
上記の問題を解決した後、フレーム グラフの解析を続けると、データの書き込み時にmemtable
次のホット スポットが生成されることがわかりました:ページ フォールト中断。
とは何かを簡単に紹介します缺页中断
。
上の図に示すように、CPU はデータを計算するときに、メモリ内のデータの取得を要求します。CPU レベルで見られるメモリ アドレスは次のとおりです。これはVirtual Address
、特別な CPU 構造 MMU を介して仮想アドレスから物理アドレスにマップされる必要があります。MMU は TLB (変換ルックアサイド バッファ、これがキャッシュであることに注意してください) に移動して、対応する仮想アドレスと物理アドレスのマッピングを見つけます。オペレーティング システムではメモリはページを通じて管理され、アドレスはページ メモリ アドレスのオフセットに基づいているため、このプロセスは開始ページ アドレスを見つけるタスクになります。ターゲット仮想メモリ空間内のメモリ ページが物理メモリ内に対応するページ マッピングを持たない場合、この場合、ページ フォールト割り込み (Page Fault) が発生します。
ページフォールトは明らかに追加のオーバーヘッドを課します。
- ユーザーモードからカーネルモードへの切り替え
- カーネルはページフォールトを処理します
したがって、頻繁なページフォールトはインポートのパフォーマンスに悪影響を与えるため、これを解決する必要があります。
メモリの再利用
ここでのメモリ使用量とアドレス指定の多くは、Column に対する操作によって発生するため、メモリ割り当てのソースからこの問題を解決する必要があります。
解決策も非常に簡単で、ページフォルトはメモリマッピングの不足によって発生するので、以前に使用していたメモリを再利用するようにすれば、ページフォルトの問題は自然に発生しなくなります。 TLB キャッシュ アクセスの問題、より高いアフィニティ。
Doris は、ChunkAlloctor
メモリ割り当て、多重化、およびコア バインディング ロジックのクラスを内部でサポートしています。これにより、ChunkAlloctor
メモリ アプリケーションの効率が大幅に向上し、現在のケースではページ フォールト割り込みも回避できます。
podarray のメモリ割り当てロジックを置き換えた後の効果も期待どおりで、フレーム グラフで観察すると、ページ フォールト割り込みの割合が大幅に減少し、パフォーマンスの面で大きなメリットが得られています。
最適化前 | 最適化された |
---|---|
980年代 | 776s |
3. 関連する最適化された TODO のいくつか:
-
CSV データ形式分析: 4kb キャッシュを通じて複数行のデータをプリフェッチし、SIMD 命令セットを使用してパフォーマンスをさらに最適化します。
-
ページ フォールト中断の最適化:メモリ割り当ておよびコピーの一部で発生するページ フォールトの問題については、ページ フォールト中断とページ メモリ キャッシュをさらに最適化するために、ラージ ページ メモリ メカニズムの導入を検討します。
4. まとめ
もちろん、作者が行ったベクトル化されたインポート作業は、Doris のベクトル化されたインポート作業の一部にすぎません。コミュニティの多くの学生も関連業務に深く参加し、現状ベースでより理想的なパフォーマンスを獲得しています。つまり、パフォーマンス最適化の作業に終わりはありません。
また、コード レビューと分析を手伝ってくれたコミュニティの 2 人の学生にも特別に感謝します: xinyiZzz、 Gabriel
ビンゴ!完全にベクトル化された Doris の次の 1.2 バージョンにご期待ください。パフォーマンスと安定性の点で驚かれると思います。
最後に、皆さんが Apache Doris をサポートし、Doris にコードを貢献してくれることを願っています、ありがとう~~