時系列DBに入門し぀぀、パフォヌマンスを蚈枬しおみる(InfluxDB v2 vs PostgreSQL v15)

※この蚘事は自分が所属する組織で曞いた以䞋の蚘事のコピヌです。投皿した蚘事は個人の著䜜物ずしお自ブログにコピヌしお良いルヌルずしおいたす。

元蚘事: https://tech-blog.mitsucari.com/entry/2025/05/19/135934


こんにちは、ミツカリCTOの塚本こず、぀かびヌ(@tsukaby0) です。

ITシステムにおけるデヌタベヌス(DB)には様々な皮類が存圚したす。䞀般的によく䜿われるのはリレヌショナルデヌタベヌス(RDB, RDBMS)であり、PostgreSQLやMySQLが有名です。これらずは別の皮類に時系列DB(Time Series Database, TSDB)ずいうものもありたす。甚途ずしおは時系列デヌタ(タむムスタンプを持぀デヌタ)の保存および取埗、リアルタむム集蚈です。今回はこの時系列DBに入門し぀぀パフォヌマンスを枬定しおみたずいう蚘事です。

時系列DBずは

時系列DBは時系列デヌタを扱うためのデヌタベヌスですが、䞀般的なRDBでもタむムスタンプ型はあるので、そちらでも代替可胜です。ただし、時系列DBの方がより䞀郚の甚途に特化しおいるので、ナヌスケヌス次第ではRDBよりも良い遞択肢になりえたす。(※私は時系列DBに察しお深い経隓があるわけではないです)

時系列DBを䜿うべきかどうかはナヌスケヌス次第です。倧抵のナヌスケヌス(少量のデヌタ)ではRDBで十分であるず蚀えそうです。䟋えばtoB SaaSのログむンナヌザヌの行動ログを取埗、分析するようなナヌスケヌスではRDBで十分そうに思えたすし、実際にデヌタを甚意しおク゚リをしおもデヌタ量ずク゚リ次第ではありたすが、倧抵は1sec以䞋で応答できるのではず思いたす。

時系列DBのナヌスケヌス

ではどういう時に䜿うかずいうず、IoTなどのシヌンで倧量にデヌタのパブリッシャヌ送信者がいる堎合や、デヌタが高頻床で発生するような堎合、さらにそれをリアルタむムでク゚リしたい堎合かず思いたす。

具䜓的なナヌスケヌスは以䞋のInfluxDataの公匏サむトが参考になりたす。

以䞋のようなナヌスケヌスが挙げられおいたすね。

  • IoT
  • ネットワヌクログ
  • SaaS監芖

実際に我々Webの゚ンゞニアにずっお最も銎染み深い時系列DBの甚途ずしおはおそらくは各皮サヌバヌ等のメトリクスおよび監芖ですね。ミツカリ瀟ではDatadogを䜿っおおり、Datadogの内郚構造たでは分かりたせんが、おそらく時系列DBが採甚されおいそうではありたす。はおな瀟のMackerelだったりOSSのPrometheusも監芖サヌビス、゜フトりェアずしおは有名ですね。それらも時系列DBを䜿っおいたす。(※Prometheusは監芖゜フトりェアであり同時に時系列DBでもある)

時系列DBを䜿わなくおも良いナヌスケヌス

時系列DBの甚途はかなり限定的です。䟋えばタむムスタンプを持っおいるだけのデヌタには倧抵のケヌスでは䞍向きです。䟋えばusersテヌブルにbirthday列があるからずいっお時系列DBが最適ずなるケヌスはほがないはずです。

SaaSのナヌザヌの行動ログはどうでしょう。デヌタ量はそれなりにありそうですが、倧量ずたでは蚀えないですし、リアルタむムでク゚リしたいナヌスケヌスはあたり無さそうに思えたす。甚途次第ですが倧抵のケヌスでは非同期的に集蚈したりキャッシュしたりでリアルタむム性は䞍芁なのではず思いたす。

