TiDB HTAPリアルタイム分析実践:TiFlashからリアルタイムダッシュボードまで6つのプロダクションパターン

数据库

T+1分析は終わった、リアルタイムインサイトこそ未来

午前3時、オンライン注文が10倍に急増、CEOが聞く:「今、各カテゴリのリアルタイムGMVは?」——あなたは答えるしかない:「データはまだETLパイプラインの中、明日にならないと見られません。」

これが従来のT+1分析のジレンマ:

  • ETLパイプラインの脆弱性:Kafka → Flink → ClickHouse、どの环节が故障してもデータが途絶
  • データ遅延の制御不能:OLTPからOLAPまで、分〜時間レベルの遅延が常態
  • デュアルシステムの運用悪夢:MySQLがトランザクション、ClickHouseが分析、データ整合性は手動対応
  • コストの暴走:2つのストレージ、2つのコンピューティング、2つの運用、リソース利用率は低い
  • リアルタイム性の不足:ビジネス判断には秒単位の応答が必要、T+1レポートは過去の遺物

TiDB HTAPの約束:1つのシステムでOLTPとOLAPを同時に処理、行ストレージから列ストレージへのデータ同期遅延ゼロ。これはPPT上のアーキテクチャではなく、数千の企業でプロダクション検証済みのソリューション。


HTAPコア概念クイックリファレンス

概念 フルネーム コアの役割 例え
HTAP Hybrid Transactional/Analytical Processing 1つのシステムでトランザクションと分析を同時処理 1人がトレーダーとアナリストを兼務
TiFlash TiDB Flash 列ストレージエンジン、OLAPクエリを処理 OLAP専用アクセラレータ
TiKV TiDB Key-Value 行ストレージエンジン、OLTPトランザクションを処理 OLTPの礎
MPP Massively Parallel Processing マルチノード並列計算フレームワーク 複数人が異なるシャードを同時計算
列ストレージ Columnar Storage 列単位でデータを格納、分析クエリは必要な列のみ読み取り 必要なページだけめくる
Raft Learner Raft合意プロトコル学習者ロール TiFlashへ非同期レプリケーション、メインフローに影響なし 影の書記
データマート Data Mart 特定ビジネスドメイン向けの事前集計データセット 各部署向けのカスタムレポートショーケース

💡 JSONフォーマッターを使ってTiDB設定JSONファイルを整形し、トラブルシューティングを容易に。


従来のリアルタイム分析アーキテクチャの5つのペインポイント

ペインポイント1:ETLパイプラインが最大の単一障害点

MySQL → Canal → Kafka → Flink → ClickHouse
  │        │       │       │        │
  │        │       │       │        └─ 書き込み失敗、データロス
  │        │       │       └─ ジョブクラッシュ、データ蓄積
  │        │       └─ パーティション不均、消費遅延
  │        └─ Binlog解析エラー
  └─ レプリケーションラグ

一つでも問題が起きるとパイプライン全体が断絶。深夜のアラートは止まず、運用チームは疲弊。

ペインポイント2:データ整合性の保証不可

OLTPとOLAPは独立した2つのシステム、データ同期には遅延ウィンドウが存在:

-- MySQL: 注文が返金された
UPDATE orders SET status = 'refunded' WHERE id = 10086;

-- ClickHouse: 5分後に返金ステータスが反映
-- この5分間、レポートデータは誤り

ペインポイント3:デュアルシステムの運用コスト倍増

運用項目 MySQL ClickHouse 合計
監視・アラート Grafana + Prometheus Grafana + Prometheus 2セット
バックアップ・リカバリ mysqldump / XtraBackup clickhouse-backup 2セット
キャパシティプランニング プライマリ-レプリカ + シャーディング 分散テーブル + レプリカ 2セット
バージョンアップ ローリングアップグレード ローリングアップグレード 2セット
人員要件 DBA ClickHouseエキスパート 2チーム

ペインポイント4:クエリパフォーマンスとデータ鮮度のジレンマ

  • ClickHouseはクエリパフォーマンスを追求、MergeTreeマージが必要、データに遅延あり
  • リアルタイム性を求めるとReplacingMergeTreeを使うが、クエリにFINALが必要、パフォーマンス急落
  • リアルタイム性とパフォーマンス、二者択一

ペインポイント5:開発効率の低下

// 開発者は2つのデータモデルを保守する必要がある
public class OrderService {
    // OLTP: MySQL
    @Transactional
    public void createOrder(Order order) {
        orderMapper.insert(order);
    }
    
    // OLAP: ClickHouse - もう一度書く必要がある
    public void syncToClickHouse(Order order) {
        clickHouseMapper.insert(order);
        // フィールドマッピング、型変換、エラーハンドリング...
    }
}

