0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TimescaleDBを用いた工場のセンサー時系列データ収集とGrafana可視化ダッシュボードの構築

0
Posted at

TimescaleDBを用いた工場のセンサー時系列データ収集とGrafana可視化ダッシュボードの構築

Feature(197).png

はじめに

こんにちは、NKKTech Global 技術チームです。

製造現場のIoT化において、エンジニアが直面するデータベース選定の課題は以下の2点に集約されます。

  1. 秒間数万件の時系列データを高速にINSERTでき、数か月分のデータをストレージを圧迫せずに保持したい
  2. センサー値だけでなく、「設備型番」「担当ライン」「閾値マスタ」などの業務データと標準SQLでJOINしたい

InfluxDBなどのNoSQL時系列データベースは時系列の書き込みには強いものの、マスタデータとのリレーショナル結合が困難です。一方、PostgreSQLの拡張機能である TimescaleDB は、「完全なPostgreSQL互換(SQL/JOIN可能)」を保ちながら、時系列データの書き込み・集計速度を10〜100倍に高め、最大90%以上のデータ圧縮を実現します。

本記事では、工場センサーデータをTimescaleDBに蓄積し、Grafanaで瞬時に描画するための設計と実装を完全解説します。


1. システム全体アーキテクチャ

工場現場(OT)からクラウド/オンプレミス可視化基盤(IT)までのパイプライン構成です。


2. TimescaleDBのセットアップとHypertable設計

① テーブル作成とHypertableへの変換

まずは通常のPostgreSQLテーブルを作成し、TimescaleDBの核となる Hypertable(ハイパーテーブル) へ変換します。Hypertable化することで、指定した時間間隔(デフォルト7日)ごとに内部でテーブルが自動パーティショニング(チャンク分割)され、B-Treeインデックスの肥大化を防ぎます。

-- 1. TimescaleDB拡張の有効化
CREATE EXTENSION IF NOT EXISTS timescaledb;

-- 2. 設備マスタテーブル(通常のPostgreSQLリレーショナルテーブル)
CREATE TABLE IF NOT EXISTS equipment_master (
    equipment_id VARCHAR(50) PRIMARY KEY,
    line_name VARCHAR(50) NOT NULL,
    model_name VARCHAR(100),
    install_date DATE,
    critical_level INT DEFAULT 1
);

-- 3. センサー時系列テーブル
CREATE TABLE IF NOT EXISTS sensor_metrics (
    recorded_at TIMESTAMPTZ NOT NULL,
    equipment_id VARCHAR(50) NOT NULL,
    temperature NUMERIC(5,2),
    vibration_rms NUMERIC(6,3),
    current_ampere NUMERIC(5,2),
    CONSTRAINT fk_equipment FOREIGN KEY (equipment_id) REFERENCES equipment_master (equipment_id)
);

-- 4. Hypertableへの変換 (時間列: recorded_at, チャンク期間: 1日)
SELECT create_hypertable(
    'sensor_metrics', 
    by_range('recorded_at', INTERVAL '1 day')
);

-- 5. 高速検索用複合インデックス
CREATE INDEX IF NOT EXISTS idx_sensor_equipment_time 
ON sensor_metrics (equipment_id, recorded_at DESC);

3. 本番運用の必須機能:圧縮とContinuous Aggregates

数か月〜数年分のデータを運用する場合、ストレージの枯渇と描画遅延を防ぐために以下の2つの設定が必須です。

① ネイティブ・カラムナー圧縮(Compression Policy)

時系列データは類似した値が連続するため、カラムナ形式に変換することで90%以上のストレージ削減が可能です。

-- 1. 圧縮設定の有効化 (設備IDごとにソートして圧縮)
ALTER TABLE sensor_metrics SET (
    timescaledb.compress,
    timescaledb.compress_segmentby = 'equipment_id',
    timescaledb.compress_orderby = 'recorded_at DESC'
);

-- 2. 7日以上前のチャンクを自動圧縮するポリシーを追加
SELECT add_compression_policy('sensor_metrics', INTERVAL '7 days');

② 継続的集計(Continuous Aggregates)

Grafanaで「過去1か月間の温度推移」を表示する際、数億レコードの生データをスキャンすると数十秒かかります。バックグラウンドで自動集計されるマテリアライズドビューを定義します。

-- 5分単位の平均・最大・最小値を保持する集計ビュー
CREATE MATERIALIZED VIEW sensor_metrics_5min
WITH (timescaledb.continuous) AS
SELECT
    time_bucket('5 minutes', recorded_at) AS bucket,
    equipment_id,
    AVG(temperature) AS avg_temp,
    MAX(temperature) AS max_temp,
    AVG(vibration_rms) AS avg_vibration,
    MAX(vibration_rms) AS max_vibration
FROM sensor_metrics
GROUP BY bucket, equipment_id
WITH NO DATA;

-- 毎分自動更新するポリシーの追加 (直近1時間〜過去1か月の範囲を更新)
SELECT add_continuous_aggregate_policy('sensor_metrics_5min',
    start_offset => INTERVAL '1 month',
    end_offset   => INTERVAL '5 minutes',
    schedule_interval => INTERVAL '1 minute');

4. 高速データ取り込みパイプライン(Python)

エッジから送られてくる大量のJSONデータを、単一INSERTではなく**バッチ実行(copy または execute_values)**で秒間数万レコード規模まで引き上げます。

import asyncio
import asyncpg
from datetime import datetime, timezone

DATABASE_URL = "postgresql://postgres:password@localhost:5432/factory_iot"

async def bulk_insert_metrics(records):
    """
    records: List of tuples (recorded_at, equipment_id, temp, vib, amp)
    """
    conn = await asyncpg.connect(DATABASE_URL)
    try:
        # asyncpgのcopy_records_to_tableによる超高速バイナリインポート
        await conn.copy_records_to_table(
            'sensor_metrics',
            records=records,
            columns=['recorded_at', 'equipment_id', 'temperature', 'vibration_rms', 'current_ampere']
        )
    finally:
        await conn.close()

# 実行シミュレーション
async def main():
    now = datetime.now(timezone.utc)
    # サンプルバッチデータ作成
    batch_data = [
        (now, f"LINE_A_MC_0{i%5+1}", 65.5 + i*0.1, 1.25, 14.8)
        for i in range(1000)
    ]
    await bulk_insert_metrics(batch_data)
    print("1,000 records successfully ingested via COPY.")

if __name__ == "__main__":
    asyncio.run(main())

5. Grafanaダッシュボードの構築とSQLクエリ設計

Grafanaのデータソースに「PostgreSQL」を選択し、TimescaleDBオプションを有効にします。

① マスタ結合を用いたリアルタイム時系列グラフ

Grafanaの標準マクロ $__timeFilter と TimescaleDB固有の time_bucket を組み合わせます。

SELECT
    $__timeFilter(bucket) AS "time",
    CONCAT(m.line_name, ' - ', m.model_name, ' (', s.equipment_id, ')') AS metric,
    s.avg_temp AS "平均温度 [℃]"
FROM sensor_metrics_5min s
JOIN equipment_master m ON s.equipment_id = m.equipment_id
WHERE
    $__timeFilter(s.bucket)
    AND m.line_name = '$SelectedLine' -- Grafanaダッシュボード変数
ORDER BY 1;

② 異常予兆の警告パネル(Stat Panel)

振動値が警戒値を超えている設備の最新ステータスを表示します。

SELECT
    m.equipment_id AS "設備ID",
    m.line_name AS "ライン",
    s.vibration_rms AS "最新振動RMS",
    CASE 
        WHEN s.vibration_rms > 4.5 THEN '危険 (Critical)'
        WHEN s.vibration_rms > 2.8 THEN '注意 (Warning)'
        ELSE '正常 (Normal)'
    END AS "ステータス"
FROM (
    SELECT DISTINCT ON (equipment_id) equipment_id, vibration_rms, recorded_at
    FROM sensor_metrics
    ORDER BY equipment_id, recorded_at DESC
) s
JOIN equipment_master m ON s.equipment_id = m.equipment_id
ORDER BY s.vibration_rms DESC;

6. 本番運用のベストプラクティス

  1. チャンクサイズの調整基準:
    1つのチャンク(テーブルパーティション)のインデックスとデータが、サーバーのRAM容量の25%程度に収まるように時間範囲(chunk_time_interval)を設定します(例: メモリ32GB環境で1日あたり数GBのデータ量なら1日単位が最適)。
  2. 自動保持ポリシー(Data Retention):
    「生データは3か月で削除し、集計ビュー(Continuous Aggregate)は2年間保持する」設定を行うことで、ストレージコストを一定に保ちます。
    SELECT add_retention_policy('sensor_metrics', INTERVAL '90 days');
    
  3. PgBouncerによるコネクションプール:
    多数のエッジゲートウェイやワーカープロセスから同時接続される場合、PostgreSQLのプロセス枯渇を防ぐため、必ず手前にPgBouncerを配置してください。

まとめ:OTデータの真価は「SQLで語れること」にある

工場のIoT化を成功に導く最大のポイントは、「時系列センサー値」と「工場の生産管理コンテキスト」をシームレスに結合できるアーキテクチャを選択することです。

  • TimescaleDBのHypertableで、秒間数万件のインジェストに耐えうる時系列性能を確保する。
  • Continuous Aggregates & Columnar Compressionで、Grafanaの超高速描画とストレージの省力化を実現する。
  • PostgreSQL互換の標準SQLを活用し、設備マスタや保全履歴と瞬時に紐付ける。

NKKTech Globalでは、製造業に向けたエッジゲートウェイの設計から、TimescaleDBを用いた大規模IoT基盤の構築、Grafanaダッシュボードの導入支援までを一気通貫で支援しています。


お問い合わせ先

工場IoT・センサーデータ可視化基盤の構築、TimescaleDBの設計・性能チューニング、スマートファクトリー化のご相談は、下記よりお気軽にお問い合わせください。

著者:NKKTech Global 技術チーム
私たちは、強固なデータ基盤と確かなIoTエンジニアリングで、製造業のデータドリブン経営をグローバルに支援します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?