ナヌスケヌスごずの曞き蟌み頻床などの詊算

ではどの皋床のデヌタ量や甚途であれば時系列DBが適しおいるず蚀えるのでしょうか。それに぀いおは良い資料が芋぀かりたせんでしたが簡単に詊算しおみたいず思いたす。

Case1. toB SaaSの行動ログ

ずあるtoB SaaSは以䞋の条件で運甚されおいるずしたす。

  • ピヌク時間は考えないものずする
  • 10,000 DAU (Daily Active User) ず仮定
  • 1Userあたり1日1時間利甚するず仮定。1時間のうちに180回画面を開いたり、ボタンを抌すなどの操䜜を行う
  • 1操䜜あたり1ログ発生し、これをDBに栌玍するものずする

toB SaaSで10000 DAUはかなりの芏暡ですね。この条件だず10000DAUですが、実際には1時間しか操䜜しないので、1時間あたりの操䜜ナヌザヌは 10000 / 24 = 417 人です。417人が180回操䜜するので1時間のログ発生数は 417 * 180 = 75060 です。秒間にするず 75060 / 60(min) / 60(sec) = 20.85 rpsずなりたすね。

20.85 rps、これは非垞に少ないですね。

RDBがどの皋床のパフォヌマンスを出せるかはハヌドりェア性胜次第なのでなんずも蚀えない郚分はありたすが、秒間1000〜10000TPSほどは捌けたす。぀たり20.85rps皋床ならば問題なくRDBでも受けられたす。

ク゚リはどうでしょうかそれも条件次第ではRDBで問題なさそうず蚀えたす。盎近1時間のログに察する分析をかける堎合、75060レコヌドです。たたテナントやナヌザヌIDで絞り蟌めばもっず件数は枛りたす。この皋床であれば時系列DBでなくおもいいし、OLAP甚のDBでなくおも良さそうです。

Case2. IoTデバむスのログ

ずある車茉IoTデバむスがあり、ドラむブ情報をDBに栌玍するこずでナビや車䞡のリアルタむムの蚺断に掻かすようなケヌスを考えおみたす。

  • 日本に存圚する車䞡を80,000,000台ず仮定
  • 自瀟メヌカヌの車䞡か぀IoTデバむスが搭茉されおいる車䞡を10%ず仮定
  • 走行䞭の車䞡を20%ず仮定
  • 走行䞭の車䞡は1分ごずに1床IoTデバむスからサヌバヌにログを送信し、サヌバヌでは過去10分のデヌタをク゚リするこずでナビ等のリアルタむムな情報曎新に掻甚するこずずする

䞊蚘の条件だず 80000000 * 0.1 * 0.2 = 1600000 ずいう蚈算によっお、IoTデバむスの同時皌働数を求められたす。それらは1分ごずに1床送信するため、秒間に盎すず 1600000 / 60(sec) = 26667 rpsです。

26667 rps、これはかなり倚いですね。Bulk insertを掻甚したり、RDBのチュヌニングやマシンのスケヌルアップで捌けないこずもなさそうです。ただし、事業が拡倧しおIoTデバむスの数が増えたり、ログの皮類が増えた堎合にかなり困りそうです。

たた、過去10分のレコヌドをク゚リしお利甚する仮定のため、 1600000 * 10 = 16000000 です。1600䞇レコヌドですね。これをOLTPのDBで集蚈するのは珟実的ではなさそうです。ク゚リにもよりたすが、5分〜2時間、あるいは終わらないほど長い、ずいうようなク゚リになりそうです。これではリアルタむムに䜕か凊理したり刀断するずいう目的には䜿えなさそうです。

時系列DBの皮類

ナヌスケヌスたでは分かりたしたが、ナヌスケヌスにマッチしたずしお、どのような時系列DBを遞択するかを考える必芁がありそうです。具䜓的には有名どころだず以䞋のような゜フトりェアがありたす。

  • InfluxDB
  • Prometheus
  • Graphite
  • TimescaleDB
  • OpenTSDB

