データベース

OpenTSDB

概要

OpenTSDBは、Apache HBaseをベースとして構築された分散・スケーラブルな時系列データベースです。StumbleUponによって2010年に開発され、数十億のデータポイントを効率的に保存・処理できる能力を持ちます。IoTデバイス、サーバー監視、アプリケーションメトリクスなど、大量の時系列データを扱うシステムに最適化されています。

詳細

主要特徴

  • 無制限のスケーラビリティ: HBaseの分散アーキテクチャを活用し、ノードを追加するだけで線形にスケール
  • 高いカーディナリティ: タグ(キー・バリューペア)による柔軟なデータ識別が可能
  • 生データの保持: デフォルトで集約せずに元のデータを保存
  • 強力なクエリ機能: HTTP APIやコマンドライン経由での複雑な集約・フィルタリング
  • プラグインシステム: 認証、検索、リアルタイム配信などのカスタム拡張に対応
  • コマンドラインツール: データインポート、クエリ、UID管理など包括的なツール群

アーキテクチャ

OpenTSDBは3つの主要コンポーネントで構成されています:

  • tCollector: 各サーバーに配置され、メトリクスデータを定期的に収集
  • TSD (Time Series Daemon): データを受信してHBaseに保存、クエリ処理を担当
  • HBase: バックエンドストレージシステムとして動作

データモデル

時系列データは以下の要素で識別されます:

  • メトリクス名: 測定対象(例:cpu.usage、memory.free)
  • タグ: key=valueペアによる識別子(例:host=web01、region=us-east)
  • タイムスタンプ: データポイントの時刻
  • : 測定値

効率的な保存のため、文字列名は一意のバイナリID(UID)にマッピングされます。

メリット・デメリット

メリット

  • 卓越したスケーラビリティ: 1秒間に数百万の書き込みを処理可能
  • HBaseの成熟したエコシステム: 豊富な運用ノウハウとツール
  • 柔軟なタグシステム: 高いカーディナリティに対応
  • 長期保存: データ保持期間に制限なし
  • オープンソース: 無料で利用可能、アクティブなコミュニティ
  • RESTful API: 簡単な統合とクエリが可能
  • プラグイン対応: カスタマイズ性が高い

デメリット

  • 複雑なセットアップ: HBaseクラスタの構築・運用が必要
  • 高いハードウェア要件: 最低4GB RAM推奨、本格運用には更に多くのリソースが必要
  • 学習コストの高さ: HBaseとOpenTSDBの両方の知識が必要
  • リアルタイム性の制約: バッチ指向のため、極めて低遅延が必要な用途には不向き
  • SQL未対応: 独自のクエリ構文を学習する必要
  • InfluxDBやTimescaleDBと比較してモダンさに欠ける: 新しい時系列DBに比べて設計が古い

主要リンク

書き方の例

インストール・セットアップ

前提条件

# Java 8以上が必要
java -version

# HBase 0.94以上が必要
# ZooKeeperクラスタも事前に構築

Dockerを使用した簡単セットアップ

# OpenTSDBコンテナを起動
docker run -d \
  --name opentsdb \
  -p 4242:4242 \
  petergrace/opentsdb-docker

# Webインターフェースにアクセス
# http://localhost:4242

設定ファイル(/etc/opentsdb/opentsdb.conf)

# HBaseへの接続設定
tsd.storage.hbase.zk_quorum = localhost:2181
tsd.storage.hbase.zk_basedir = /hbase

# ポート設定
tsd.network.port = 4242

# 新しいメトリクスの自動作成
tsd.core.auto_create_metrics = true

# メタデータキャッシュの有効化
tsd.core.meta.enable_realtime_ts = true

基本操作(データ挿入・クエリ)

データ挿入(HTTP API)

# 単一データポイントの挿入
curl -X POST http://localhost:4242/api/put \
  -H "Content-Type: application/json" \
  -d '{
    "metric": "cpu.usage",
    "timestamp": 1609459200,
    "value": 45.2,
    "tags": {
      "host": "web01",
      "region": "us-east"
    }
  }'

# 複数データポイントの一括挿入
curl -X POST http://localhost:4242/api/put \
  -H "Content-Type: application/json" \
  -d '[
    {
      "metric": "memory.usage",
      "timestamp": 1609459200,
      "value": 78.5,
      "tags": {"host": "web01", "type": "physical"}
    },
    {
      "metric": "memory.usage", 
      "timestamp": 1609459260,
      "value": 79.1,
      "tags": {"host": "web01", "type": "physical"}
    }
  ]'

Telnetインターフェース経由での挿入

# Telnetクライアントでの接続
telnet localhost 4242

# データフォーマット: put <metric> <timestamp> <value> <tag1=value1> [<tag2=value2>...]
put cpu.usage 1609459200 45.2 host=web01 region=us-east
put memory.free 1609459260 2048 host=web01 type=available

データクエリ