6つのプロダクション級HTAP実践パターン

パターン1:TiFlash列ストレージレプリカ構築

TiFlashはRaft Learnerロールを通じてTiKVのデータ変更を非同期受信し、行ストレージから列ストレージへのリアルタイム同期を実現。

1.1 TiFlashノードのデプロイ

# tiup topology.yaml スニペット
tiflash_servers:
  - host: 10.0.1.21
    tcp_port: 9000
    http_port: 8123
    flash_service_port: 3930
    flash_proxy_port: 20170
    flash_proxy_status_port: 20292
    metrics_interval: 15
    data_dir: /data/tiflash/data
    deploy_dir: /data/tiflash/deploy
    config:
      logger:
        level: information
      storage:
        main:
          capacity: "2TB"
        latest:
          capacity: "200GB"
  - host: 10.0.1.22
    tcp_port: 9000
    http_port: 8123
    flash_service_port: 3930
    flash_proxy_port: 20170
    flash_proxy_status_port: 20292
    data_dir: /data/tiflash/data
    deploy_dir: /data/tiflash/deploy
# TiFlashノードのスケールアウト
tiup cluster scale-out tidb-prod topology-tiflash.yaml

# TiFlashノードステータスの確認
tiup cluster display tidb-prod | grep tiflash

1.2 テーブルにTiFlashレプリカを追加

-- テーブル全体にTiFlashレプリカを追加(デフォルト1レプリカ)
ALTER TABLE orders SET TIFLASH REPLICA 1;

-- テーブルに2つのTiFlashレプリカを追加(高可用性)
ALTER TABLE orders SET TIFLASH REPLICA 2;

-- パーティションテーブルにTiFlashレプリカを追加
ALTER TABLE orders_partition SET TIFLASH REPLICA 1;

-- レプリカ同期進捗の確認
SELECT * FROM information_schema.tiflash_replica
WHERE table_name = 'orders';

同期進捗出力例:

+----------+------------+----------+---------------+------------------+-----------+
| TABLE_ID | TABLE_NAME | REPLICA  | LOCATION_LABELS| AVAILABLE        | PROGRESS  |
+----------+------------+----------+---------------+------------------+-----------+
|       85 | orders     |        1 |               | True             | 1.0       |
+----------+------------+----------+---------------+------------------+-----------+

1.3 列単位でTiFlashレプリカを追加(ストレージ節約)

-- 分析に必要な列のみTiFlashレプリカを作成
ALTER TABLE orders SET TIFLASH REPLICA 1
  COLUMNS (order_id, user_id, product_id, amount, status, created_at);

-- 列レベルレプリカの確認
SHOW CREATE TABLE orders;

パターン2:MPP分散クエリアクセラレーション

TiDBのMPPエンジンは分析クエリを複数のTiFlashノードにプッシュダウンして並列実行し、ClickHouseに近いクエリパフォーマンスを実現。

2.1 MPPモードの有効化

-- 現在のMPPモードの確認
SHOW VARIABLES LIKE 'tidb_allow_mpp';

-- MPPの有効化(デフォルトで有効)
SET SESSION tidb_allow_mpp = 1;

-- MPPの強制使用(テスト/検証用)
SET SESSION tidb_enforce_mpp = 1;

-- MPPクエリのExchange圧縮設定
SET SESSION tidb_exchange_compression = 'ON';

2.2 MPPクエリ実践:リアルタイム売上分析

-- シナリオ:本日のカテゴリ別売上Top10をリアルタイム集計
-- MPPは自動的に計算をTiFlashノードにプッシュダウンして並列実行

SELECT
    c.category_name,
    SUM(oi.quantity * oi.unit_price) AS total_sales,
    COUNT(DISTINCT o.user_id) AS unique_buyers,
    AVG(oi.quantity * oi.unit_price) AS avg_order_value
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
JOIN categories c ON p.category_id = c.category_id
WHERE o.created_at >= CURDATE()
  AND o.status IN ('paid', 'shipped', 'completed')
GROUP BY c.category_name
ORDER BY total_sales DESC
LIMIT 10;

2.3 MPP実行計画の確認

-- 実行計画を確認、MPPオペレータを確認
EXPLAIN ANALYZE
SELECT
    c.category_name,
    SUM(oi.quantity * oi.unit_price) AS total_sales
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
JOIN categories c ON p.category_id = c.category_id
WHERE o.created_at >= CURDATE()
GROUP BY c.category_name;

主要な実行計画の特徴:

+------------------------------------------+----------+---------+--------------+
| id                                       | task     | rows    | operator info|
+------------------------------------------+----------+---------+--------------+
| TableReader_45                           | root     | 10      | ...          |
| └─ExchangeSender_44                      | mpp[tif] | 10      | ExchangeType |
|   └─Projection_42                        | mpp[tif] | 10      | ...          |
|     └─HashAgg_43                         | mpp[tif] | 10      | group by:... |
|       └─ExchangeReceiver_38              | mpp[tif] | 100     | ...          |
|         └─ExchangeSender_37              | mpp[tif] | 100     | ExchangeType |
|           └─HashJoin_36                  | mpp[tif] | 100     | inner join   |
|             ├─Selection_25(Build)        | mpp[tif] | 500     | ...          |
|             │ └─TableFullScan_24         | mpp[tif] | 10000   | tikv:tiflash |
|             └─Selection_30(Probe)        | mpp[tif] | 800     | ...          |
|               └─TableFullScan_29         | mpp[tif] | 20000   | tikv:tiflash |
+------------------------------------------+----------+---------+--------------+

mpp[tif]ExchangeSender/Receiver が見えればMPPが有効。

2.4 MPPパフォーマンス比較

-- MPPを無効化、従来のTiKVスキャンを使用
SET SESSION tidb_allow_mpp = 0;

EXPLAIN ANALYZE
SELECT c.category_name, SUM(oi.quantity * oi.unit_price) AS total_sales
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
JOIN categories c ON p.category_id = c.category_id
WHERE o.created_at >= CURDATE()
GROUP BY c.category_name;

-- MPPを再有効化
SET SESSION tidb_allow_mpp = 1;
クエリモード データ量 実行時間 スキャン行数
TiKVスキャン 1億行 45.2s 100,000,000
TiFlash非MPP 1億行 12.8s 100,000,000
TiFlash MPP 1億行 3.2s 100,000,000

パターン3:TiCDCリアルタイムETL代替

TiCDC(Change Data Capture)は従来のETLパイプラインを代替し、TiDBのデータ変更をリアルタイムに下流システムへ同期。

3.1 TiCDCのデプロイ

# tiup topology.yaml スニペット
cdc_servers:
  - host: 10.0.1.31
    port: 8300
    deploy_dir: /data/cdc/deploy
    data_dir: /data/cdc/data
    config:
      per-table-memory-quota: 10485760
      sink-memory-quota: 536870912
  - host: 10.0.1.32
    port: 8300
    deploy_dir: /data/cdc/deploy
    data_dir: /data/cdc/data
# TiCDCのスケールアウト
tiup cluster scale-out tidb-prod topology-cdc.yaml

# TiCDCステータスの確認
tiup cluster display tidb-prod | grep cdc

3.2 同期タスクの作成:MySQL → Kafka → Flinkパイプラインの代替

# TiCDC同期タスクの作成:TiDB → Kafka(Canal + Kafkaの代替)
cdc cli changefeed create \
  --server=http://10.0.1.31:8300 \
  --sink-uri="kafka://kafka-cluster:9092/tidb-orders?partition-num=6&max-message-bytes=10485760&replication-factor=3" \
  --changefeed-id="orders-to-kafka" \
  --config=cdc-orders.yaml
# cdc-orders.yaml
filter:
  rules:
    - 'ecommerce.orders'
    - 'ecommerce.order_items'
    - 'ecommerce.payments'
  ignore_txn_start_ts: []

mounter:
  worker-num: 16

sink:
  protocol: "canal-json"
  dispatchers:
    - matcher: ['ecommerce.*']
      partition: "index-value"

selector:
  rules:
    - 'ecommerce.orders'
    - 'ecommerce.order_items'
    - 'ecommerce.payments'

3.3 ClickHouseへの直接同期(引き続き必要な場合)

# TiCDC → ClickHouseダイレクト接続
cdc cli changefeed create \
  --server=http://10.0.1.31:8300 \
  --sink-uri="clickhouse://clickhouse-server:8123?database=analytics&username=default&password=***" \
  --changefeed-id="orders-to-clickhouse" \
  --config=cdc-ch.yaml

3.4 TiCDCからS3への同期(データレイクソリューション)

# TiCDC → S3データレイク
cdc cli changefeed create \
  --server=http://10.0.1.31:8300 \
  --sink-uri="s3://data-lake/tidb-cdc/?endpoint=https://s3.amazonaws.com&access-key=***&secret-access-key=***" \
  --changefeed-id="orders-to-s3" \
  --config=cdc-s3.yaml
# cdc-s3.yaml
sink:
  protocol: "csv"
  column-selectors:
    - matcher: ['ecommerce.orders']
      columns: ['order_id', 'user_id', 'amount', 'status', 'created_at']