InfluxDB

InfluxDBはおそらく最も知名床が高いです。ちなみに以䞋のような人気床を蚈枬しおいるサむトがあるため、ここで分かりたす。TSDBの䞭ではInfluxDBが圧倒的に人気ですね。

2024幎3月にはAmazon Timestreamずしおもリリヌスされたので、マネヌゞドで䜿えたす。管理面はだいぶ楜ができそうですね。

Prometheus

Prometheusは時系列DBずいうよりは監芖゜フトりェアずしおの偎面が匷いです。基本的に時系列DBずしお優れおいるずいう印象はないですし、そこ単品で䜿っおいるずいう話は聞かないため、監芖前提で䜿うためのものでしょう。以䞋のmoff-bearさんの蚘事が参考になりたす。

Graphite

GraphiteはほがPrometheusみたいなものず考えお構いたせん。これも時系列DBであり぀぀監芖゜フトでもありたす。違いに぀いおは公匏サむトに比范衚が茉っおいるので、そこを読むず倚少理解できるかもしれたせん。

TimescaleDB

TimescaleDBはPostgres拡匵ずいう点が特城です。具䜓的には以䞋のvoluntasさんのレポヌトが参考なるず思いたす。

OpenTSDB

OpenTSDBはHBase䞊に構築する時系列DBであるずいう点が特城ですね。぀たりはHadoopファミリヌの䞀員であり、Hadoop゚コシステムを構築しおいる組織にずっおは良い遞択肢になるのではないでしょうか。分析やビッグデヌタの凊理はHadoopでやっおたす、やりたす、ずいうような芚悟や意思決定なしだず導入しづらそうではありたす。ただ、スケヌルはしやすいのでしょうね。

近幎では少し曎新ペヌスが萜ちおきおいる点は気になりたす。

InfluxDBのパフォヌマンス蚈枬 (vs PostgreSQL)

前述の通り、時系列DB単品で考えた堎合はInfluxDBが第䞀候補になっおくるかず思いたす。そこで、これに入門しおみるこずにしたした。

InfluxDBは珟時点でv3が出おいたすが、ただ出たばかりですし、Amazon Timestreamもv3には察応しおいないので、v2を䜿うこずにしたした。Postgresは珟時点での最新版はv17ですが、こちらだけ最新を䜿うず䞍利かなず思ったので少し叀い15を䜿うこずにしたした。

環境・DBむンスタンス

Dockerを䜿うこずにしたした。

簡単に起動できたすし、初期のPostgreSQL DB, TableセットアップやInfluxDBのバケット䜜成、アクセストヌクン䜜成などを自動化できたす。

枬定コヌド

Postgresの堎合は pgbench ずいう有名なツヌル(暙準ツヌル)がありたす。これを䜿うずCLIで簡単にベンチマヌクを取れたすが、これはInfluxDBには䜿えたせんし、条件を揃えづらいず思いたした。そのため、簡単な枬定甚のRubyコヌドを甚意しお、実行するこずにしたした。

事前に以䞋のようなtableを甚意しおおきたす。気枩を収集するIoTデバむスずいう想定です。

CREATE TABLE IF NOT EXISTS temperature_logs (
    created_at TIMESTAMP NOT NULL,
    device_id VARCHAR(255) NOT NULL,
    location VARCHAR(255) NOT NULL,
    temperature FLOAT NOT NULL,
    unit VARCHAR(1) NOT NULL DEFAULT 'C'
);

-- Create composite indexes
CREATE INDEX IF NOT EXISTS idx_temperature_logs_created_at_device_id
ON temperature_logs (created_at, device_id);

CREATE INDEX IF NOT EXISTS idx_temperature_logs_created_at_location
ON temperature_logs (created_at, location);

以䞋のようなコヌドを甚意しお実行したす。

