TiDB CloudでPoCやってみた
こんにちは、zinです🦑
今回、約2ヶ月間かけてTiDB Cloudを使ったPoCを実施しました。本記事では、その検証内容と結果についてご紹介します。
TiDBとは
TiDBは、PingCAP様が開発するオープンソースの分散型NewSQLデータベースです。MySQL互換性を持ちながら、水平スケーリングやHTAPアーキテクチャなどの特徴を備えています。
PoC実施の背景
弊社サービスの Liny では Amazon Aurora MySQLを使用していますが、以下のような課題を抱えています。
- 巨大テーブルに対するDDLのオペレーションコストが大きい
- 歴戦のスロークエリたちが改善できないままになっている
- 大量のinsertが集中しパフォーマンスが低下する
- Auroraの
max_connections限界(16,000)が見えてきている - Auroraのバージョンアップにシステム停止が必要
継続的に対策・改善を行なっていますが、根本的な解決が難しいものもあります。
TiDBに移行することでこれらの課題を(Auroraより楽に)解決できるのか、試してみたいと思いました。
PoCのゴール
今回はPoC第一弾として、以下のようなゴールを設定しました。
TiDBで現状のLinyの困りごとがどれくらい解決できそうかを探る
第一弾では本番DBを移行するかどうかまでは気負わず、TiDBだと今ある課題がどの程度解消できるのかを検証してみる、ということにしました。
データは全てダミーデータを利用しています。
検証の条件
TiDB Cloud (Essential)
| TiDB Version | v7.5.6 |
| Cloud Provider | AWS |
| Region | Tokyo (ap-northeast-1) |
| High Availability | Regional |
| RCU | 20,000 ~ 100,000 |
| Row-based Storage | 約750GB |
| Columnar Storage | 約300GB |
Aurora MySQL
| Engine version | 8.0.mysql_aurora.3.08.1 |
| Capacity type | Provisioned |
| Cluster storage configuration | Aurora I/O-Optimized |
| Writer instance type | db.r7g.16xlarge |
検証内容・結果
PoC実施の背景 で挙げた5つの課題をどれだけ解消できそうかを主に検証します。
また TiDB User Day に参加した際、セッションの中で気になった以下の点についても検証しました。
- 外部キーは使わない方が良いという噂
これら6ケースについて、TiDB・Auroraで同じ内容を実施し結果を比較しました。
検証で投げるクエリはEC2インスタンス(c6i.4xlarge)からmysql、mysqlslap、sysbench を利用して実行しました。
以下のようなラッパー関数を作成し、各ケースでsourceして使っています。
utils.sh
#!/bin/bash
set -euo pipefail
# mysql
readonly db_host=${DB_HOST:-localhost}
readonly db_port=${DB_PORT:-3306}
readonly db_username=${DB_USERNAME:-root}
readonly db_password=${DB_PASSWORD:-password}
readonly db_database=${DB_DATABASE:-tidb_stress_test}
# mysqlslap
readonly concurrency=${CONCURRENCY:-5}
readonly iterations=${ITERATIONS:-3}
function execute_mysql_cmd () {
local sql=${1}
local start_time end_time
echo "**************************************************"
echo "${sql}"
echo "*"
echo "*"
start_time=$(date +%Y-%m-%dT%H:%M:%S)
echo "Start: ${start_time}"
MYSQL_PWD="${db_password}" mysql \
--host="${db_host}" \
--port="${db_port}" \
--user="${db_username}" \
--database="${db_database}" \
-e "${sql}"
end_time=$(date +%Y-%m-%dT%H:%M:%S)
took=$(($(date -d "${end_time}" +%s) - $(date -d "${start_time}" +%s)))
echo "End: ${end_time} | took ${took}s"
echo "*"
}
function execute_mysqlslap_cmd () {
local sql=${1}
local start_time end_time
echo "**************************************************"
echo "${sql}"
echo "*"
echo "*"
start_time=$(date +%Y-%m-%dT%H:%M:%S)
echo "Start: ${start_time}"
MYSQL_PWD="${db_password}" mysqlslap \
--no-defaults \
--host="${db_host}" \
--port="${db_port}" \
--user="${db_username}" \
--create-schema="${db_database}" \
--no-drop \
--delimiter=';' \
--detach=1 \
--concurrency="${concurrency}" \
--iterations="${iterations}" \
-vv \
--query="${sql}"
end_time=$(date +%Y-%m-%dT%H:%M:%S)
took=$(($(date -d "${end_time}" +%s) - $(date -d "${start_time}" +%s)))
echo "End: ${end_time} | took ${took}s"
echo "*"
}
function execute_sysbench_cmd () {
local script_name=${1}
local other_options=${2}
echo "**************************************************"
echo "Options: ${other_options}"
echo "[${script_name}]"
cat "${script_name}"
echo "*"
echo "*"
# shellcheck disable=SC2086
sysbench \
--mysql-host="${db_host}" \
--mysql-port="${db_port}" \
--mysql-db="${db_database}" \
--mysql-user="${db_username}" \
--mysql-password="${db_password}" \
--mysql-driver=mysql \
${other_options} "${script_name}" run
echo "*"
}
CASE1 巨大テーブルに対するDDLのオペレーションコストが大きい
困りごと
既存のテーブルにALTERを投げる場合、以下のようなロックの懸念があります。
- ALGORITHM=COPY
- ALTER実行中書き込みがブロックされる
- ALGORITHM=INPLACE,INSTANT
- ALTER実行のクエリはブロックされないが、最後にメタデータロックがある
巨大なテーブルではALTERに10時間以上かかることもあり、ALGORITHM=COPYとなるDDLをシステム無停止で実行するのは難しくなります。
ALGORITHM=INPLACE,INSTANTとなるDDLは基本的に無停止で実行可能ですが、微調整できないためメタデータロックのタイミングにリスクがあります。
pt-online-schema-change のようなツールを使うことで解消できる部分もありますが、lock_wait_timeoutとリトライを適切に管理しないと障害につながるケースがあります。私のように。
検証方法
ダミーテーブルを用意し、ALTERを投げてロックが発生するかどうかを検証します。
CREATE TABLE case1_dummy (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name_with_index VARCHAR(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
name_without_index VARCHAR(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
PRIMARY KEY (id),
KEY case1_dummy_name (name_with_index)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci;
insert into case1_dummy (name_with_index, name_without_index) select concat(rand(), ''), concat(rand(), '');
insert into case1_dummy (name_with_index, name_without_index) select concat(rand(), ''), concat(rand(), '') from case1_dummy;
... (20回繰り返し100万行程度にする)
以下の順にクエリを実行し、メタデータロックによる他のクエリのブロックが発生するかを確認します。
- ターミナルA
ALTER前に流れているスロークエリ想定 (クエリAとする)begin; select count(*) from case1_dummy; -- このまま待機させる - ターミナルB
ALTERを実行ALTER TABLE case1_dummy ADD COLUMN new_column BIGINT NOT NULL DEFAULT 0, ALGORITHM=INSTANT; - ターミナルC
ALTERの後に実行されるクエリ想定 (クエリCとする)insert into case1_dummy (name_with_index, name_without_index) select concat(rand(), ''), concat(rand(), ''); - ターミナルA
スロークエリを完了させる-- begin; -- select count(*) from case1_dummy; rollback;
クエリCをALGORITHM=COPYとなるDDLのパターンでも実施しました。
ALTER TABLE case1_dummy MODIFY COLUMN new_column INT NOT NULL DEFAULT 0, ALGORITHM=COPY;
検証結果
| 操作 | TiDB | Aurora |
|---|---|---|
| 2) ALTER TABLE | クエリA完了まで待機 | クエリA完了まで待機 |
| 3) クエリC (INSTANT) | 待機なしで完了 | ALTER完了まで待機 |
| 3) クエリC (COPY) | 待機なしで完了 | ALTER完了まで待機 |
DDLの前に長いクエリ(クエリA)が流れている場合、ALTER TABLE自体はクエリAが完了するまで待たされるという点はTiDB・Auroraで同じでした。
しかし、TiDBではALTER TABLEより後に実行されたクエリ(クエリC)をブロックしません。
これは非常に素晴らしい結果だと思います。
CASE2 歴戦のスロークエリたちが改善できないままになっている
困りごと
スロークエリログに既出のパターンで認識はできているが修正できていない...そんなクエリがTiDBにすることで解消できたら嬉しいという気持ちです。
検証方法
こちらの検証は皆さんが特に知りたい内容かと思いますが、Linyの複数テーブルの構造がモロに露出してしまうため概要のみのご紹介となってしまいます。ご容赦ください...
messagesテーブルはLINE友だちとのチャット履歴やその他システムメッセージを保持しているテーブルで、Linyの中でも最大級のテーブルです。
以下のようなパターンがスロークエリとしてよく出ています。
- インデックスは効いているが、結果セットが大きい
- where in (サブクエリ) のサブクエリが返す行数が大きい
select
*
from messages as msg
-- インデックスが効く条件がいくつか
where msg.user_id = ?
and msg.user_id is not null
and msg.status = ?
...
-- インデックスが効かない条件がいくつか
and msg.message_type in (?)
...
-- 問題点: インデックスは効くが件数が多い where in
and msg.member_id in (
select id
from members as m
where m.user_id = ?
and m.user_id is not null
)
order by time desc limit 101 offset 0;
このようなクエリを何パターンか用意し、sysbenchで実行しました。1スレッドで5回クエリを実行したLatencyの平均で比較します。
TiDBについては、ストレージに TiKV を使うパターンと TiFlash を使うパターンで比較しています。
検証結果
Auroraで160秒程度かかっていたクエリが、TiKVでは20秒程度、TiFlashでは18秒程度で完了できました。爆速です。
ただし、TiFlashが関わるクエリではselect *の使い方に注意が必要です。
JOINなどでTiFlash連携・未連携テーブルが混在するような複雑なクエリでは、不要なTiKVアクセスを減らす工夫が必要になります。
LaravelのようにORMを利用しているケースではmodelのget系メソッドの使い方で注意が必要になるかもしれません。
CASE3 大量のinsertが集中しパフォーマンスが低下する
困りごと
Linyにはアクションの スケジュール実行 という、ユーザーが設定できる定期バッチのような機能があります。
バッチあるあるだと思いますが、0時付近にものすごく処理が集中しています。