file:
  size: 67108864
  interval: 5m

filter:
  rules:
    - 'ecommerce.orders'
    - 'ecommerce.order_items'

3.5 TiCDC同期遅延の監視

-- 同期タスクステータスの確認
cdc cli changefeed list \
  --server=http://10.0.1.31:8300;

-- 同期遅延の確認
cdc cli changefeed query \
  --changefeed-id=orders-to-kafka \
  --server=http://10.0.1.31:8300;

主要メトリクス:

{
  "state": "normal",
  "tso": 446685327530688513,
  "checkpoint": "2026-06-15 10:30:00.123",
  "lag": "1.2s"
}

パターン4:ダッシュボードクエリ最適化

リアルタイムダッシュボードはHTAPの最も直接的な応用シナリオだが、クエリパフォーマンスがユーザー体験に直結。

4.1 ダッシュボードクエリパターンの識別

-- 典型的なダッシュボードクエリ1:リアルタイムGMV
SELECT
    DATE_FORMAT(created_at, '%Y-%m-%d %H:00') AS hour_slot,
    SUM(amount) AS gmv,
    COUNT(*) AS order_count
FROM orders
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
  AND status != 'cancelled'
GROUP BY hour_slot
ORDER BY hour_slot;

-- 典型的なダッシュボードクエリ2:リアルタイムユーザーアクティビティ
SELECT
    DATE_FORMAT(login_time, '%Y-%m-%d %H:00') AS hour_slot,
    COUNT(DISTINCT user_id) AS dau,
    COUNT(*) AS total_actions
FROM user_actions
WHERE login_time >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY hour_slot
ORDER BY hour_slot;

-- 典型的なダッシュボードクエリ3:リアルタイムコンバージョンファネル
SELECT
    COUNT(DISTINCT CASE WHEN event = 'view' THEN user_id END) AS views,
    COUNT(DISTINCT CASE WHEN event = 'cart' THEN user_id END) AS carts,
    COUNT(DISTINCT CASE WHEN event = 'pay' THEN user_id END) AS pays,
    ROUND(COUNT(DISTINCT CASE WHEN event = 'pay' THEN user_id END) * 100.0
      / NULLIF(COUNT(DISTINCT CASE WHEN event = 'view' THEN user_id END), 0), 2) AS conversion_rate
FROM user_events
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 1 HOUR);

4.2 クエリのTiFlash強制使用

-- 方法1:HintでTiFlashを強制
SELECT /*+ read_from_storage(tiflash[orders]) */
    DATE_FORMAT(created_at, '%Y-%m-%d %H:00') AS hour_slot,
    SUM(amount) AS gmv
FROM orders
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY hour_slot;

-- 方法2:セッション変数の設定
SET SESSION tidb_isolation_read_engines = 'tiflash';
SELECT
    DATE_FORMAT(created_at, '%Y-%m-%d %H:00') AS hour_slot,
    SUM(amount) AS gmv
FROM orders
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY hour_slot;
SET SESSION tidb_isolation_read_engines = 'tikv,tiflash';

-- 方法3:Resource GroupでOLAPトラフィックを分離
CREATE RESOURCE GROUP IF NOT EXISTS olap_group
  RU_PER_SEC = 5000
  PRIORITY = LOW;

ALTER USER dashboard_user RESOURCE GROUP olap_group;

4.3 ダッシュボードクエリキャッシュの最適化

-- Bindingで実行計画を固定
CREATE SESSION BINDING FOR
SELECT SUM(amount) FROM orders WHERE created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
USING
SELECT /*+ read_from_storage(tiflash[orders]) */ SUM(amount)
FROM orders WHERE created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR);

-- Bindingの確認
SHOW SESSION BINDINGS;

4.4 ダッシュボードリフレッシュ戦略

-- ダッシュボードクエリはREAD ONLYモードの使用を推奨、OLTPとのリソース競合を回避
SET SESSION tidb_isolation_read_engines = 'tiflash';

-- ダッシュボードクエリのリソース消費を制限
SET SESSION max_execution_time = 30000;

-- Prepared Statementでパースオーバーヘッドを削減
PREPARE dashboard_gmv FROM
SELECT
    DATE_FORMAT(created_at, '%Y-%m-%d %H:00') AS hour_slot,
    SUM(amount) AS gmv
FROM orders
WHERE created_at >= ?
  AND status != 'cancelled'
GROUP BY hour_slot
ORDER BY hour_slot;

EXECUTE dashboard_gmv USING DATE_SUB(NOW(), INTERVAL 24 HOUR);