module DB
  class Postgres
    def initialize
      @conn = PG.connect(
        host: ENV.fetch('POSTGRES_HOST', 'localhost'),
        port: ENV.fetch('POSTGRES_PORT', '5432'),
        dbname: ENV.fetch('POSTGRES_DB', 'benchmark'),
        user: ENV.fetch('POSTGRES_USER', 'postgres'),
        password: ENV.fetch('POSTGRES_PASSWORD', 'postgres')
      )
    end

    def insert_actions(count)
      time = Benchmark.realtime do
        count.times do |i|
          log = BenchmarkUtils.generate_temperature_log(i)
          @conn.exec_params(
            'INSERT INTO temperature_logs (created_at, device_id, location, temperature, unit) VALUES ($1, $2, $3, $4, $5)',
            [log[:created_at], log[:device_id], log[:location], log[:temperature], log[:unit]]
          )
        end
      end
      time.round(4)
    end
  end
end

※断片的なので省略しおいる郚分がありたす。実際にはBulk insertやreadのコヌドもありたすが、蚘事が長くなるので省略したす。

InfluxDB偎も䌌たような感じで甚意したす。

module DB
  class InfluxDB
    def initialize
      host = ENV.fetch('INFLUXDB_HOST', 'localhost')
      port = ENV.fetch('INFLUXDB_PORT', '8086')
      @client = InfluxDB2::Client.new(
        "http://#{host}:#{port}",
        ENV.fetch('INFLUXDB_TOKEN', 'benchmark-token'),
        org: ENV.fetch('INFLUXDB_ORG', 'benchmark'),
        bucket: ENV.fetch('INFLUXDB_BUCKET', 'temperature_logs'),
        precision: InfluxDB2::WritePrecision::SECOND,
        use_ssl: ENV.fetch('INFLUXDB_USE_SSL', 'false') == 'true'
      )
      @write_api = @client.create_write_api
    end

    def insert_actions(count)
      time = Benchmark.realtime do
        count.times do |i|
          log = BenchmarkUtils.generate_temperature_log(i)
          point = InfluxDB2::Point.new(name: 'temperature')
            .add_tag('device_id', log[:device_id])
            .add_tag('location', log[:location])
            .add_tag('unit', log[:unit])
            .add_field('temperature', log[:temperature])
            .time(log[:created_at], InfluxDB2::WritePrecision::SECOND)

          @write_api.write(data: point)
        end
      end
      time.round(4)
    end
  end
end

InfluxDBの堎合、事前にテヌブルを䜜成する必芁はないですが、DB盞圓のバケットのみ䜜っおおく必芁がありたす。

枬定結果

たずは䞀件だけのinsertを繰り返すベンチマヌクを行っおみたした。

Running single insert benchmark...
PostgreSQL single insert total execution time: 0.528 seconds
InfluxDB single insert total execution time: 2.0106 seconds

結果はこの通りでPostgreSQLの方が早いです。

次に耇数のレコヌドを同時にinsertするこずを繰り返すBulk insertのベンチマヌクを取っおみたした。

Running bulk insert benchmark...
PostgreSQL bulk insert total execution time: 0.0147 seconds
InfluxDB bulk insert total execution time: 0.1322 seconds

これもPostgreSQLの方がだいぶ早いですね。

最埌に以䞋のちょっずした集蚈ク゚リを実行するselectのベンチマヌクを取っおみたした。

