Apache IoTDBシリーズチュートリアル6:パフォーマンスの最適化(0.8-0.10)

 

今日のコンテンツには、モデリングの最適化、読み取りと書き込みのパフォーマンスの最適化が含まれ、いくつかの単純な原則が含まれます。主に0.8-0.10バージョン用。

テキストは3754語で、推定読書時間は10分です。

モデリングガイド

ストレージグループについて

現在、各ストレージグループは比較的独立したエンジンであり、読み取り/書き込みロックはストレージグループレベルにあります。したがって、ストレージグループを1から10に変更すると、読み取りと書き込みの速度を基本的に8倍向上させることができます。単一のIoTDBインスタンスに対して、CPUコアを備えた複数のストレージグループをセットアップすることをお勧めします。ストレージグループが多いほど、並列処理の度合いが高くなります。ロックの粒度をデバイスレイヤーに分散する予定です。

装置

デバイスの概念はSQLステートメントで定義されていませんが、最後から2番目のレイヤーはサーバー側の処理中にデフォルトでデバイスとして設定されるため、誰もがこの概念を簡単に無視できます。装置が何に影響するかについてお話しましょう。

(1)順次データと順不同データの区別は、粒度としての機器に基づいています。たとえば、デバイスがメモリにタイムスタンプ1〜10のデータを書き込む場合(どの測定ポイントが書き込まれるかに関係なく、タイムスタンプはデバイスのヘッドでカウントされます)、ディスクが配置され、タイムスタンプ<= 10のデータが書き込まれます。 、これらのデータは順不同データとしてキャッシュされ、ディスクに配置されます。

(2)機器の粒度の時間範囲インデックス。TsFileファイルごとに、デバイスの粒度のインデックスがメモリに構築されます。すべてのデバイスがアクティブである場合、N TsFileおよびDデバイスの場合、N * Dインデックスが存在します。数百万のデバイスのインデックスメモリは圧倒されます。これを1つまたは2つのバージョンで変更します。

デバイスの数を制御するための設計とモデル化の方法について説明します。実際のアプリケーション機器やセンサーレベルは比較的シンプルで、センサー層は機器の直下にあり、一般的に構築するのは間違いありません。装置下の多層構造に注意してください。

たとえば、1つのデバイスの下に10個のセンサー(s1、s2、...、s10)があり、各センサーは10個の時系列データ(f1、f2、... f10)を収集します。このとき、root.xxx.device.s1.f1をビルドするのは簡単です。これをビルドすると、考えていたデバイスは考えていたデバイスではなくなり、実際のデバイスはroot.xxx.device.s1になります。デバイスの実際の数は、あなたが思っているものの10倍です。

どうすればよいですか?デバイスの下にサブデバイスが多くない場合は、システムに実際に存在するデバイスの数がわかっていればモデリングに問題はないので、通信に偏りがなく、後でトラブルシューティングを行うのに便利です。

多くのサブデバイスがある場合は、root.xxx.device.s1_f1のように、デバイスの背後にあるものを1つのレイヤーに重ね​​ることができます。使用しているので、セパレータとして、s1_f1はレベル1になります。実際のデバイスはroot.xxx.deviceです。

測定定義

測定は、最後のレイヤーの測定ポイントです。測定ポイントがINT32またはINT64タイプであり、このデータの値がほとんどの場合同じである場合、変化はないため、RLEエンコーディングを使用することをお勧めします。もちろん、ディスク容量を大幅に節約できます。フラッシュの速度も速くなります。SNAPPYがオンの場合、圧縮モードは問題ありません。

タグと属性

0.10.0で導入されたこれらの2つの概念では、2つの違いについて混乱しやすくなります。これらはすべてKey-Value属性ですが。ただし、このタグを使用すると、時系列のメタデータを逆にクエリできます。タグのキーが所有者である場合は、show timeseries where owner = Thanosを使用して、Thanosが所有する時系列を確認できます。タグはメモリに常駐し、タグから時系列へのインデックスを持っています。