パターン5:マテリアライズドビューによるデータマート構築

TiDB 8.xはマテリアライズドビュー(Materialized View)をサポート、集計データを事前計算し、ビジネス向けのデータマートを構築可能。

5.1 マテリアライズドビューの作成

-- 日次売上サマリーマテリアライズドビューの作成
CREATE MATERIALIZED VIEW mv_daily_sales
REFRESH EVERY 1 HOUR
AS
SELECT
    DATE(created_at) AS sale_date,
    c.category_name,
    p.product_name,
    SUM(oi.quantity) AS total_quantity,
    SUM(oi.quantity * oi.unit_price) AS total_revenue,
    COUNT(DISTINCT o.user_id) AS unique_buyers,
    AVG(oi.quantity * oi.unit_price) AS avg_price
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
JOIN categories c ON p.category_id = c.category_id
WHERE o.status IN ('paid', 'shipped', 'completed')
GROUP BY DATE(created_at), c.category_name, p.product_name;

5.2 ユーザー行動マテリアライズドビューの作成

-- ユーザー行動ファネルマテリアライズドビュー
CREATE MATERIALIZED VIEW mv_user_funnel
REFRESH EVERY 5 MINUTE
AS
SELECT
    DATE(created_at) AS event_date,
    COUNT(DISTINCT CASE WHEN event_type = 'page_view' THEN user_id END) AS page_views,
    COUNT(DISTINCT CASE WHEN event_type = 'add_to_cart' THEN user_id END) AS add_to_carts,
    COUNT(DISTINCT CASE WHEN event_type = 'checkout' THEN user_id END) AS checkouts,
    COUNT(DISTINCT CASE WHEN event_type = 'payment' THEN user_id END) AS payments,
    ROUND(
        COUNT(DISTINCT CASE WHEN event_type = 'payment' THEN user_id END) * 100.0
        / NULLIF(COUNT(DISTINCT CASE WHEN event_type = 'page_view' THEN user_id END), 0),
        2
    ) AS view_to_pay_rate
FROM user_events
GROUP BY DATE(created_at);

5.3 マテリアライズドビューの管理

-- マテリアライズドビューのステータス確認
SHOW MATERIALIZED VIEWS;

-- 手動リフレッシュ
ALTER MATERIALIZED VIEW mv_daily_sales REFRESH;

-- 自動リフレッシュの一時停止
ALTER MATERIALIZED VIEW mv_daily_sales DISABLE;

-- 自動リフレッシュの再開
ALTER MATERIALIZED VIEW mv_daily_sales ENABLE;

-- マテリアライズドビューの削除
DROP MATERIALIZED VIEW IF EXISTS mv_daily_sales;

5.4 マテリアライズドビューベースのダッシュボードクエリ

-- マテリアライズドビューのクエリ(ミリ秒レベルのレスポンス)
SELECT
    sale_date,
    category_name,
    total_revenue,
    unique_buyers
FROM mv_daily_sales
WHERE sale_date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
ORDER BY total_revenue DESC
LIMIT 20;

パターン6:プロダクションHTAPデプロイとモニタリング

プロダクション環境のHTAPデプロイでは、リソース分離、モニタリング/アラート、障害復旧を考慮する必要がある。

6.1 リソース制御設定

-- OLTPリソースグループの作成(高優先度)
CREATE RESOURCE GROUP IF NOT EXISTS oltp_group
  RU_PER_SEC = 20000
  PRIORITY = HIGH;

-- OLAPリソースグループの作成(低優先度、リソース制限あり)
CREATE RESOURCE GROUP IF NOT EXISTS olap_group
  RU_PER_SEC = 8000
  PRIORITY = LOW;

-- ユーザーをリソースグループにバインド
ALTER USER app_user RESOURCE GROUP oltp_group;
ALTER USER dashboard_user RESOURCE GROUP olap_group;
ALTER USER etl_user RESOURCE GROUP olap_group;

-- リソースグループ設定の確認
SELECT * FROM information_schema.resource_groups;

6.2 TiFlash主要モニタリングメトリクス

# Grafana Dashboard 主要メトリクス
# TiFlash Summary Dashboard

tiflash_system_profile:
  - metric: tiflash_storage_write_duration_seconds
    alert_threshold: "> 5s"
    description: "TiFlash書き込みレイテンシ"
  
  - metric: tiflash_mpp_task_duration_seconds
    alert_threshold: "> 60s"
    description: "MPPタスク実行時間"
  
  - metric: tiflash_storage_segment_count
    alert_threshold: "> 10000"
    description: "セグメント数(多すぎる場合はcompactionが必要)"
  
  - metric: tiflash_cpu_usage
    alert_threshold: "> 80%"
    description: "TiFlash CPU使用率"
  
  - metric: tiflash_storage_disk_usage_ratio
    alert_threshold: "> 0.8"
    description: "TiFlashディスク使用率"

