InfluxDBの内部構造についての入門セッションをInfluxDBの新しいメンバー向けにPaul Dixが開催してくれました。 多くのことを学びましたのでコミュニティーに内容を共有したいと思います。私のInfluxDBへの理解を整理するためにも、同時にもしかするとInfluxDBがどのようなアーキテクチャーかを学びたいと思っている人の役にたつように、この記事を書いています。この連載のゴールはInfluxDBのアーキテクチャに関する概要を整理された状態でご紹介することです。
内容がたくさんありますので、3つのパートに分けてお伝えします。最初の投稿ではデータモデルと書込みについて、2つ目の投稿ではクエリーについて、3つ目の投稿ではInfluxDB Enterpriseのクラスタリングについて説明します。
目次
- 1. データモデルと書込みについて: InfluxDBへのデータの追加
- データモデルと用語
- クライアントからリクエスト(points)を受け付ける
- ストレージに永続化する
- 永続化されたデータを圧縮する
- 2. クエリーについて: InfluxDBからデータを読込む
- インデックスを作成する
- TSI(time series index: ディスク上のインデックス)について
- パースと実行計画
- クエリーの実行
- IFQL(※)について
- DELETEとDROPについて: InfluxDBからのデータを削除
- データの更新
- 3. クラスタリング: InfluxDB Enterprise
- メタデータサービスを理解する
- データノードを理解する
- データの分散およびレプリケーションについて
※訳注: SQLライクなInfluxQLとは異なる拡張されたクエリー言語。下記参照
- https://www.influxdata.com/blog/influxdb-now-supports-prometheus-remote-read-write-natively/
- https://www.influxdata.com/blog/new-data-model-query-language-influxdb-kapacitor/
データモデルと書込みについて: InfluxDBへのデータの追加
デーモデルと用語
InfluxDBのデータベースはポイント
(points
)を保存します。ポイントは4つの要素から構成されます。メジャメント
(measurement
)、タグセット
(tagset
)、フィールドセット
(fieldset
)、そしてタイムスタンプ
(timestamp
)です。
メジャメント
(measurement
)は、タグセット
あるいはフィールドセット
が異なる関連するポイントを関連付けるために利用することができます。タグセットはポイントともに保存するキーバリューのディクショナリです。フィールドセット
は型付きのスカラー値の集合
、すなわちポイントで保存されるデータです。
ポイントのシリアライゼーション形式は、「ラインプロトコル」にて定義されます。 仕様に記載しているポイントの例をみると用語が説明しやすいのでみてみましょう。
temperature,machine=unit42,type=assembly internal=32,external=100 1434055562000000035
メジャメント
はtemperature(温度)です。
タグセット
は、machine=unit42,type=assemblyです。キーはmachineとtypeで、これはタグセット
内ではタグキー
(tag keys
)と呼ばれます。値はunit42とassemblyでタグセット
内でこれはタグ値
(tag values
)とと呼ばれます。
フィールドセット
はinternal=32,external=100です。キーはinternalとexternalで、これはフィールドセット
ではフィールドキー
(field keys
)と呼ばれます。値は32および100でフィールドセット
ではこれはフィールド値
(field values
)と呼ばれます。
それぞれのポイントはただ1つのデータベース
(database
)にただ1つのリテンションポリシー
(retention policy
)で保存されます。データベース
は複数のユーザーに対する、複数のリテンションポリシー、そして複数のポイントの入れ物です。リテンションポリシー
はInfluxDBがどれだけポイントのデータをを保持するか(保存期間)、クラスターでいくつ複製を持つか(レプリケーションファクター)、そしてシャードグループでカバーされるタイムレンジ(シャードグループ保存期間)を設定します。リテンションポリシー
を利用することによって、ユーザーが(また、データベースが効率的に)不要となったデータを簡単に破棄できるようになります。これは時系列のアプリケーションでは共通することです。
レプリケーションファクター
(replication factor
)、シャードグループ
(shard groups
)、そしてシャード
(shard
)については後ほどInfluxDBの書込みの動作をご紹介する際に説明します。
もう1つ最初に抑えるべき用語があります。シリーズ
(series
)です。シリーズはリテンションポリシー
とメジャメント
とタグセット
を合わせたものを単純に短くしたものです。全く同じリテンションポリシー
、メジャメント
、そしてタグセット
を持つ全てのポイント
は同じシリーズ
のメンバーです。
これらの用語、あるいはこの一連のブログ投稿で利用される他の用語については用語集のドキュメントもご活用ください。
クライアントからリクエスト(points)を受け付ける
クライアントはポイントを(ラインプロトコル形式で)InfluxDBのHTTP /write
エンドポイントにPOSTします。ポイントは個別に送ることも可能ですが、効率化するために殆どのアプリケーションはバッチでポイントを送ります。典型的なバッチではポイントは数百から数千のサイズとなります。POSTでは、クエリーパラメーターでデータベースとオプションで付与するリテンションポリシーを指定します。リテンションポリシーが指定されない場合は、デフォルトのリテンションポリシーが利用されます。リクエストボディーに含まれる全てのポイントはそのデータベースおよびリテンションポリシーで書込まれます。POSTのボディーに記述するポイントは、任意の数のシリーズで構成可能です。すなわち、バッチ内のポイントは同一のメジャメントあるいはタグセットである必要はありません。
データベースが新しいポイントを受け取ったら次の2点が必要です。1つ目はデータベースまたはサーバーがクラッシュした際に復元できるようこれらのポイントを永続化すること、2つ目はポイントを問合せ可能(queryable)にすることです。この投稿ではポイントを永続化する前半部分について焦点をあてています。
ストレージに永続化する
ポイントを永続化するためには、それぞれのバッチは書きこまれ先行書き込みログ(WAL
)にfsync
されます。WAL
はデータベースをリカバリーする際のみ読込まれる追記のみを行うファイルです。ディスク容量とディスクIOを効率化するために、WAL
内の各バッチはディスクに書込まれる前にsnappyアルゴリズムで圧縮されます。
WAL
は入力データを永続化するために形式を効率化しますが、これは読込に対してとても良くない形式です。すなわち、クエリーをサポートするのには適さない形式となります。新しいデータに対してすぐにクエリーが発行できるようにするために、入力のポイントはメモリー上のキャッシュ
(cache
)にも書込まれます。キャッシュ
は参照および挿入の性能が最適化されるようなメモリー内のデータ構造をとります。これは時間でソートしたフィールドのリストに対するシリーズのマップです。
WAL
は新しいポイントを永続化し、キャッシュ
は新しいポイントに対してクエリー可能とします。キャッシュ
がTSM
ファイルに書き込まれる前にシステムがクラッシュまたはシャットダウンされた場合には、データベースが起動した際にWAL
に保存されたバッチを読み込んでリプレーすることで再構成されます。
WAL
とキャッシュ
の組み合わせは入力データに対してよく機能しますが、長期間の保存には不十分です。WAL
は起動時に必ずリプレーされますので、これは妥当なサイズに制限することが重要です。キャッシュ
はRAMのサイズに制限され、これは多くの時系列データの利用例から考えると理想的ではありません。すなわち、データは(データベースに多くのポイントを保存できるよう)容量を効率化し効率的にクエリーを実行できるようにデータを再構成し、ディスク上の長期間に渡る保存領域に書込む必要があります。
時系列のクエリーはある期間に渡る集約、例えばある限られた時刻範囲のポイントを読込み平均、最大、あるいはウィンドウ関数のような集約関数で分析する、といったものであることが多いです。データを行ではなく列ベースに再構成しディスクに保存する、列指向データベースのデータ保存の技術は、このクエリーパターンにはとても適しています。その上、列形式のシステムはデータの圧縮が格段に優れていますので、データを効率的に保存する需要を満たします。列の保存については多くの文献があり、[列指向データベースシステム]はこの概要を記載したドキュメントの1つです。
時系列のアプリケーションではある一定期間の後にデータを強制的に削除することがしばしばあります。多くの監視アプリケーションでは、例えば、監視のクエリーに対応するために直近の1ヶ月あるいは2ヶ月のデータを保存します。設定されたデータ保持期間を超えた場合にデータベースからデータを効率的に削除できる必要があります。列指向ストレージからポイントを削除するのは高コストですので、InfluxDBでは列指向の形式を時間で区切ったチャンクとして再構成しています。保存期間が過ぎたら永続化されたデータに対して大規模な更新処理をする必要はなく、ファイルシステム上から時間で区切られたファイルがただ単に削除されます。
最後にInfluxDBがクラスター構成で運用されている際には、障害発生時に可用性および堅牢性が保たれるようにデータを複数サーバーで複製します。
オプションとして指定できるデータ保存期間、保存期間内の時間ブロックの粒度、データ複製数はInfluxDBのリテンションポリシー
で設定します。
CREATE RETENTION POLICY {retention_policy_name} ON {database_name} DURATION {duration} REPLICATION {n} [SHARD DURATION {duration}] [DEFAULT]
※訳注: 表示上の問題から原文の<
, >
を{
, }
に変えて表示
duration
はオプションで指定するデータ保持期間です(データを破棄しないのであれば、duration
はINF
に設定してください)。SHARD DURATION
はデータ保持期間内のデータの粒度です。例えば、24時間のduration
でshard duration
を1時間に設定すると、データベースは24の1時間のシャードで保存するよう設定します。毎時間一番古いシャードがデータベースから削除されます。レプリケーションファクター、つまりクラスター内でシャードの複製をいくつ保持するか、を設定するにはREPLICATION
を指定してください。
具体的には、データベースは次の物理配置でディスク上にデータを作成します。
'' Database director /db
'' Retention Policy directory /db/rp
'' Shard Group (time bounded). (Logical)
'' Shard directory (db/rp/Id#)
'' TSM0001.tsm (data file)
'' TSM0002.tsm (data file)
'' …
メモリー内のキャッシュ
はディスクにTSM形式でフラッシュされます。フラッシュが完了すると、フラッシュしたポイントはキャッシュ
および対応するWAL
から削除されます(WALとキャッシュはシャードごとに管理されます)。TSMのデータファイルはポイントを列指向に構成した上で保存しています。一度書き込まれればTSMファイルは以後変更されません。TSMのファイル形式についての詳細についてはInfluxDBのドキュメントをご確認ください。
TSMデータを圧縮する
キャッシュ
は比較的少量のデータです。TSMの列指向の形式はある1つのブロックのシリーズに長期間のデータを保存するとき一番うまく動作します。期間が長くなれば圧縮効率がよくなり、クエリーに対するフィールドをスキャンする時間を低減できます。TSMの形式は基本的にlog-structured merge-treeアルゴリズムに大きく依存しています。新しい(レベル1の
)TSMファイルはキャッシュがフラッシュされた際に生成されます。これらのファイルは後ほどレベル2のファイルに結合(圧縮
)されます。レベル2のファイルはさらに、レベル3
のファイルに結合されます。高位の圧縮はファイルが大きくなり結果としてコールドに(そのタイムレンジが書込みに対してホットでなくなった場合)なった際に発生します。上記で参照しているドキュメントで、圧縮についての詳細がご覧になれます。
TSMの圧縮のソースコード内では多くのロジックがあり高度化されています。しかし、高位のゴールはとてもシンプルです。すなわち、あるシリーズに対して圧縮効率およびクエリーに対する読込性能が最善となるよう長期間に渡りデータを統合し最適化する、ということです。
パート1のまとめ
まとめとしては、ポイント
がバッチでInfluxDBにPOSTされます。このバッチはすぐに永続化するためにsnappyアルゴリズムで圧縮されWAL
として書込まれます。ポイントは新しく書き込まれたポイントに対してすぐにクエリーが発行可能となるよう、メモリー内のキャッシュ
にも書き込まれます。キャッシュ
は定期的にTSM
ファイルにフラッシュされます。TSM
ファイルが蓄積されると、これらは結合そして圧縮
され高位のTSM
ファイルとなります。TSM
のデータはシャード
に分かれて保存されており、シャード
でカバーされる時間レンジやクラスター構成の際のレプリケーションファクターがリテンションポリシー
として設定されます。
この投稿がInfluxDBが書き込みに対して、どのようにデータを受け取り永続化しているかについての説明としてお役に立てればと思います。次の投稿では、参照、更新、削除の操作をどのように実現しているかを取り扱う予定です。