属性は一般的な属性です。たとえば、属性はdescription = "this is my series"です。これらの属性は、ヘルパーが表示できるように、特定の時系列のパスに沿って付随的にのみ表示できます。

そのため、実際のニーズに応じて区別する必要があり、逆検索が必要な属性をタグに組み込み、それ以外を属性にすることができます。 

読み取りと書き込みの最適化

読み取りと書き込みは密接に関連しており、データの書き込みとパラメーターの構成はクエリのパフォーマンスに影響します。

書き込みインターフェース

0.10を例にとると、最初に同じ種類を比較すると、insertRecordsインターフェースはinsertRecordインターフェースよりも確実に高速です。同様に、insertTabletsはinsertTabletよりも高速で、createMultiTimeseriesもcreateTimeseriesより高速です。

さらに、2つのinsertRecordsメソッドを提供しています。1つはObjectの値を渡すことで、もう1つはStringの値を渡すことです。クライアントが値タイプを取得できる場合は、Objectを使用することをお勧めします。これは、Stringよりも約25%高速です。

クラス間の比較では、クライアント側での時間のかかるフォーマット変換を考慮しない場合、insertTabletはinsertRecordsよりもはるかに高速で、おそらく8倍以上であり、時間のかかるオブジェクトのカプセル化を大幅に節約し、バッチサイズは約1000です。

insertTabletインターフェースはデフォルトではソートされません。Tabletデータのタイムスタンプが減少しないことを確認できる場合は、sortedがtrueのパラメーターを追加できます。クライアントのソートを保存します。

統計に時間がかかる場合は、クライアントの時間のかかるフォーマット変換にも注意する必要があります。インターフェースパラメータの構築時間と実行時間を分離できます。

クエリインターフェイス

クエリインターフェースは比較的単純です。SessionのデフォルトのhasNextとnextはRowRecord構造を返します。この構造は必ずしもすべての人に必要なわけではありません。SessionDataSetのイテレーターを使用してイテレーターを取得し、JDBCのようなインターフェースを介して元のデータを取得して、多くの無駄を回避できますオブジェクトの生成。

順次書き込み

時系列データベースの場合、時系列は非常に重要な概念であり、混乱しないことが最善です。IoTDBはデータの順不同の書き込みをサポートしますが、順不同のデータは主に集計クエリのクエリパフォーマンスに影響します。原則として、順不同のデータは事前​​計算された統計情報を無効にし、集計クエリの次元を減らして元のデータを読み取ります。

通常の状況では、数回の障害で問題はありませんが、一定の期間に書き込まれる障害データが多すぎる(数万回)と、クエリ中にメモリがバーストする可能性があります。たとえば、メモリバッファーは、タイムスタンプが1〜10のデータをディスクに書き込み、次に9999倍の1〜10バッファーを書き込むため、ディスクにはタイムスタンプが1〜10のデータブロックが10,000個あります。 。クエリを実行する場合、マージのために10,000データブロックすべてを読み取る必要があり、メモリ使用量は比較的大きくなります。

このシナリオに直面して、無秩序に対処するためにバックグラウンドでデータの並べ替えを行います(0.9で導入されたマージですが、バージョン0.9にはバグがあり、0.10は修正されていますが、デフォルトではオフになっており、0.11でマージが再開されます)。クライアントの無秩序を回避できる場合は、書くときにそれを避けてください。デバイスは昇順で書き込まれます。

Kafkaが前面に接続されている場合、パーティションの細分性としてデバイスIDに注意することをお勧めします。これにより、デバイスのデータが1つのパーティションに送信され、消費中に同じパーティションで順序を保証できます。

メモリバッファ

最初に、シーケンスごとにメモリにキャッシュできるポイントの数を計算する方法を紹介します。memtableのサイズをシーケンスの数で割り、次に各ポイントのサイズで割ります。たとえば、longタイプは16バイト(8バイトのタイムスタンプ、 8バイトの値)、floatは12バイトです。

