この記事で扱う内容
時系列データの管理に関して、以下の2点について扱います。この二つの観点は関連しています。
- 分散環境における管理方法
- データ保存期間
分散環境における時系列データの管理方法
分散データベースでは、データのパーティショニング(あるいはシャーディング)が行われます。
このパーティショニングは、(明示的にであれ、潜在的にであれ)何らかの値をもとに行われます。
Apache Cassandraでは、明示的に、パーティションの基準とする値に用いるキーを指定します。
時系列データを管理する場合のパーティションキー設計のパターンとして「タイムバケッティング(time bucketing)」があります。
CREATE TABLE device (
deviceid INT,
monthbucket TEXT,
timestamp TIMESTAMP,
...
PRIMARY KEY ((deviceid,monthbucket),timestamp));
ここでmonthbucket
には、例えば202308
のようにtimestamp
値を構成する年と月のデータを格納することが考えられます(これは、あくまで例であり、後述のデータ保存期間との関係で、異なる粒度を選択することが考えられます)。
このような設計にすることにより、以下の2点の効果があります。
- 検索性能
- データ分散
検索性能
データ検索時に限られたパーティション(/ノード/物理サーバ)にアクセスすれば済むため、検索性能があがります。
データ分散
上述の検索性能を実現するだけであれば、timestamp
カラム自体をパーティションキーにすることが考えられます。しかし、少し考えればわかるように、これはパーティションキーの種類が、すぎに膨大になり、無限に増殖することを意味します。一般にこのようにタイムスタンプ値自体をパーティショニングの基準にすることはアンチパターンといえます。「タイムバケッティング(time bucketing)」の手法を用いることで、このアンチパターンを回避しつつ、時系列情報を検索に用いることができます。
実例
以下は、クエリの例です。monthbucket
を検索に用いると同時にtimestamp
でより詳細な時間を指定します。そのために、timestamp
カラムは検索可能なカラム(Cassandraにおけるクラスタリングキー)として設定されている必要があります。
SELECT * FROM device
WHERE deviceid='123' AND monthbucket='202303'
AND timestamp >= '2023-03-01 00:00:00-0500'
AND timestamp < '2023-03-16 00:00:00-0500';
分散環境における時系列データの保存方法
問題
時系列データの管理においては、データが持続的に増え続けることへの考慮が必要です。
つまり、特に何の配慮も行わない場合、検索性能は、(どれだけ技術的な最適化が行われていたとしても)論理的に下がり続けることになります。
ここでは、時系列データを管理するためのひとつのパターンについて紹介します。
データ管理において、よくある考え方としては、古いデータを退避する、というものがあります。このことによって、そのテーブルのデータの量は一定量に保たれ、検索性能について、一貫した性能を期待することができます。
よくある手法では、テーブルから古くなったデータを抽出し、オブジェクトストアなどの他の環境に保存し、元のテーブルから削除するという方法があります。この場合、以下の2点について考慮する必要があります。
- データの退避(移動)方法(ETLなどの活用)
- (退避先からの)データの検索方法(データベースとは別の検索方法)
これらは、時系列データを管理するデータベースとは、他の技術によって実現することになります。
TTL利用
Apache Cassandraのように、データベースにはテーブルのデータに有効期限/TTL(time to live)を指定することによって、一定期間の後に、有効期限が過ぎたデータを削除する機能があります。
データの格納時に、TTLが設定されたテーブルと、TTLが設定されていないテーブルの二つにデータを格納することによって、上述の二つの問題を同時に解決することができます。
この二つのテーブルは、以下のようなイメージになります。
LATEST_DATA_WITH_TTL
HISTORICAL_DATA_WITHOUT_TTL
例えば、このテーブルへのクエリを行う要件の大部分(90%以上など)が、過去1か月のデータへのクエリである場合、TTLとして2か月程度(単純に現在時点から1か月前ではなく「先月のデータ」という要件も考慮すべき)を設定することが考えられます。このTTL期間設定は、クエリ要件と照らし合わせて、設計することになります。
この手法は、過去のデータをつねに(多少の検索性能は犠牲としても)アクティブな状態にしておきたいという要件を(オブジェクトストアへの別の検索手段を講じずに、たんに検索先テーブルを変更するだけで)満たすことができます。
また、このような手法と、従来の外部へのデータ退避とを組み合わせることも考えることができます。例えば、数か月前のデータをHISTORICAL_DATA_WITHOUT_TTL
に移すことで、クエリの90%は、LATEST_DATA_WITH_TTL
へのクエリとして予想された性能を確保します。その後、HISTORICAL_DATA_WITHOUT_TTL
へのクエリ要件において、数年前のデータへのクエリ要件が例えば、1%以下であれば、その期間を超えるデータは、オブジェクトストアへ退避して、データベースの無制限のデータ容量を避けながら、1%以下のデータ検索の要件に対しては、マニュアル操作によるデータ復帰プロセスを含めて、例えばリクエストから一週間でデータ提供、といったサービスレベルを定めることが考えられます。
また、このことによりデータ退避処理期間中にテーブルへの検索性能が下がるといった問題についても、(検索要件の90%で)避けることができます。
参考情報