6.3 Prometheusアラートルール

# tidb-htap-alerts.yaml
groups:
  - name: tidb_htap
    rules:
      - alert: TiFlashReplicaSyncLag
        expr: |
          tiflash_replica_available == 0
          or (tiflash_replica_progress < 0.95 and tiflash_replica_progress > 0)
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "TiFlashレプリカ同期遅延"
          description: "テーブル {{ $labels.table_name }} のTiFlashレプリカ同期進捗は {{ $value }} のみ"

      - alert: TiFlashHighWriteDuration
        expr: |
          histogram_quantile(0.95,
            rate(tiflash_storage_write_duration_seconds_bucket[5m])
          ) > 5
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "TiFlash書き込みレイテンシが高すぎる"
          description: "P95書き込みレイテンシ {{ $value }}s"

      - alert: MPPQueryTimeout
        expr: |
          rate(tiflash_mpp_task_error_count{reason="timeout"}[5m]) > 0.1
        for: 3m
        labels:
          severity: critical
        annotations:
          summary: "MPPクエリタイムアウト率が高すぎる"
          description: "MPPクエリタイムアウト率 {{ $value }}/s"

      - alert: TiFlashDiskSpaceLow
        expr: |
          tiflash_storage_disk_usage_ratio > 0.85
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "TiFlashディスク容量不足"
          description: "ディスク使用率 {{ $value }}"

6.4 日常運用スクリプト

#!/bin/bash
# tidb-htap-healthcheck.sh
# TiDB HTAPヘルスチェックスクリプト

CLUSTER_NAME="tidb-prod"
LOG_FILE="/var/log/tidb-htap-healthcheck.log"

echo "=== TiDB HTAP Health Check $(date) ===" >> $LOG_FILE

# TiFlashノードステータスの確認
echo "--- TiFlash Node Status ---" >> $LOG_FILE
tiup cluster display $CLUSTER_NAME 2>/dev/null | grep tiflash >> $LOG_FILE

# TiFlashレプリカ同期ステータスの確認
echo "--- TiFlash Replica Sync Status ---" >> $LOG_FILE
mysql -h10.0.1.10 -P4000 -uroot -e "
SELECT table_schema, table_name, replica_count, available, progress
FROM information_schema.tiflash_replica
WHERE available = 0 OR progress < 1.0;
" >> $LOG_FILE 2>&1

# TiCDC同期遅延の確認
echo "--- TiCDC Sync Lag ---" >> $LOG_FILE
cdc cli changefeed list --server=http://10.0.1.31:8300 >> $LOG_FILE 2>&1

# MPPクエリパフォーマンスの確認
echo "--- MPP Query Performance ---" >> $LOG_FILE
mysql -h10.0.1.10 -P4000 -uroot -e "
SELECT DIGEST_TEXT, AVG_LATENCY, EXEC_COUNT
FROM information_schema.statements_summary
WHERE DIGEST_TEXT LIKE '%GROUP BY%'
  AND AVG_LATENCY > 1000000000
ORDER BY AVG_LATENCY DESC
LIMIT 10;
" >> $LOG_FILE 2>&1

echo "=== Health Check Complete ===" >> $LOG_FILE

5つのよくある落とし穴ガイド

❌ 落とし穴1:TiFlashレプリカ未同期でクエリ実行

-- ❌ 誤り:TiFlashレプリカ追加直後にクエリ、データが不完全の可能性
ALTER TABLE orders SET TIFLASH REPLICA 1;
-- 即座にクエリ、不完全なデータを読み取る可能性
SELECT COUNT(*) FROM orders;

-- ✅ 正しい:レプリカ同期完了を待つ
ALTER TABLE orders SET TIFLASH REPLICA 1;

-- 同期進捗の確認
SELECT table_name, progress, available
FROM information_schema.tiflash_replica
WHERE table_name = 'orders';

-- available = 1 になってからクエリ
SELECT COUNT(*) FROM orders;

❌ 落とし穴2:小さなテーブルにもTiFlashレプリカを追加

-- ❌ 誤り:小さなテーブルにTiFlashレプリカを追加すると逆に遅くなる(ネットワークオーバーヘッド > スキャンオーバーヘッド)
ALTER TABLE config_dict SET TIFLASH REPLICA 1;

-- ✅ 正しい:小さなテーブルはTiKVに維持、大きなテーブルのみTiFlashレプリカを追加
-- 目安:データ量 > 100万行の場合のみTiFlashレプリカを検討
-- 小さなテーブルはHintでTiKVを強制
SELECT /*+ read_from_storage(tikv[config_dict]) */
    * FROM config_dict WHERE type = 'payment';

❌ 落とし穴3:OLAPクエリがOLTPパフォーマンスに影響

-- ❌ 誤り:OLAPとOLTPが同じユーザーを使用、リソース分離なし
SELECT user, resource_group FROM mysql.user WHERE user = 'app_user';
-- app_user | default

-- ✅ 正しい:Resource Groupで分離
CREATE RESOURCE GROUP IF NOT EXISTS oltp_group
  RU_PER_SEC = 20000 PRIORITY = HIGH;
CREATE RESOURCE GROUP IF NOT EXISTS olap_group
  RU_PER_SEC = 8000 PRIORITY = LOW;

ALTER USER app_user RESOURCE GROUP oltp_group;
ALTER USER dashboard_user RESOURCE GROUP olap_group;

-- OLAPクエリにタイムアウトを設定
SET SESSION max_execution_time = 60000;

❌ 落とし穴4:TiFlashノードのディスク容量不足

# ❌ 誤り:TiFlashデータディレクトリがシステムディスクと共用
tiflash_servers:
  - host: 10.0.1.21
    data_dir: /var/lib/tiflash/data  # システムディスクは容量が限られている

# ✅ 正しい:TiFlashは専用データディスクを使用、30%の空き容量を確保
tiflash_servers:
  - host: 10.0.1.21
    data_dir: /data/tiflash/data    # 専用データディスク
    config:
      storage:
        main:
          capacity: "2TB"           # 容量制限を明示
        latest:
          capacity: "200GB"

❌ 落とし穴5:TiCDC同期遅延アラートの無視

# ❌ 誤り:TiCDC遅延を監視せず、データ同期が停止しても気づかない
# アラート設定が一切ない

# ✅ 正しい:TiCDC遅延アラートを設定
# Prometheusアラートルール
- alert: TiCDCReplicationLag
  expr: |
    tidb_cdc_checkpoint_ts_lag_seconds > 300
  for: 5m
  labels:
    severity: critical
  annotations:
    summary: "TiCDC同期遅延が5分を超過"
    description: "changefeed {{ $labels.changefeed }} 遅延 {{ $value }}s"

エラートラブルシューティングクイックリファレンス

エラー現象 考えられる原因 診断コマンド/方法 解決策
TiFlashレプリカ同期がスタック TiFlashノードのディスク満杯またはダウン SELECT * FROM information_schema.tiflash_replica WHERE progress < 1.0; ディスク拡張またはTiFlashノードの再起動
MPPクエリが Too many MPP tasks を報告 同時MPPクエリが多すぎる SHOW CONFIG WHERE name LIKE '%mpp%'; tidb_mpp_task_limit の調整または同時実行数の削減
クエリがTiFlashを使用していない オプティマイザがTiKVをより適切と判断 EXPLAIN SELECT ...; でオペレータを確認 /*+ read_from_storage(tiflash[t]) */ Hintを使用
TiCDC同期遅延が増大 下流の書き込みが遅い、またはネットワークジッター cdc cli changefeed query --changefeed-id=xxx 下流のスケールアップまたはTiCDCワーカー数の増加
TiFlash OOM クエリデータ量が大きすぎる grep OOM /data/tiflash/log/tiflash.log max_memory_usage の増加またはクエリ範囲の絞り込み
ダッシュボードクエリのタイムアウト クエリリソース制限なし SHOW PROCESSLIST; max_execution_time とResource Groupの設定
マテリアライズドビューのリフレッシュ失敗 ソーステーブルのデータ量が大きすぎる、またはロック競合 SHOW MATERIALIZED VIEWS; リフレッシュ頻度の調整またはソーステーブルインデックスの最適化
TiFlash書き込みレイテンシが高い Raft Learner同期圧力が高い Grafana TiFlash Dashboard TiFlashノードのスケールアップまたは raft-store.sync-log の調整
MPP Joinのデータスキュー Joinキーの分布が不均一 EXPLAIN ANALYZE で各ノードのデータ量を確認 /*+ shuffle_join() */ の使用またはバケット数の増加
TiFlashディスクIOが高い Compactionまたは大量スキャン iostat -x 1 でIOを確認 bg_task_io_limit の調整またはディスク拡張

高度な最適化テクニック

3.1 TiFlashストレージエンジンのチューニング