memtableのサイズはログで確認できます。reachを検索すると、おそらくログはmemtableサイズxxxがしきい値に達したことになります。構成ファイルのenable_parameter_adapterがfalseに変更されていない場合、このmemtableのサイズは固定されず、登録されたシーケンスの数で調整されます。

メモリバッファは、読み取りと書き込みを容易にするために、特定の範囲内でできるだけ大きくします。各シーケンスが100万ポイント未満をバッファできることがより良いです。ただし、大きすぎることはお勧めしません。クエリ中に一時的に並べ替えられます。メモリ内のデータポイントが数千万など、多すぎる場合、メモリの並べ替えはクエリ中に最大10秒かかります。

この問題を回避するために、パラメーターが0.10.0、avg_series_point_number_thresholdに追加されました。デフォルトは10000です。これは、メモリーバッファー内の各シーケンスが最大で多くのポイントをキャッシュし、ディスクがフラッシュされることを意味します。このデフォルトパラメーターは適切に指定されておらず、500,000に変更できます。または100万。

パラメータmemtable_size_thresholdが大きいほど、書き込み速度は速くなりますが、通常は数百Mから1 Gまたは2 G程度です。書き込み速度に深刻な影響を与える、数メガバイトなどの小さすぎる値を設定しないでください。このパラメータを設定するときは、メモリ制限を超えないように注意する必要があります。このパラメータを調整する前に、enable_parameter_adapterがfalseに変更されていることを確認する必要があります。

複数のデータディレクトリ

データベースのボトルネックはディスクIOです。ディスクIO機能を改善する簡単な方法は、複数のディスクを構成することです。IoTDBのデータディレクトリは、複数のディレクトリをカンマで区切ってdata_dirsパラメータで構成できます。ディスクごとに1つのディレクトリがあります。データを書き込むとき、これらのディスクの中で最も自由な書き込みを見つけます。

クライアントの最適化

ストレージグループレベルのロックについて説明しました。同じストレージグループ内のN個の書き込みスレッドの場合、これらのN個の書き込みスレッドがロックを取得します。ストレージグループが50クライアント以下に対応していることが望ましいです。書き込みスレッドが多すぎると、過度のロック競合。

スレッドプールSessionPoolの容量は、通常、サーバーのCPUコアを搭載するのに十分な量であり、多すぎません。

クライアントのメモリ、データの生成、消費率も監視して、送信されたタスクの過剰なバックログを回避できます。クライアントのメモリがいっぱいになると、現象が発生します。クライアントがサーバーにリクエストを送信し、サーバーがすぐに実行されて戻りますが、クライアントは結果の受信に時間がかかります。

バーストしやすいメモリポイント

Select * from rootこのステートメントは、シーケンスが多すぎる場合は実行しないことをお勧めします。この操作は、ライブラリ全体をテーブルとして扱い、すべての列のデータのバッチを一度に見つけます。メモリをバーストするのは簡単です。バージョン0.11でチェックを追加します。時間内に拒否します。

show timeseriesバージョン0.10以前は、メモリ内のすべてのシステムシーケンスをコピーしてクライアントに送信します。シーケンスが多すぎる場合は、プレフィックスを指定してフィルタリングすることをお勧めします。または、レイヤーごとに子パスを表示して確認します。

時系列が多すぎると(1億レベル)、メタデータがメモリ内で爆発する可能性があります。200バイトの時系列によれば、約1000万の系列が2Gメタデータ(つまり、メタデータツリー)を占めると推定できます。

総括する

データベースは初期段階で多くの手動チューニングを必要とします。現在の自動チューニングツールはまだ改善する必要があります。私たちの目標はできるだけ単純にすることです。バージョン0.11ではメモリとパラメータの設定が改善されています。今日はたくさんのコンテンツがありますが、後で考えれば続編が出ます!

githubのフォロー、転送、スターへようこそ!

https://github.com/apache/incubator-iotdb/tree/master

おすすめ

転載: blog.csdn.net/qiaojialin/article/details/107328557