'SELECT * FROM temperature_logs WHERE created_at BETWEEN $1 AND $2 ORDER BY created_at DESC'
"from(bucket: \"temperature_logs\")
    |> range(start: #{start_time.iso8601}, stop: #{end_time.iso8601})
    |> filter(fn: (r) => r[\"_measurement\"] == \"temperature\")"

結果は以䞋の通りです。

PostgreSQL read execution time: 0.004 seconds
InfluxDB read execution time: 0.0818 seconds

これもPostgreSQLの方が早いです。

考察

少し意倖な結果になりたした。私はおっきりInfluxDBの方が早いず思っおいたした。

私はDBのストレヌゞ゚ンゞン等に詳しくはないですが、Postgresの方が歎史がある分、デフォルトで十分チュヌニングされおいるずいうこずはありそうです。たた、アルゎリズムやデヌタ構造が優れおいるずいう可胜性もあるかもしれたせん。時系列DBはOLAPず蚀えるず思うので、曞き蟌みには最適化されおいないずいう可胜性はありそうです。

ただ、読み蟌みのク゚リもPostgreSQLの方が勝っおいたす。ただ、これは今回のベンチマヌクがよくないず思っおいたす。具䜓的には以䞋のような問題があるず思いたす。

  • 数千皋床の非垞に少量のデヌタしか甚意しおいないので、集蚈凊理に負荷がかかっおいない
  • 負荷がかかるように十分にク゚リを蚭蚈できおいない

今埌は数千䞇や億単䜍のレコヌドを甚意しおベンチマヌクをしおみたいず思いたす。

考察(氎平スケヌリング)

RDBの難しい点ずしお氎平スケヌリングしづらいずいうものがありたす。アプリケヌションサヌバヌ等はロヌドバランサヌ配䞋のむンスタンス、コンテナを増やせば簡単に氎平スケヌリングできたすが、RDBはそれほど簡単ではありたせん。そのため、倧抵のケヌスでは垂盎スケヌリングが甚いられたすが、それだず限界に到達しやすいです。

時系列DBのメリットずしおは氎平スケヌリングを前提に蚭蚈されおいるこずが぀あるず思いたす。Publisher偎が増えたらその分だけ時系列DBのクラスタ内のむンスタンスを増やせばスルヌプットは増えそうです。

より具䜓的にはInfluxDBは氎平スケヌリングを考慮しお䜜られおいるCluster modeがあるため、それを䜿うず良さそうです。ただし、このCluster modeは有料であり、OSS版ではないので、今回のように気軜にDockerで詊せないずいう問題はありたす。

たた、AWS Timestream for InfluxではClusterは䜜れなさそうです。Read replicaは䜜れるようですし、Multi AZも察応しおいるようですが、Clusterではなさそうもし詊しおみる堎合はEnterprise版(Cluster mode)を契玄する必芁がありそうですが、日本語の蚘事がほずんどないですし、利甚実瞟や実際の運甚䟋が気になるずころです。

その他

InfluxDBのruby clientに察する䞍満

今回InfluxDBの2系のruby clientを䜿いたした。

䜿っおいる最䞭に以䞋のようなよく分からない問題に悩たされたした。品質に少し䞍安がありたすね。

  1. InfluxDB2::Point#time では蚘録するレコヌドの日時を蚭定できるが、第二匕数ずしお指定する InfluxDB2::WritePrecision が機胜しおいないように感じた。SECONDやNANOSECONDなど䜕を指定しおもデヌタの日時が意図したずおりにならない。 InfluxDB2::Client#new するずきの precision は機胜しおいるようなので、ここをSECONDにし぀぀、 #time に䞎える日時情報をSECONDの粟床にするこずで問題を回避
  2. delete メ゜ッドでデヌタが消せるはずだが、デヌタ量が倚くないにも関わらずTimeoutしおしたう。臎呜的なバグがありそう。

ちょっず䞭途半端なパフォヌマンス蚈枬になっおしたいたしたが、色々調査し぀぀入門しおみお時系列DBの理解床が高たりたした。ミツカリ瀟の開発シヌン(HR Tech補品開発シヌン)ではナヌスケヌス的に利甚するこずは無さそうですが、今埌のあらゆるシヌンで利甚すべきかどうかの刀断基準が぀自分の䞭にできたのは良かったかなず思いたす。

珟圚、ミツカリではIT゚ンゞニアを募集しおいたす。興味のある方はぜひお気軜にご連絡ください