特に読み書きが集中するのはLINE友だちに タグ をつけるための中間テーブルです。
レプリカラグを避けるため処理がwriterに集中していることもあり、塵も積もればパフォーマンス低下という状況になっています。
検証方法
スクリプトが少し長いですが、LINE友だち(member)とタグ(tag)の中間テーブルに対してsysbenchで読み書きの負荷をかけていきます。
負荷を調整するため、sysbenchプロセスをselect専用とinsert専用の2つ立ち上げます。
大きな負荷がかかるのでこのケースだけMinimum RCUを50,000に変更しました。
case.sh
#!/bin/bash
set -euo pipefail
cd "$(dirname "${0}")"
. utils.sh
readonly workdir=/tmp/case3
readonly duration_sec=${DURATION_SEC:-15}
readonly select_threads=${SELECT_THREADS:-1}
readonly insert_threads=${INSERT_THREADS:-10}
readonly tidb_mode=${TIDB_MODE:-false} # true/false
# 事前: workdir
rm -rf "${workdir}"
mkdir -p "${workdir}"
cat <<EOF | tee "${workdir}/log_base"
Target: ${db_host}
DURATION_SEC=${duration_sec}
SELECT_THREADS=${select_threads}
INSERT_THREADS=${insert_threads}
EOF
# 準備: CREATE TABLE
if [[ ${tidb_mode} = "true" ]]; then
id_strategy=AUTO_RANDOM
else
id_strategy=AUTO_INCREMENT
fi
cat <<EOF > "${workdir}/create_dummy_member_tag.sql"
DROP TABLE IF EXISTS dummy_member_tag;
CREATE TABLE dummy_member_tag (
id bigint unsigned NOT NULL ${id_strategy},
created_at timestamp NULL DEFAULT '1970-01-01 09:00:01',
updated_at timestamp NULL DEFAULT '1970-01-01 09:00:01',
member_id int NOT NULL,
tag_id int NOT NULL,
PRIMARY KEY (id),
KEY tag_id (tag_id),
KEY member_id (member_id)
);
EOF
# 準備: ANALYZE TABLE
cat <<EOF > "${workdir}/analyze_dummy_member_tag.sql"
ANALYZE TABLE dummy_member_tag ALL COLUMNS;
EOF
# 準備: 負荷試験 insert
cat <<EOF > "${workdir}/test_dummy_member_tag_insert.lua"
function event()
db_query("insert into dummy_member_tag (member_id, tag_id, created_at, updated_at) values (floor(rand() * 10000), floor(rand() * 10000), now(), now())")
end
EOF
# 準備: 負荷試験 select軽め
cat <<EOF > "${workdir}/test_dummy_member_tag_select_small.lua"
function event()
db_query("select * from dummy_member_tag where id between 1 and 1000")
end
EOF
# 準備: テーブル作成
execute_mysql_cmd "$(cat "${workdir}/create_dummy_member_tag.sql")" \
| tee -a "${workdir}/log_base"
# 準備: 初期データ (eventsで止まるようにtimeを長めに設定する)
execute_sysbench_cmd \
"${workdir}/test_dummy_member_tag_insert.lua" \
"--events=100000 --time=120 --threads=$(nproc)" \
| tee -a "${workdir}/log_base"
# 準備: ANALYZE
if [[ ${tidb_mode} = "true" ]]; then
execute_mysql_cmd "$(cat "${workdir}/analyze_dummy_member_tag.sql")" \
| tee -a "${workdir}/log_base"
fi
# 検証: 同時に流す
execute_sysbench_cmd \
"${workdir}/test_dummy_member_tag_insert.lua" \
"--time=${duration_sec} --threads=${insert_threads}" \
> "${workdir}/log_dummy_member_tag_insert" 2>&1 &
execute_sysbench_cmd \
"${workdir}/test_dummy_member_tag_select_small.lua" \
"--time=${duration_sec} --threads=${select_threads}" \
> "${workdir}/log_dummy_member_tag_select_small" 2>&1 &
# 検証: 完了まで待機 (結果まとめの時間があるのでdurationより長め)
sleep_sec=$((duration_sec + 10))
echo "sleep (${sleep_sec} sec) ..."
sleep "${sleep_sec}"
# 結果表示
cat <<EOF
To check the results, run the following command:
$ cat ${workdir}/log_base ${workdir}/log_dummy_*
EOF
# TiDBの場合
TIDB_MODE=true DURATION_SEC=120 SELECT_THREADS=64 INSERT_THREADS=64 bash case.sh
# Auroraの場合
DURATION_SEC=120 SELECT_THREADS=64 INSERT_THREADS=64 bash case.sh
TiDBで利用している AUTO_RANDOM はID採番を分散させることで書き込み性能を向上させるモードです。
検証結果
sysbenchのSQL statistics: QPSで比較します。
insertのQPS比較
| threads | TiDB | Aurora |
|---|---|---|
| SELECT/INSERT THREADS=16 | insert 1069.66 per sec. | insert 2855.55 per sec. |
| SELECT/INSERT_THREADS=32 | insert 1885.83 per sec. | insert 4853.61 per sec. |
| SELECT/INSERT_THREADS=64 | insert 2996.51 per sec. | insert 6296.64 per sec. |
| SELECT/INSERT_THREADS=128 | insert 7531.03 per sec. | insert 9515.41 per sec. |
| SELECT/INSERT_THREADS=256 | insert 8991.89 per sec. | insert 11402.86 per sec. |
selectのQPS比較
| threads | TiDB | Aurora |
|---|---|---|
| SELECT/INSERT_THREADS=16 | select 3995.55 per sec. | select 6741.81 per sec. |
| SELECT/INSERT_THREADS=32 | select 6774.45 per sec. | select 13071.77 per sec. |
| SELECT/INSERT_THREADS=64 | select 9727.65 per sec. | select 24901.79 per sec. |
| SELECT/INSERT_THREADS=128 | select 20060.28 per sec. | select 25557.52 per sec. |
| SELECT/INSERT_THREADS=256 | select 27389.31 per sec. | select 18136.06 per sec. |
TiDBはinsert, selectいずれもクライアント数が増えるほどパフォーマンスが向上しています。
Auroraはinsertが高速でしたが、selectは一定の並列度を超えるとパフォーマンスが低下していました。
(case.shから抜粋)今回selectのクエリは以下のものを利用しました。
select * from dummy_member_tag where id between 1 and 1000
TiDBではAUTO_RANDOMとAUTO_INCREMENTそれぞれで検証を実施しましたがそれほど差は見られませんでした。
検証はできませんでしたが、PingCAP様のパフォーマンスチームから以下のような情報をいただいたので補足しておきます。
- 最低1億レコード程度のデータを予め用意したうえでAUTO_RANDOMを利用することで、insertのパフォーマンス向上が見込める
今回は試験のたびにテーブルを作り直していましたが、データ量が増えるほどTiKVのデータが分散されパフォーマンス向上が見込めるのでデータは消さずに試験をすると良さそう、とのことでした。
本番環境ではデータは増え続けるので、実運用ではこれより良いパフォーマンスが得られる可能性があります。
また、以下のようなクエリはTiDBではかなり不利になります。
select * from dummy_member_tag order by id desc limit 50
このケースはTiDBではフルスキャンになってしまうため、Auroraと比べると数倍遅くなってしまいます。
しかし実際にwhere文なしのorder by + limitというクエリを実行することはほぼないのでTiDBの苦手ケースの一例として捉えています。
ページング処理などで大きな結果セットの一部を取得する処理に影響があるかもしれません。
ページング処理のパターン別の比較記事が参考になります。
CASE4 Auroraのmax_connections限界(16,000)が見えてきている
困りごと
Linyでは500以上のECSタスクが常駐しており、各コンテナにApacheやSupervisorで管理された複数の子プロセスが存在しています。
スケジュールタスク、オートスケール、リリース(ローリングアップデート)によりタスク数が増減することで、瞬間的にmax_connectionsを超える可能性があります。
今はRDS Proxyのおかげで耐えていますが、今後コンテナが増え続けた時に耐えられるかという懸念があります。(そしてRDS Proxyはお高いので廃止したい気持ちもある)
検証方法
コネクション"数"の限界に集中するため、クエリは軽めのものを用意しました。
スクリプト
#!/bin/bash
set -euo pipefail
cd "$(dirname "${0}")"
. utils.sh
readonly workdir=/tmp/case4
readonly duration_sec=${DURATION_SEC:-30}
readonly threads=${THREADS:-12000}
# 事前: workdir
rm -rf "${workdir}"
mkdir -p "${workdir}"
cat <<EOF | tee "${workdir}/log_base"
Target: ${db_host}
DURATION_SEC=${duration_sec}
THREADS=${threads}
EOF
# 準備: 負荷試験
cat <<EOF > "${workdir}/test_dummy_sleep.lua"
function event()
db_query("select now()")
end
EOF
# 実施
execute_sysbench_cmd \
"${workdir}/test_dummy_sleep.lua" \
"--time=${duration_sec} --threads=${threads} --rate=${threads}" \
2>&1 | tee -a "${workdir}/log_dummy_sleep"
# 結果表示
cat <<EOF
To check the results, run the following command:
$ cat ${workdir}/log_base ${workdir}/log_dummy_*
EOF
その他、この検証のみいくつかの設定を変更しています。
- EC2をc6i.12xlargeに変更
- Unknown server hostが発生するので
/etc/hostsにIPアドレスを直書き - エフェメラルポートの幅を変更
sudo sysctl -w net.ipv4.ip_local_port_range='16384 65535'
検証結果
| TiDB | Aurora | |
|---|---|---|
| 最大コネクション数 | 25,000以上 | 16,000 |
Auroraは想定通りmax_connectionsまで、TiDBはコネクション数25,000まで実施し、問題ありませんでした。
今回は25,000までしか検証していませんが、コネクション数だけで見ればこれ以上でも問題なさそうです。
実際に導入を見越す場合はコネクション数に加えて同時に流れるクエリの負荷などを加味して検証する必要があります。
CASE5 Auroraのバージョンアップにシステム停止が必要
困りごと
これに関しては Blue/Greenデプロイ を使えという話ではありますが...
LinyのDBではbinlogを有効化していないためAurora2系→3系のバージョンアップは6時間ほどシステムを停止してバージョンアップを実施しました。
zero-downtime patchingによるバージョンアップもタイムアウトやコネクションが切られるなどは普通に起きます(RDS Proxyのおかげで被害は軽減されていますが、それでもゼロには遠い)。
検証方法・結果
PingCAP様主催のTiDBワークショップ TiDBエキスパートへの道:実践的な知識とPingCAP認定のスキルアップワークショップ の中で「アップグレード時ダウンタイムなし」というハンズオンがあり、その中で挙動を確認しました。
tiupコマンドでクラスタをデプロイし、負荷をかけながらバージョンアップを実行してもクエリの失敗や大きな遅延はありませんでした。
CASE6 外部キーは使わない方が良いという噂
どういうことか
TiDBでは外部キー制約を追加すると、子テーブルのレコードを更新するときに親テーブルのレコードにも排他ロックがかかります。
つまり、子レコードが同時に多数更新されると親レコードのロックの奪い合いが発生します。
擬似的にロックの奪い合いを起こして確認してみます。
検証方法
以下のようなダミーテーブルを用意しました、適当なレコードを何件か入れておきます。
CREATE TABLE case6_dummy (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
PRIMARY KEY (id),
KEY case6_dummy_name (name)
);
CREATE TABLE case6_child (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
dummy_id BIGINT UNSIGNED NOT NULL,
value INT UNSIGNED DEFAULT NULL,
PRIMARY KEY (id),
CONSTRAINT case6_child_fk FOREIGN KEY (dummy_id) REFERENCES case6_dummy (id) ON DELETE CASCADE
);
insert into case6_dummy (name) select concat(rand(), '');
insert into case6_dummy (name) select concat(rand(), '') from case6_dummy;
insert into case6_dummy (name) select concat(rand(), '') from case6_dummy;
insert into case6_child (dummy_id) select id from case6_dummy;
以下の順にクエリを実行し、排他ロックがかかる様子を確認します。
- ターミナルA
親レコードのロックを取る (クエリAとする)begin; insert into case6_child (dummy_id, value) values (1, 1); -- このまま待機させる - ターミナルB
親レコードが同じinsertを実行する (クエリBとする)insert into case6_child (dummy_id, value) values (1, 1); - ターミナルA
クエリAを完了させる-- begin; -- insert into case6_child (dummy_id, value) values (1, 1); commit;
検証結果
クエリBがクエリA完了までブロックされることが確認できました。
この挙動がどの程度問題になるかは実際に流れているクエリから判断する必要があります。
検証結果の判断
PoC第一弾のゴール: TiDBで現状のLinyの困りごとがどれくらい解決できそうかを探る
今回のPoCでは「気になったことを試してみる」ベースでの検証が主でしたが、Auroraと比較したTiDBの強みと気になる点が確認できたと思います。
検証結果を受けての判断: すぐにTiDBへの移行はせずAuroraでできる改善を続ける、今後Linyが成長を続けAuroraの限界が見えてきたら移行を視野に本気の検証を実施する
この判断に至った理由をまとめます。
Auroraと比較したTiDBの強み
- DDLやバージョンアップなどの運用コストは大幅に下げることができそう
- クエリの並列度を上げることでAuroraよりも高いパフォーマンスを引き出せる可能性がある
- TiFlashを有効活用することでパフォーマンス向上が期待できる
Auroraと比較したTiDBの気になる点
- クエリ単発で見るとAuroraよりも遅くなる、特に今回はinsert性能で差が目立った
- Auroraでは問題なかったクエリが遅くなるケースがある (速くなるケースもある)
- TiFlashを有効活用することは簡単ではないだろう
性能以外での比較
- サポートが強い (レスが速い、丁寧)
- コストの見積もりが難しい
- 互換性が高いとはいえ、MySQL→TiDBの移行コストは低いとは言い切れない
特にサポートが素晴らしいというのはTiDB User Dayの多くのセッションで言われていましたが、弊社もPoCとは思えないほど手厚くサポートいただきました。
まとめ
Aurora・MySQLで運用していたシステムをTiDBに乗り換えるという視点では移行コストなどから移行に踏み切れないケースもあると思います。
しかし、これから新規に開発するシステムであればTiDBに最適化した設計を取り入れやすいのでまずは小さく始めて知見を溜め、大規模移行に備えたいという気持ちになりました。
PingCAP様にはUser Dayやワークショップ、PoCなど様々な場面でご支援いただきました。この場を借りて心より御礼申し上げます。
今回の検証方法・結果がTiDB導入を検討している方の参考になれば幸いです。
Discussion