👏

TiDBの自動シャーディングを体感。AUTO_RANDOM使ってみた

に公開

はじめに

きっかけは、TiDBユーザグループ ミートアップ #5に参加し、そこでTiDBのシャーディングが自動で行われる仕組みに興味を持ったことです。特に、AUTO_INCREMENTが引き起こす「ホットスポット」問題と、それを解決する機能について、実際に自分の手で試してみることにしました。

MySQLなどの従来DBでは、シャーディングは複雑な手作業でした。しかし、TiDBではシャーディングは完全に自動化されています。

この記事では、TiDBがどのようにシャーディングを自動で行うかを解説し、AUTO_INCREMENTが引き起こすホットスポット問題をAUTO_RANDOMで解決する一連のテスト手順と、グラフを使った詳細な分析結果までを網羅的に紹介します。

1. TiDBのシャーディング:自動分割単位「Region」

TiDBにおけるシャーディングの主役はRegionです。TiDBはテーブルのデータを約96MBごとの塊(Region)に自動で分割し、クラスタ内の複数サーバー(TiKVノード)に自動で分散配置します。この分割と分散はすべてデータベース内部で透過的に行われるため、開発者はシャーディングを意識する必要がありません。

しかし、AUTO_INCREMENTのように常にIDが増加する主キーを使うと、新しいデータはテーブルの末尾に集中します。その結果、特定の1つのRegionに書き込みが殺到し、そのRegionを持つTiKVサーバーの性能がボトルネックとなる書き込みホットスポットが発生します。

2. 解決策:AUTO_INCREMENTからAUTO_RANDOMへ

このホットスポット問題を解決するのがAUTO_RANDOMです。これはAUTO_INCREMENTの代替機能で、IDを内部的にランダム化して払い出します。これにより、連番で挿入しているように見えても、データはクラスタ内の様々なRegionに分散して書き込まれ、ホットスポットを根本的に解消します。

比較テストの実践

AUTO_INCREMENTAUTO_RANDOMの性能差を、実際の負荷テストで比較してみましょう。

ステップ1: 比較用のテーブルを作成する

まず、比較対象となる2つのテーブルを作成します。

./src/infra/db/tidb/data/test_db.sql
-- テスト用のデータベースを作成(存在しない場合のみ)
CREATE DATABASE IF NOT EXISTS hotspot_test;
USE hotspot_test;

-- ----------------------------------------------------------------
-- テーブル1: シャーディングなし(ホットスポットが発生する比較対象)
-- ----------------------------------------------------------------
CREATE TABLE users_no_shard (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255)
);

-- ----------------------------------------------------------------
-- テーブル2: シャーディングあり(ホットスポットを解消するテスト対象)
-- ----------------------------------------------------------------
CREATE TABLE users_sharded (
    id BIGINT PRIMARY KEY AUTO_RANDOM,
    name VARCHAR(255)
);

ステップ2: 高負荷をかけるための簡易スクリプト

sysbenchはTiDB固有のDDLに対応していないため、大量のINSERTを並列実行する簡単なシェルスクリプトを使います。以下の内容をinsert_test.shとして保存し、chmod +x insert_test.shで実行権限を付与してください。

./src/infra/db/tidb/insert_test.sh
#!/bin/bash
DB_HOST="127.0.0.1"  # ご自身のTiDBのIPアドレスに変更
TABLE_NAME=$1
CONCURRENCY=50
INSERTS_PER_THREAD=2000

echo "--- Starting high-concurrency inserts on table: $TABLE_NAME ---"
time (
  for i in $(seq 1 $CONCURRENCY); do
    (
      for j in $(seq 1 $INSERTS_PER_THREAD); do
        mysql -h"$DB_HOST" -P4000 -uroot -Dhotspot_test -e "INSERT INTO $TABLE_NAME (name) VALUES (UUID());"
      done
    ) &
  done
  wait
)
echo "--- Test finished for table: $TABLE_NAME ---"

ステップ3: テストの実行とTiDB Dashboardでの観察

  1. ブラウザで TiDB Dashboard (http://<TiDBのIP>:2379) を開き、Key VisualizerとMetricsのページを表示しておきます。
    2.テストA: 「シャーディングなし」テーブルで実行
./insert_test.sh users_no_shard

3.実行中にKey Visualizerを観察します。
テストB: 「シャーディングあり」テーブルで実行

./insert_test.sh users_sharded

同様に、実行中にKey VisualizerとMetricsを観察します。

テスト結果の分析

実行結果でダッシュボードの画面ショットは以下になります。
シャーディングなし
シャーディングあり

比較サマリー

比較項目 シャーディングなし (AUTO_INCREMENT) シャーディングあり (AUTO_RANDOM)
QPS (スループット) 低く、不安定(最大 約30k-40k QPS) 高く、安定(最大 約80k-100k QPS
Latency (応答時間) 高く、不安定なスパイクが多い 低く、非常に安定している
Key Visualizer 負荷が一本の線に集中(ホットスポット) 負荷が全体に分散

詳細な分析

  • シャーディングなし(ホットスポットあり)
    • QPS: 性能が頭打ちになり、グラフが不安定です。これは、書き込みが単一のTiKVノードに集中し、そのノードがボトルネックになっていることを示します。
    • Latency: 大きなスパイクが頻発しており、処理待ちの長い行列ができている状態です。
  • シャーディングあり(ホットスポット解消)
    • QPS: QPSが2倍以上に向上し、非常に高いレベルで安定しています。AUTO_RANDOMによって書き込みが複数のTiKVノードに分散され、クラスタ全体のパワーを並列で使えている証拠です。
    • Latency: 非常に低いレベルで安定しており、リクエストが常に高速に処理されていることを示しています。

まとめ

今回のテストから、TiDBの自動シャーディング機能を最大限に活用するには、適切なスキーマ設計が極めて重要であることが分かりました。

AUTO_INCREMENTは便利な機能ですが、高負荷な書き込みが想定されるテーブルではホットスポットを引き起こし、クラスタ全体の性能を低下させる可能性があります。そのような場合は、AUTO_RANDOMを主キーに採用することで、開発者はシャーディングを意識することなく、TiDBの性能を最大限に引き出すことができます。

コラボスタイル Developers

Discussion