-- TiFlashセグメント分割閾値の調整(小さなセグメントの削減)
-- TiFlash設定で変更
# tiflash-config.yaml
storage:
  main:
    segment_delta_rows: 8192
    segment_delta_size: 536870912
    segment_stable_rows: 10485760
  latest:
    segment_delta_rows: 4096
    segment_delta_size: 134217728

raft:
  apply_batch: 1024
  sync_log: false

engine:
  dt:
    enable_read_thread: true
    read_thread_count: 8
    enable_leaf_dt_segment_optimize: true

3.2 MPPクエリの高度な最適化

-- 1. Runtime FilterでJoinデータ転送を削減
-- TiDB 8.xではデフォルトで有効、ステータスを確認
SET SESSION tidb_runtime_filter_mode = "LOCAL";

-- 2. MPP Exchangeデータ圧縮の調整
SET SESSION tidb_exchange_compression = 'ON';
SET SESSION tidb_exchange_compression_level = 3;

-- 3. 大きなテーブルのJoin最適化:Hash Join Hintを使用
SELECT /*+ hash_join_build(o) */
    c.category_name,
    SUM(oi.quantity * oi.unit_price) AS total_sales
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN categories c ON oi.product_id = c.category_id
GROUP BY c.category_name;

-- 4. Index Lookup JoinでHash Joinを代替(小さなテーブルが大きなテーブルを駆動する場合に適している)
SELECT /*+ inl_join(p) */
    o.order_id, p.product_name
FROM orders o
JOIN products p ON o.product_id = p.product_id
WHERE o.created_at >= CURDATE();

3.3 マルチテナントHTAPリソース分離

-- 異なるビジネスライン向けに独立したリソースグループを作成
CREATE RESOURCE GROUP IF NOT EXISTS rg_ecommerce
  RU_PER_SEC = 15000 PRIORITY = HIGH
  QUERY_LIMIT = (EXECUTION_TIME = 30s);

CREATE RESOURCE GROUP IF NOT EXISTS rg_analytics
  RU_PER_SEC = 10000 PRIORITY = LOW
  QUERY_LIMIT = (EXECUTION_TIME = 120s);

CREATE RESOURCE GROUP IF NOT EXISTS rg_data_science
  RU_PER_SEC = 5000 PRIORITY = LOW
  QUERY_LIMIT = (EXECUTION_TIME = 600s);

-- ユーザーをリソースグループにバインド
ALTER USER ecommerce_app RESOURCE GROUP rg_ecommerce;
ALTER USER analytics_user RESOURCE GROUP rg_analytics;
ALTER USER ds_user RESOURCE GROUP rg_data_science;

-- リソースグループの使用状況をモニタリング
SELECT * FROM information_schema.resource_group_usage;

HTAPソリューション比較

次元 TiDB HTAP ClickHouse + MySQL Snowflake Apache Doris SingleStore
アーキテクチャ 統合HTAP デュアルシステムの結合 クラウドネイティブOLAP 統合HTAP 統合HTAP
OLTP能力 強(MySQL互換) MySQLネイティブ なし 弱い 中程度
OLAPパフォーマンス 強(MPP) 非常に強い 非常に強い 強い 強い
データ同期 Raft Learner(自動) 自前ETLが必要 インポートが必要 自動 自動
リアルタイム性 秒レベル 分レベル 分レベル 秒レベル 秒レベル
MySQL互換性 95%+ ネイティブ 非互換 中程度 中程度
水平スケーリング 透過的 各自でスケーリング 自動スケーリング 透過的 透過的
運用複雑度 中程度 高い 低い 中程度 中程度
コスト 中程度 高い(デュアルシステム) 高い(従量課金) 中程度 高い
オープンソース 完全オープンソース 一部オープンソース クローズドソース 完全オープンソース 一部オープンソース
適用シナリオ 汎用HTAP 既存MySQL + 強力なOLAPが必要 純粋な分析 リアルタイムデータウェアハウス リアルタイム分析

まとめ

TiDB HTAPは「OLTPもOLAPもできる」というマーケティングスローガンではなく、Raft Learnerによる行ストレージから列ストレージへのリアルタイム同期、MPPエンジンによる分散並列計算、Resource ControlによるOLTP/OLAPリソース分離を実現するエンジニアリングソリューションです。2026年の今、まだMySQL + ClickHouseのデュアルシステムアーキテクチャを維持しているなら、TiDB HTAPを真剣に評価する時です——1つのシステム、1つの運用、ゼロデータ遅延、それこそがリアルタイム分析のあるべき姿です。


おすすめツール

ブラウザローカルツールを無料で試す →

#TiDB#HTAP#实时分析#TiFlash#分布式数据库#2026#列存