OLTPベンチマークTPC-CをTiDBで実行する

# TL;DR

* OLTP(On-Line Transaction Processing) ベンチマークTPC-C Homepageを **TiDB** で実行し，動作を確認します
    * 「[OLTPベンチマークTPC-CをMariaDBで実行する](https://qiita.com/myoshimi/items/4205ad940214a1f48552)」の続編です

# TiDB概要

* [TiDB](https://github.com/pingcap/tidb)は，google社が提案した分散データベースF1([F1: A Distributed SQL Database That Scales (pdf)](https://storage.googleapis.com/pub-tools-public-publication-data/pdf/41344.pdf))のオープンソース実装です．以下のような特徴があります
    * HTAP(Hybrid Transactional and Analytical Processing)型で，大きなデータセットのリアルタイム処理を対象にしています
    * MySQLクエリ互換
    * 水平方向のスケーラビリティ（並列実行による高速化ができる）
    * ストレージレイヤとして分散Key-ValueストアTiKVを持ち，leveldb, boltdb, rocksdbなど，いくつかのKVSを入れ替えて使用することができます

# TiDBのインストール

* TiDBを実験的にインストールします
    * 分散はしない
    * ストレージレイヤはデフォルトのgoleveldbのまま
    * EC2のt2.smallインスタンス(Amazon Linux2)

## goのインストール

* [公式サイト](https://golang.org/dl/)のgoをインストールします．
(1.12.4をインストールしました．[pingcap/tidb Quick Start](https://github.com/pingcap/tidb/blob/master/docs/QUICKSTART.md)によると，必要なのはgo1.9以上と書いてあるのですが，1.10以降導入の```strings.Builder```が無いと言われてビルドに失敗するので，yumでgoをインストールすると，TiDBがビルドできない場合があります．)

```bash
wget https://dl.google.com/go/go1.12.4.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.12.4.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
which go
# /usr/local/go/bin/go
```

## TiDBのビルド

* ```make```コマンドでtidb-serverをビルドします
* 実行前に，設定ファイルをsedコマンドで若干修正します
    * tpcc_load時に，["statement count 5001 exceeds the transaction limitation"](https://github.com/pingcap/tidb/issues/6042)のエラーが発生してしまうので，その対策です

```bash
git clone https://github.com/pingcap/tidb
cd tidb
sed -e "s/stmt-count-limit = 5000/stmt-count-limit = 10000000/" \
    config/config.toml.example > config/config.toml
make
# Build TiDB Server successfully!
make server
```

## tpcc-mysqlの修正

* コミット間隔が広すぎて，```9500, HY000, transaction too large, len:300001```のエラーが起こるので，```tpcc_load```プログラム実行時のautocommitをオンにして，問題を回避します
    * 参考：[The error message transaction too large is displayed.](https://github.com/pingcap/docs/blob/master/FAQ.md#the-error-message-transaction-too-large-is-displayed)
    * データのロード時間は遅くなりますが，エラーを回避できます

```bash
cd ~/
git clone https://github.com/Percona-Lab/tpcc-mysql
cd tpcc-mysql
sed -i -e "/mysql_autocommit(mysql, 0);/d" src/load.c
cd src && make
# ~/tpcc-mysql/{tpcc_load,tpcc_start}が生成される
```

## TiDBサーバの起動

* ```make server```コマンドで作られた```bin/tidb-server```を実行すると，TiDBサーバが起動します．
    * デフォルトでは4000/TCPで接続を待ち受けしています
    * 必要に応じてrootユーザのパスワードを設定してください（デフォルトは空です）

```bash
/home/ec2-user/tidb/bin/tidb-server \
    -config /home/ec2-user/tidb/config/config.toml
#.....<snip>.....
[2019/04/18 09:43:26.178 +00:00] [INFO] [server.go:218] ["server is running MySQL protocol"] [addr=0.0.0.0:4000]
[2019/04/18 09:43:26.180 +00:00] [INFO] [domain.go:910] ["init stats info time"] ["take time"=2.415889ms]
[2019/04/18 09:43:26.181 +00:00] [INFO] [http_status.go:253] ["for status and metrics report"] ["listening on addr"=0.0.0.0:10080]
```

## MySQLクライアント(mariadb)で接続テスト

* 前項で起動したTiDBサーバに，MySQLクライアント(mariadb)で接続します
    * 接続した先の```Server version```がTiDBであることを確認します

```bash
mysql -h 127.0.0.1 -P 4000 -u root

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.25-TiDB-v3.0.0-beta.1-119-ga19f4d698 MySQL Community Server (Apache License 2.0)
```

* 接続後は，MySQLクエリでデータベース操作ができます

# TiDBでTPC-C MySQLベンチマークの実行

## ベンチマークデータの準備

* [OLTPベンチマークTPC-CをMariaDBで実行する - TPC-C MySQLベンチマークのセットアップ](https://qiita.com/myoshimi/items/4205ad940214a1f48552#tpc-c-mysql%E3%83%99%E3%83%B3%E3%83%81%E3%83%9E%E3%83%BC%E3%82%AF%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)を参考に，TiDBにデータベース，テーブル，インデックスを作成します

```bash
cd ~/
git clone https://github.com/Percona-Lab/tpcc-mysql
cd tpcc-mysql/src && make && cd ..
mysql -h 127.0.0.1 -P 4000 -u root -e "create database tpcc1;"
mysql -h 127.0.0.1 -P 4000 -u root -D tpcc1 < create_table.sql
mysql -h 127.0.0.1 -P 4000 -u root -D tpcc1 < add_fkey_idx.sql
./tpcc_load -h 127.0.0.1 -P 4000 -d tpcc1 -u root -p "" -w 1

...DATA LOADING COMPLETED SUCCESSFULLY.
```

## ベンチマークの実行

* ```tpcc_start```コマンドで，ベンチマークを実行する

```bash
./tpcc_start \
    -h 127.0.0.1 \
    -P 4000 \
    -d tpcc1 \
    -u root -p "" \
    -w 1 -c 32 \
    -r 10 \
    -l 120
```

* ```-c``` で接続数を1以上にすると，以下のエラーが発生します

```bash
8002, HY000, [107] can not retry select for update statement
payment 27:10
```

# 実行結果

```bash
<Parameters>
     [server]: 127.0.0.1
     [port]: 4000
     [DBname]: tpcc1
       [user]: root
       [pass]:
  [warehouse]: 1
 [connection]: 1
     [rampup]: 10 (sec.)
    [measure]: 120 (sec.)

RAMP-UP TIME.(10 sec.)

MEASURING START.

  10, trx: 174, 95%: 86.087, 99%: 144.535, max_rt: 219.411, 177|61.709, 17|31.180, 18|265.861, 18|545.106
  20, trx: 173, 95%: 74.789, 99%: 104.797, max_rt: 116.901, 171|45.104, 17|57.527, 17|184.130, 17|586.898
  30, trx: 161, 95%: 98.442, 99%: 135.526, max_rt: 212.417, 160|61.524, 16|50.483, 16|160.769, 16|633.625
  40, trx: 149, 95%: 104.297, 99%: 155.440, max_rt: 171.512, 151|70.659, 15|33.149, 15|184.273, 15|671.190
  50, trx: 132, 95%: 101.707, 99%: 183.972, max_rt: 200.505, 132|96.509, 13|30.087, 13|360.673, 13|716.512
  60, trx: 146, 95%: 78.788, 99%: 153.176, max_rt: 203.134, 146|116.560, 15|22.338, 15|161.079, 15|899.085
  70, trx: 162, 95%: 78.717, 99%: 130.158, max_rt: 143.581, 159|73.114, 16|36.744, 16|195.115, 15|825.362
  80, trx: 156, 95%: 74.187, 99%: 116.826, max_rt: 156.505, 157|47.547, 16|39.209, 15|232.520, 17|1079.047
  90, trx: 165, 95%: 81.352, 99%: 122.411, max_rt: 194.717, 167|71.724, 16|66.685, 17|205.575, 16|903.697
 100, trx: 169, 95%: 55.061, 99%: 93.866, max_rt: 180.461, 174|34.459, 17|29.073, 17|302.898, 18|846.473
 110, trx: 162, 95%: 82.604, 99%: 93.558, max_rt: 132.451, 157|58.182, 16|21.362, 16|131.207, 15|929.020
 120, trx: 166, 95%: 71.334, 99%: 116.025, max_rt: 179.116, 167|31.039, 17|22.678, 17|148.962, 16|730.660

STOPPING THREADS.

<Raw Results>
  [0] sc:0 lt:1915  rt:0  fl:0 avg_rt: 29.5 (5)
  [1] sc:1656 lt:262  rt:0  fl:0 avg_rt: 5.9 (5)
  [2] sc:159 lt:32  rt:0  fl:0 avg_rt: 6.6 (5)
  [3] sc:154 lt:38  rt:0  fl:0 avg_rt: 84.3 (80)
  [4] sc:0 lt:191  rt:0  fl:0 avg_rt: 235.0 (20)
 in 120 sec.

<Raw Results2(sum ver.)>
  [0] sc:0  lt:1915  rt:0  fl:0
  [1] sc:1656  lt:262  rt:0  fl:0
  [2] sc:159  lt:32  rt:0  fl:0
  [3] sc:154  lt:38  rt:0  fl:0
  [4] sc:0  lt:191  rt:0  fl:0

<Constraint Check> (all must be [OK])
 [transaction percentage]
        Payment: 43.52% (>=43.0%) [OK]
   Order-Status: 4.33% (>= 4.0%) [OK]
       Delivery: 4.36% (>= 4.0%) [OK]
    Stock-Level: 4.33% (>= 4.0%) [OK]
 [response time (at least 90% passed)]
      New-Order: 0.00%  [NG] *
        Payment: 86.34%  [NG] *
   Order-Status: 83.25%  [NG] *
       Delivery: 80.21%  [NG] *
    Stock-Level: 0.00%  [NG] *

<TpmC>
                 957.500 TpmC
```

* TpmCスコアは，同じインスタンスタイプでMySQL上で実行した場合（[OLTPベンチマークTPC-CをMariaDBで実行する](https://qiita.com/myoshimi/items/4205ad940214a1f48552)）と比べて約1/8．小規模データで，かつ，バックエンドがLevelDBで並列化効果が得られないので，速度面では期待できないです．
   * テストで使用する場合のお手軽さを除いて，TiDBが良いパフォーマンスを挙げられる場面が思いつかないです．
    * 状況によって使い勝手が良くなる場面があったら，再度使ってみたいと思います．

# 参考

* [TiDB](https://github.com/pingcap/tidb)
* [F1: A Distributed SQL Database That Scales (pdf)](https://storage.googleapis.com/pub-tools-public-publication-data/pdf/41344.pdf)
* [OLTPベンチマークTPC-CをMariaDBで実行する](https://qiita.com/myoshimi/items/4205ad940214a1f48552)
* [MySQL は分散DBの夢を見るか、Google F1 論文を実装した TiDB を使ってみた](https://www.infiniteloop.co.jp/blog/2016/05/install-tidb/)