DockerでTiDBをデプロイする:分散型NewSQLデータベースでHTAPをスケールさせる

Database tutorial - IT technology blog
Database tutorial - IT technology blog

スケーリングの壁とETLのコスト

私たちの多くは、従来の型リレーショナルデータベースから開発のキャリアをスタートさせます。MySQL、PostgreSQL、MongoDBなど様々なプロジェクトで扱ってきましたが、それぞれに強みがあります。信頼性と使いやすさの面で、私は通常MySQLを第一の選択肢にしています。

しかし、プロジェクトが成長し、単一のMySQLインスタンスでは書き込み負荷を処理しきれなくなる「壁」にぶつかることがよくあります。従来、この解決策はシャーディングでした。これはデータを複数のサーバーに分割する複雑なプロセスです。これはメンテナンスの悪夢であり、シャードをまたぐトランザクションが壊れ、クエリの実行も非常に厄介になります。

次に分析の側面です。ビジネスチームがリアルタイムのレポートを求める際、本番環境のMySQLインスタンスで重い集計クエリを実行すると、パフォーマンスが崩壊する原因になります。これを解決するために、通常はETL(抽出・変換・格納)パイプラインを構築し、ClickHouseやSnowflakeのような別のデータウェアハウスにデータを移動します。しかし、これによりデータの遅延が発生し、故障の原因となる可動パーツが増えてしまいます。

TiDBはこの動向を根本から変えます。TiDBは水平スケーラブルでACIDトランザクションをサポートし、MySQLプロトコルに対応したNewSQLデータベースです。しかし、その真の魔法はHTAP(Hybrid Transactional/Analytical Processing)にあります。トランザクション(OLTP)と分析(OLAP)のワークロードを、互いに干渉することなく同じクラスター上で実行できるのです。複雑なETLパイプラインのオーバーヘッドなしにリアルタイムのインサイトを必要とするチームにとって、これは画期的なソリューションになると私は確信しています。

コアコンセプト:TiDBがいかにして「impossible」を可能にするか

Dockerでのセットアップに入る前に、そのアーキテクチャを理解しておくと役立ちます。TiDBは単一のバイナリではなく、連携して動作する専門的なコンポーネントのクラスターです。

  • TiDB Server: ステートレスなSQLレイヤー。クライアントの接続を処理し、SQLを解析し、クエリ実行を最適化します。このレイヤーを拡張することで、より多くの同時接続を処理できます。
  • PD (Placement Driver): クラスターの「脳」です。メタデータを保存し、データの分散を管理し、トランザクションのタイムスタンプ割り当てを処理します。
  • TiKV: 行ベースのストレージエンジン。トランザクションデータが保存される場所です。Raftコンセンサスアルゴリズムを使用して、高可用性とデータの一貫性を確保します。
  • TiFlash: 列ベースのストレージエンジン。これがTiDBをHTAPデータベースたらしめる要素です。TiKVからデータを列形式で複製し、スキャンや集計に最適化されたニアリアルタイムの分析機能を提供します。

TiDBはMySQL 5.7プロトコルと互換性があるため、既存েরアプリケーションは通常、接続文字列を変更するだけでTiDBに移行できます。ORMのロジックや複雑なクエリを書き直す必要はありません。

DockerでのTiDBセットアップ

開発やテストにおいて、Docker ComposeはTiDBクラスターを起動する最も効率的な方法です。TiDBには本番デプロイ用のtiupというツールがありますが、Dockerを使えばHTAP機能を探索するためのクリーンで分離された環境をすぐに構築できます。

1. Docker Composeの設定

プロジェクト用のディレクトリを作成し、以下の内容をdocker-compose.ymlとして保存します。この設定には、PD、TiKV、TiDB、TiFlashのコアコンポーネントが含まれています。

version: '3.8'

services:
  pd:
    image: pingcap/pd:latest
    ports:
      - "2379:2379"
    command:
      - --name=pd
      - --data-dir=/data/pd
      - --client-urls=http://0.0.0.0:2379
      - --advertise-client-urls=http://pd:2379
      - --peer-urls=http://0.0.0.0:2380
      - --advertise-peer-urls=http://pd:2380
      - --initial-cluster=pd=http://pd:2380
      - --log-file=/logs/pd.log

  tikv:
    image: pingcap/tikv:latest
    depends_on:
      - pd
    command:
      - --addr=0.0.0.0:20160
      - --advertise-addr=tikv:20160
      - --data-dir=/data/tikv
      - --pd-endpoints=http://pd:2379
      - --log-file=/logs/tikv.log

  tidb:
    image: pingcap/tidb:latest
    ports:
      - "4000:4000"
      - "10080:10080"
    depends_on:
      - pd
      - tikv
    command:
      - --store=tikv
      - --path=pd:2379
      - --log-file=/logs/tidb.log

  tiflash:
    image: pingcap/tiflash:latest
    depends_on:
      - pd
      - tikv
    command:
      - server
      - --config-file=/etc/tiflash/tiflash-learner.toml
    # 注:TiFlashを安定して動作させるには特定の構成が必要です。
    # このデモでは、デフォルトのイメージ設定で十分です。