# 基本的なクエリ
curl "http://localhost:4242/api/query?start=1h-ago&m=avg:cpu.usage{host=web01}"

# 複数メトリクスのクエリ
curl "http://localhost:4242/api/query?start=1d-ago&m=avg:cpu.usage{host=*}&m=avg:memory.usage{host=*}"

# 集約関数を使用したクエリ
curl "http://localhost:4242/api/query?start=6h-ago&m=avg:rate:network.bytes.in{interface=eth0}"

データモデリング

効果的なタグ設計

// 良い例:適切な粒度のタグ
{
  "metric": "http.requests",
  "tags": {
    "method": "GET",
    "status": "200", 
    "endpoint": "api",
    "datacenter": "us-east-1"
  }
}

// 避けるべき例:高すぎるカーディナリティ
{
  "metric": "http.requests",
  "tags": {
    "user_id": "12345",  // ユーザーIDは数百万になる可能性
    "request_id": "abc123" // リクエストIDは無限に増加
  }
}

メトリクス命名規則

# 階層的な命名(ドット区切り)
system.cpu.usage
system.memory.free
app.response_time
database.connections.active
cache.hits_per_second

# プレフィックスでカテゴリ分け
prod.web.cpu.usage
dev.api.response_time
monitoring.alerts.count

メトリクス収集

アプリケーション統合例(Java)

import net.opentsdb.client.*;

public class MetricsCollector {
    private OpenTSDBClient client;
    
    public MetricsCollector() {
        this.client = new OpenTSDBClient("localhost", 4242);
    }
    
    public void recordMetric(String metric, double value, Map<String, String> tags) {
        DataPoint point = new DataPoint(metric, System.currentTimeMillis() / 1000, value, tags);
        client.put(point);
    }
    
    // CPU使用率の送信例
    public void sendCpuUsage() {
        Map<String, String> tags = new HashMap<>();
        tags.put("host", "app-server-01");
        tags.put("environment", "production");
        
        double cpuUsage = getCpuUsage(); // システムからCPU使用率を取得
        recordMetric("system.cpu.usage", cpuUsage, tags);
    }
}

Pythonクライアントの例

import requests
import time
import json

class OpenTSDBClient:
    def __init__(self, host='localhost', port=4242):
        self.base_url = f"http://{host}:{port}"
    
    def put(self, metric, value, tags, timestamp=None):
        if timestamp is None:
            timestamp = int(time.time())
        
        data = {
            "metric": metric,
            "timestamp": timestamp,
            "value": value,
            "tags": tags
        }
        
        response = requests.post(
            f"{self.base_url}/api/put",
            json=data,
            headers={'Content-Type': 'application/json'}
        )
        return response.status_code == 204

# 使用例
client = OpenTSDBClient()
client.put("temperature", 23.5, {"sensor": "room1", "building": "office"})
client.put("humidity", 65.2, {"sensor": "room1", "building": "office"})

実用例

システム監視のダッシュボード構築

# Grafanaとの連携設定
# OpenTSDBデータソースの設定
curl -X POST http://admin:admin@localhost:3000/api/datasources \
  -H "Content-Type: application/json" \
  -d '{
    "name": "OpenTSDB",
    "type": "opentsdb",
    "url": "http://localhost:4242",
    "access": "proxy"
  }'

アラート設定

# Nagiosプラグインを使用したアラート
./check_tsd -H localhost -p 4242 -m cpu.usage -t host=web01 -w 80 -c 90

# カスタムアラートスクリプト
curl "http://localhost:4242/api/query?start=5m-ago&m=avg:cpu.usage{host=web01}" | \
jq '.[] | if .dps | to_entries | .[-1].value > 90 then "CRITICAL: CPU > 90%" else "OK" end'

ベストプラクティス

パフォーマンス最適化

# 設定ファイルの最適化
# バッチサイズの調整
tsd.storage.flush_interval = 1000

# 圧縮の有効化
tsd.storage.enable_compaction = true

# キャッシュサイズの調整
tsd.core.meta.cache.enable = true
tsd.core.meta.cache.size = 1000000

運用監視

# OpenTSDB自体の監視
curl "http://localhost:4242/api/stats"

# HBaseの状態確認
echo "status" | hbase shell

# ログ監視
tail -f /var/log/opentsdb/opentsdb.log

データ保持ポリシー

# 古いデータの削除(HBaseのTTL設定)
echo "alter 'tsdb', {NAME => 'f', TTL => 31536000}" | hbase shell  # 1年間保持

# データのコンパクション実行
tsdb fsck --fix-duplicates --compact

スケーリング戦略

# 複数TSDインスタンスの負荷分散設定
# ロードバランサー(HAProxy)設定例
backend opentsdb_cluster
    balance roundrobin
    server tsd1 192.168.1.10:4242 check
    server tsd2 192.168.1.11:4242 check
    server tsd3 192.168.1.12:4242 check