2. クラスターの起動

以下のコマンドを実行して、バックグラウンドでサービスを開始します。

docker-compose up -d

すべてのコンポーネントが初期化され、Placement Driver (PD) に登録されるまで1〜2分かかります。docker-compose psを使用してコンテナの状態を確認できます。

HTAP機能のテスト

クラスターが起動したら、任意のMySQLクライアントを使用して接続できます。ここでは標準的なコマンドラインクライアントを使用します。TiDBのデフォルトポートは4000、デフォルトユーザーはroot(パスワードなし)です。

mysql -h 127.0.0.1 -P 4000 -u root

TiFlashレプリカを使用したテーブルの作成

HTAP機能を活用するには、どのテーブルを列指向ストレージ(TiFlash)に複製するかをTiDBに指示する必要があります。サンプルテーブルを作成し、TiFlashレプリケーションを有効にしてみましょう。

CREATE DATABASE analytics_demo;
USE analytics_demo;

CREATE TABLE orders (
    id BIGINT PRIMARY KEY,
    customer_id INT,
    amount DECIMAL(10, 2),
    order_date DATETIME
);

-- このテーブルにTiFlashレプリカを1つ追加する
ALTER TABLE orders SET TIFLASH REPLICA 1;

以下のクエリでレプリケーションの状態を確認できます。データが同期されると、AVAILABLE列が1に変わります。

SELECT * FROM information_schema.tiflash_replica WHERE table_name = 'orders';

適切なエンジンでのクエリ実行

TiDBのオプティマイザは、クエリに応じてTiKV(行ベース)とTiFlash(列ベース)のどちらを使用するかをインテリジェントに判断します。ポイントセレクトや小さなトランザクションはTiKVへ、大規模な集計はTiFlashへと送られます。

大規模なデータセットでのパフォーマンスの違いを確認するために、強制的にTiFlashを使用させることもできます。

-- このセッションでTiFlashの使用を強制する
SET @@session.tidb_isolation_read_engines = "tiflash";

SELECT SUM(amount), DATE(order_date) 
FROM orders 
GROUP BY DATE(order_date);

現場からのベストプラクティス

様々な環境でTiDBを試行錯誤した結果、デプロイとスケーリングの際に役立ついくつかのヒントをまとめました。

リソースの割り当て

TiDBはリソースを多く消費します。本番環境では、可能であればTiKVとTiFlashを同じ物理ディスクに配置しないようにしてください。TiKVはトランザクションのために低レイテンシのIOを必要とし、TiFlashはスキャンのために高いスループットを必要とするからです。Dockerでは、十分なメモリ(デモ用で最低4GB、本番用ではそれ以上)を割り当ててください。そうしないと、コンテナが予期せず終了する可能性があります。

モニタリングは必須

TiDBエコシステムの素晴らしい点の1つは、PrometheusとGrafanaとの組み込み統合です。後で公式のtiupデプロイ方法を使用する場合、これらは自動的にセットアップされます。Dockerの場合は、PDのTSO(Timestamp Oracle)待機時間やTiKVストレージエンジンのメトリクスを可視化するために、ComposeファイルにGrafanaコンテナを追加することをお勧めします。これがボトルネックを真に理解する唯一の方法です。

バージョニングへの注意

TiDBのエコシステムは進化が速いです。TiDB、TiKV、PDのバージョンが完全に一致していることを常に確認してください。例えば、TiDB v6.5サーバーとTiKV v7.1ノードを混在させると、Raftコンセンサスレイヤーでデバッグが困難な微妙なバグが発生する可能性があります。

最後に

シングルノードのMySQL構成からTiDBのような分散型NewSQLデータベースへの移行は大きな飛躍に感じられますが、Dockerベースのアプローチにより学習曲線は非常に緩やかになります。これは現代のデータエンジニアリングにおける2つの大きな悩み、つまり「水平スケーリング」と「OLTP/OLAPの分離」を解決してくれます。

TiFlashを使用することで、単一のデータベース接続というシンプルさを保ちながら、データウェアハウスのメリットを享受できます。もしアプリケーションが現在のリレーショナルデータベースの限界に達しつつあるなら、DockerでTiDBを試してみることは、次の成長段階に適した選択肢かどうかを評価する素晴らしい方法となるでしょう。

Share: