概要
1か月強ほどお仕事で開発中のプロジェクトの開発環境のDBにTiDB Serverlessを使ってみたので個人の所感や特徴・学んだ点などを復習も兼ねてまとめておきます。
前置き(注意事項)
※インフラやクラウドなどであったりTiDB自体は初心者気味なので知識の荒さなど間違っている点などはご容赦ください(間違っている点などは優し目にコメントとかでマサカリ投げてくださると幸いです)。
※本記事の内容は執筆対応をしている2023年11月時点のものとなります。
※まだ負荷試験を実施したり本番環境で運用したりといったフェーズではないため将来認識が変わる可能性があります。その辺は将来リリース後などに記事を書く機会があれば書くかもしれません・・・(?)
※本記事公開前にAmazon Aurora Limitless Databaseなるものが来ました。本記事では触れませんがそちらも確認いただいてもいいかもしれません。
TiDB ServerlessってどんなDB?(簡単な紹介)
- NewSQLと呼ばれる、従来のMySQLのようなリレーショナルデータベースのようにトランザクションなどをサポートしつつもNoSQLのような高いスケーラビリティを実現したDBです。
- MySQL互換となっているためMySQLやAuroraなどと切り替えたりを楽に行うことができます。
- TiDB自体が分散データベースとなっており、シャーディングなどの対応なくスケーリングを扱うことができます。
- Aurora Serverless v2のように自動でスケーリングしてくれます。ほとんど負荷がかかっていなければ無料枠に収まる程度になったりと運用負荷の少ない形で扱うことができます。
- db tech showcase 2022 Tokyoというイベントでの来場者アンケートで「今後、利用してみたいデータベース製品」の1位に選ばれたりなどしているそうです。他のDBなどと比べると歴史は浅めではありますがホットエントリなどでもちらほら見かけることが出てきており、段々と注目されていったり事例なども増えていきそう・・・という所感を持っています。
- TiDB自体はOSSとなっており本記事執筆時点でGitHubのスターが3万5千強といった具合にたくさんのスターが付いています。
良いなと思ったところ
シャーディングなどのしんどい対応をしなくて済む
弊社もゲーム業界なので他人事ではないのですが大量のクエリが実行されるとか1つのテーブルに膨大にレコードが追加される・・・となってくるとシャーディングなどの負荷対策が必要になってくることがあります。
参考 :
負荷対策などでやむを得ない場合も多々あると思いますがこの辺は対応すると一気に複雑な実装となったり操作でミスしがちになったり・・・と中々にしんどくなりそうで自分ではその辺保守したくはありません(DB関係の専門家というわけでもない点も踏まえ)。
TiDBでは分散DBとなっており膨大なクエリが短時間に集中されるようなプロジェクトでもシャーディングしなくともシンプルに運用することが可能になっています。
参考 :
スケーリングを気にしなくて済む
TiDBにはSeverless版の他にもDedicated版というものが存在します。こちらは事前にスペックとかを指定しておく形で、AuroraのProvisionedのような雰囲気を持っています。
Dedicated版ではスペックを変更する際にもダウンタイム無しに変更することができます。そのためDedicated版でも手動でのスペック変更などはやりやすくなっています。
一方でなんらか自動化していないと手動でスペック変更の操作をする必要があるため休みの日に突発的に負荷が高まった場合には対応が遅れる場合もあるかもしれません。
TiDBのServerless版ではその辺のスペック変更のスケールアップ・スケールダウンも勝手にやってくれるので気にしなくて済みます(クエリ数とかによる課金とACUによる課金といった差はありますがAurora Serverless v2に扱いとして近い感覚でいます)。
リモートの開発環境などがお安く済む
前節で触れた通りTiDB Serverless版は負荷が少なければコストが非常に安く済みます。無料枠も結構しっかりとあるので開発中の少人数プロジェクトでは今の所大体無料枠に収まるのでは・・・という印象です。
リモートの開発環境でのコストが抑えられるというのは会社の予算承認とかも降りやすく気軽に試してみるといったことがしやすいので大変助かっています。
TiDB Serverlessと似たような雰囲気のAurora Serverless v2に関しては最低スペックが0.5ACUとなり、東京リージョンでは1ACUの1時間辺り0.2ドルくらいの料金となります。無料枠とかは無いのとv2の場合は夜間や休日とかは自動でACUが0となったりはしません。
Aurora Serverless v1の方は夜間など完全にクエリが止まっていれば自動停止してくれますがMySQL8系が使えない点やAuroraも段々とMySQL8系に移行しないとそのうちEoLとかがちょっと怖いところです。また、開発環境とはいえコールドスタートの問題もあります。
そのためv2をそのまま夜間なども止めずに運用すると1ドル150円で計算すると0.1 * 24 * 30.5 * 150 = 月額約10980円でぼちぼちAurora Serverlessの方はコストがかかってきます(リモートの開発環境をいくつも建てる必要が出たりしてくるとちょっと抵抗感が出て来そうではあります)。
また、以前少し触っていたときには0.5ACUは大分スペックが低い(性能比に対するProvisionedのAuroraと比べてコスパ面が厳しめ)ので開発環境とはいえ0.5ACUで足りるのか?といった点もあります。
もう1点、Aurora Serverless v2コスト削減はかなり厳しい結果になりました。先ほど比較をしてはみましたが、ほぼすべてのケースでdb.r6g系統に軍配が上がります。これはやはり5.1倍のベースコストが響いた結果ではないかなと思います。
なので、コスト削減のみを目的としてServerless v2を導入するのは難しいかなという結果になりました。とは言ってもやはりマネージドサービスなので、今後の価格改定に期待という結びに今回はさせていただきます。
引用元 :
Aurora Serverless v2はとても便利なサービスだと思いますがその分最低料金とかスペックに対するコストは高めという印象なので、無料枠が結構しっかりあって且つ便利なTiDB Serverlessの方に個人的には惹かれています。
MySQL互換になっている
AuroraのようにMySQL互換となっているので普段からMySQLやAuroraに慣れていれば違和感なく扱うことができます。クライアントツールやフレームワークとかも同じように使用したりできますし、コマンドとかSQL文法とかもMySQLとほぼ同じです(若干AUTO_RANDOMなどのTiDB特有の追加要素はあります)。
学習コストも抑えられますしMySQLやAuroraとかからの切り替えもさくっと対応することができます。今の所TiDBからAuroraに変更するといった予定はありませんがしばらく触ってみてやっぱりAuroraにしたい・・・となっても開発中とかであれば気軽に切り替えることができるため導入検証時に会社を説得するのもやりやすかったです(※繰り返しになりますが開発体験とか結構気にいってきているため何か致命的なものが発生しなければAuroraとかに切り替えたりはせずにこのままTiDBで進めそうな気がしています)。
DjangoのORMとかが大体そのまま使える
仕事では長いことDjangoを使っているのですが、前節で触れた通りMySQL互換なのでDjangoとかのフレームワークでのORM(モデル)がそのまま使用できます。マイグレーションとかも動いてくれます。
ただし以下のDjagno + TiDB用のライブラリは入れる必要があり、settings.pyのDATABASESのエンジン設定とかだけはしないとDBマイグレーション時にエラーで引っかかりました。
また、Dedicated版は最近MySQL8系互換が使えるようになりましたがServerless版は本記事執筆時点ではまだ8系互換は利用できません(Dedicated版と比べて少し遅れてServerless版も新しくなってきている印象なので8系利用は少し待つ必要がありそうです)。
本記事執筆時点で最新のDjangoのLTS版のバージョンが4.2.xとなっていますが4.2.xではMySQL8系以降のみのサポートとなっているためServerless版の場合は1つ前の4.1.x系を今の所使う必要があります。
開発中のプロジェクトでの利用なので少なくともリリースまでには8系互換のServerless版が使えるようになるでしょう・・・と思っていますが本番運用中のDjangoプロジェクトで4.2.x系を使っている場合にはTiDB Serverless版への切り替えとかは注意が必要かもしれません。
※Django4.2.x系のセキュリティアップデートのEoLは2026年4月、4.1.x系は2023年12月になっています。
DBのバージョンアップとかも意識しなくて済む
この辺は自前で慎重に実施したい・・・といった意見も結構あるとは思いますがServerless版は手動でアップデートなどをしなくとも日々自動でダウンタイム無しにDBバージョンがアップデートされていくのでEoL期限が迫ってしんどい思いをしたりせずに済み、新しいバージョンによるセキュリティ面や新機能、パフォーマンス改善などの恩恵を得ることができます。
保守負担が減るので人数の少ない小さいチームとかでも楽が出来て良いと思います。
テーブル構造の変更などがしやすい
新しいMySQLやAuroraバージョンであれば比較的ALTER TABLEなども実行しやすい印象ですが、一方で本番環境で想定外のロックがかかってひやっとした・・・的なケースが発生するとちょっと怖いところではあります。
例 :
TiDBの場合インデックスの追加なども含めテーブル構造の変更はロック無しに実施することができます。DBの知識が浅いので「この条件は気を付けないとロックがかかる」的なことをあまり意識しなくて済むのは助かります。
色々考えなくともダウンタイムが少なくできそう
TiDB自体が分散DBとなっており、一部分で障害が発生した場合の迅速な復旧を自動でやってくれます。自前でマルチAZやフェイルオーバーなどを意識しなくともよしなに動作してくれます。詳しくは触れませんが単一障害点になりにくい仕組みが色々入っているようです。
また、TiDB自体は1つのメモリの大きいハイスペックなインスタンスに依存したりはせずに分散して高いパフォーマンスを確保する・・・といった形になっており、後述するCached Tablesとかの機能を除いて個々のサーバーはメモリにあまり依存していません。
そのためメモリの大きいインスタンスが死んでフェイルオーバーで復旧したもののデータがメモリに乗るまでコールドスタート的にパフォーマンスが悪いといった状況になりにくく、元のパフォーマンスまでの復帰が短時間で実現するらしいです。
サポートがしっかりしている
AWSの中の方々も素晴らしいサポート・・・と日々思っていますが、TiDBのPingCAP様にも素晴らしいサポートを受けておりその辺りはとてもしっかりしている・・・という印象です(オフラインでのTiDB講義やハンズオンワークショップなどの時やチャットやMTG時のやりとりなど諸々踏まえ)。
仕事だとこの辺のサポートなどがしっかりしていると個人的にはやはり大分安心できます。
設定がシンプル
設定項目がたくさんあったりすると中々最初の学習コストやら設定ミスやらで苦戦しそうですがTiDB Serverlessはとても設定がシンプルで好みでした(開発中の少人数プロジェクトではその辺で苦戦せずになるべく機能開発に人的リソースを割きたいというのもあり)。
クラスターをぽちぽちと数ステップで作成し、AWS環境から安全に接続するためのVPC設定などをAWS側で実施したら利用が可能になりました。
UIもシンプルで個人的には好みです。
スロークエリなどのログや統計値などが最初から保存・確認できる
何も考えずにクラスターを作成した時点で設定などしなくともスロークエリなどのログが保存されるようになったり、スロークエリの統計値、その他DBの基本的なメトリクスなどが最初からグラフ表示などもされたりと自前で設定などしなくとも参照できるようになっています。
この辺も設定とか整備とか考えなくて済むので機能開発に集中できて良いなと思いました。
小規模で更新頻度の少ないテーブル向けのキャッシュ機能がある
テーブル全体で64MBという制約があるのでユーザーデータのテーブルとかは使えないのですが、小規模で更新頻度の少ないテーブルではCached Tablesという機能でTiDB上にデータを持つことができます。
参考 :
例えばマスタデータみたいに行数がそこまで多く無いもののアクセスが多く、且つ更新頻度もデプロイ時などのみで低い・・・といった場合にTiDB完結で負荷軽減(SQLクエリ軽減)的に使用することができます。
キャッシュ更新間隔はRedisのように自分で指定することができます。10秒とかに設定したり、もしくはデプロイ時しかデータが変わらないテーブルであればデプロイ時以外は数時間といった具合にキャッシュ更新間隔を長くしてもいいかもしれません(長くした方が負荷は下がります)。
注意点としてこの機能はテーブル全体(インデックスなども含む)で64MB以内のテーブルでしか使用できません。64MBを越えているテーブルに対して新たにキャッシュ設定をテーブルに行うことはできないのと、既に設定されているテーブルに関しても書き込みが弾かれるようになります。
ゼロETLで分析が出来る
通常のTiDBは行指向のDBとなります。一方で分析での集計みたいな作業ではBigQueryやParquetを使ったAthenaのように列指向のデータの方が大規模データでは向いています。
通常は分析用のログとかはBigQueryやS3に送ってRedshiftやAthenaで扱えるようにする・・・という手間をかける必要がありますが、TiDBにはTiFlashというものありBigQueryなどと同様に列指向のデータとしてSQLを実行することができます。
参考 :
デモとしてTiDBを使ったOSS insightというサイトで膨大なデータに対して高速な分析が実行されています。
※リアルタイム分析の現実解。今話題のHTAPの実力とは?のスライドの22ページ目から引用。
設定としては既存のテーブルに対してTiFlashを使用する形に設定すればそれだけで使えるようになります。つまりログの送信とか別の分析用のDBを用意したりなどせずともシンプルにTiDBで完結することができます。いわゆるゼロETLと呼ばれるもので分析環境をとてもシンプルにすることができます。
※Aurora + Redshiftとかでも最近ゼロETLで扱えるように・・・となってきているのでその辺に近いものに近いイメージになります。
参考 :
普通にログを送って別途分析用のDBを設ける・・・という形になると、AWS環境であれば通常のデータ保存はAurora、データの送信はFirehoseやFluentd・embulkなどを使いデータの保存先はS3、データの加工は必要に応じてGlueやMWAAなど、そして分析用のDBはRedshiftやAthena・・・といった具合に使用する技術が一気に多くなります。
中々開発中の少人数チームだと大変ですし使う技術を少なくして学習コストを抑えて機能開発などにリソースを割きたいところです。
TiDBを使う場合この辺は使うものがTiDBのみとなりとてもシンプルになります。
また、通常のインサートなどでのデータ更新もほぼリアルタイムでTiFlash側に反映されるため、リアルタイムのデータの分析などにも活用することができます。
ただしTiFlashを使うと対象のテーブルで通常のデータと行指向のデータで2重にデータを持つ必要があるためディスクコストはかかります。その辺のディスクコストでの注意点は後々の節で触れます。
※TiFlashを追加したテーブルに対して、分析などでの利用が不要になったらディスクコストの節約的にTiFlash設定を解除するといったことはできるそうです。
TiFlashは定期的な集計バッチなどでも役立ちそう
TiFlashを使ってリアルタイムに列指向のデータに対して分析用のクエリを投げられるということは定期的なリアルタイム気味な集計バッチなどでも活躍してくれそうです(実際に講義中に質問させていただいたらそういった用途も向いているとのことで)。
行指向のデータを参照するか列指向のデータを参照するかはテーブルごとにSQL内容に応じて自動で判定してくれる
TiFlashを使用しているテーブルの場合、集計とかで使うようなSQLは列指向のデータで扱われて高速に処理されます。一方でインデックスが貼られたカラムで特定の1行をピンポイントに取得するといった場合には行指向のデータの方がデータ取得が高速に(一瞬で)処理されます。
TiDBではTiFlashを有効化しているテーブルに関してはスマートセレクションという機能でSQL内容に応じて行指向のデータにアクセスするか列指向のデータにアクセスするかを決定してくれます。
つまりSQLで扱う際には意識しなくともよしなに行指向のデータにアクセスするか列指向のデータにアクセスするかを自動で判定してくれます。
スマートセレクション
TiFlashレプリカを含むテーブルの場合、TiDBオプティマイザは、コスト見積もりに基づいてTiFlashレプリカを使用するかどうかを自動的に決定します。
引用元 :
ちなみに1つのSQL内でJOINなどで複数のテーブルへのアクセスがある場合にはテーブルごとに行指向のデータへアクセスするのか列指向のデータへアクセスするのかを判定してくれるそうです(1つのSQL内でどちらかに統一されるといったことはなくテーブルごとに効率の良い方が選択されます)。
ユーザーデータのテーブルとログテーブルなどを同じDBで扱えるので実装がシンプルになる
ユーザーデータのDBと分析用のDBの技術が分かれているとスキーマ定義や管理など含め必要な対応が増えて少し面倒です。プロジェクトがリリース後にヒットして経年でログが巨大になってきたりずると話は別ですが、小さいプロジェクトではヒットするかどうかも分からないのでまずはシンプルにして早めにリリースが出来るようにしたいところです。
TiDBではそれぞれをTiDB上に統一できるためシンプルになります。Djangoなどを使っているプロジェクトであればユーザーテーブルもログテーブルも共にCREATE TABLEやALTER TABLEなどはDjangoのモデルに任せてSQLを書かなくとも扱えます。ログテーブル用に別のスキーマ定義用の仕組みやGlueクローラーでのスキーマ判定などもしなくて済みますし、テーブル構造の管理もDjangoのモデルに集約されます。
この辺は他社様の事例でも複数DB → TiDBに集約する形でシンプルになったという事例もあるので参考として引用しておきます。
...
このMicoCloudを支えるデータベース基盤は当初、主にそれぞれの用途に適した3つのデータベースで構成されていました。数百種類の顧客属性を含む顧客のさまざまな情報を保存するNoSQLの「Amazon DynamoDB」、マスターデータベースとして企業を中心とした情報を扱うリレーショナルデータベースの「Amazon Aurora MySQL」、そしてデータウェアハウスとしてデータ分析を担う「Amazon Redshift」です。
...
しかしMicoCloudの急成長とともに種類の異なる3つのデータベースを運用し続けていく過程で、さまざまな課題が表面化します。まず、DynamoDBとAmazon Aurora MySQLから、データウェアハウスのAmazon Redshiftへデータを集約するためのデータ転送の複雑さがありました。
データベース間のデータ転送は一見単純そうに見えますが、スキーマを持たないNoSQLからスキーマを持つAmazon Redshiftへのデータの変換、値を検査するバリデーションなどを伴い、さらに転送済みのデータは元のデータベースから削除するなど、いくつもの仕組みが備わっています。
通常の運用作業においても、3種類のデータベースに対してそれぞれ監視や通知の設定が必要となり、データベースのバックアップやリストアを行う際には3種類のデータベース相互の整合性を維持する慎重さが求められました。
引用元 :
ログのテーブルに対してTiDBを使う場合にはGDPRなどを意識した作りにできるかもしれない
この辺は大量のログに対して試さないと負荷などの面でなんとも・・・という感じですが、ユーザーテーブルとログテーブルを同一のDB環境で扱える場合、ユーザーテーブルとログテーブル間で外部キー制約などを行うことができます。外部キー制約を使うことで例えば退会処理やユーザーデータ削除要請があった場合にログ側も一緒にユーザーIDにnullなどを設定したりといった制御が可能になります。
こういったログテーブルでの外部キー制約の利用の何が嬉しいか・・・といったところなのですが、アプリなどをグローバル展開した際にGDPRやCCPAなどの忘れられる権利などでログデータの個人との紐づけを解除したい時(対象のユーザーのIDなどをログから消したい・ただし課金金額などの重要な数値はログに残しておきたい時など)に役立つかもしれないと考えています。
通常のS3などに送るログは中々この辺の特定ユーザーのログのユーザーIDを全期間のログに対してnullにする・・・とかは中々しんどいというかあまりやりたくない作業となるのでもし外部キー制約で楽で出来るならいいな・・・と考えています(この辺は負荷的に実際に使ってみたら微妙・・・といったことはあるかもしれないため将来検証とか次第で色々考えが変わってくるかもしれませんが・・・)。
ユーザーデータとログデータの整合性をしっかりと取ることができる
ユーザーデータとログデータが両方ともTiDBに(少なくとも最初の保存時は)保存されるようになっていれば、ユーザーデータの更新などを行うリクエスト中にそのログも取る・・・といったことも整合性を取りやすいです。
例えばDjangoでは任意のリクエストでそのリクエストの最初から最後まで1つのトランザクションで扱ってくれるといった設定があります。それを使うことでTiDB上でユーザーデータの更新とログの保存が確実に完了するまで1つのトランザクションで扱う・・・といった制御ができるようになります。
1つのトランザクションで扱うことでユーザーデータ側の更新で何らかエラーになった場合でもログの保存側でエラーになった場合でもそれぞれそのリクエストの処理がまるごとロールバックされます。
処理が正常に一通り通っていれば更新処理とログの保存が1対1となる形できっちりと保存されます。ログの送信などを別の技術やサービスなどを使っていてログ側だけ稀に保存が失敗していたとか、送信処理の過程で稀に発生したリトライ処理でログが2重に保存されている・・・といったことも起こりにくくなり、ログが綺麗になります。もしくはログ送信過程で一部データが稀に破損してしまったり・・・といったこともあるかもしれません(JSONでS3に送った際にJSONが一部途切れてしまったり等)。
この辺のログを綺麗にする作業は通常はデータクレンジング的にデータレイク → データウェアハウスとかに保存する過程でETL処理とかを挟んで重複行を取り除いたり・・・といった制御を挟んでいる会社も多いと思いますが、その辺の作業をシンプルにできるため少人数で開発しているプロジェクトとかだと工数が節約できて助かります。
分散DBで集計関数などで効率的に計算されるようになっている
TiDBの講義を受けていて面白いなと思ったのですが、例えばSUMとかCOUNTとかの集計用の関数とかは分散DBで可能な場合には各サーバーで計算された後に計算結果をさらに集約して最終値を計算する・・・といった効率化がされているそうです。
分散DBという性質上集計処理とかは複数のサーバーに対してデータを参照する必要がありますが、集計とかをする前に全データを1つのサーバーに集約して一気に計算・・・とすると、集約先のDBに大量のデータを送らないといけなくなります。
それに対して各サーバーごとに計算してから計算結果を集約して再計算・・・とすると送受信するデータは一気に小さくできます。例えばSUMの処理でAサーバーでは計算結果が500万、Bサーバーでは700万という計算結果になった場合、最後の500万と700万という計算結果だけ別途集約して最後にさらに合算して1200万という計算結果を返す・・・といった具合でしょうか(PythonのDaskやVaexみたいなものでの並列計算みたいなものを連想しました)。
全ての集計関数とかはサポートしているわけではないとのことですが、普段の利用で意識しなくともこの辺は可能な場合に最適化してくれるのは良いなと思いました。
テーブル構造を参照した形でのChatGPTでのSQL作成とかの機能がある
分析用DBのスキーマとかをChatGPTに教えてあげて分析用のSQLを書いてもらう・・・といった使い方をされている会社もあると思いますが、その辺はTiDBに既に機能として組み込まれています。TiDBのコンソールでSQLのコメントとかを書けばコメント内容に合わせたSQLを書いてくれます。
自前でスキーマ情報とかをChatGPTに食べさせたりなどを整備しなくてもすぐに利用できるためお手軽そうです。
確実に意図したSQLをストレートに書いてくれるとは限らないとは思いますが、一方で分析のSQLとかだと結構複雑になったりもするのでサポート用としていいと思います。
今後アップデートで改善してくれたら良いなと思うところ
Serverless版のMySQL8系互換サポート
前節でも触れた通りDedicated版はMySQL8系互換のサポートが入ったもののServerless版は本記事執筆時点ではMySQL8系はまだサポートされていません。一方でDjangoの新しいバージョンでは8系のものしか使えなくなってきていたりと利用できるDjangoでのEoLの問題がでてきます。
そのため色々と大変かとは思いますがいつかServerless版もMySQL8系互換のバージョンが来たら嬉しい・・・と感じています。
また、お仕事ではローカルの開発環境では最初はMySQL8系を使っており、その後リモートの開発環境を整備する際にTiDBを使い始めて使っていたDjangoのバージョンでは8系じゃないと動かないということを知って古いバージョンに下げましたが、その辺の切り替えはさくっと終わっています。
別の稼働中のプロジェクトで古いMySQLからAuroraのMySQL8系互換のDBへの移行もやったこともあるため、開発途中での8系への切り替えはそこまではこちらの作業量自体や影響範囲などはそんなに心配していません。
古いログデータのディスクコストを下げられる仕組みがあると嬉しい
分析でもTiDBが使えると前節までで触れてきましたが、一方でディスクコスト的なところはBigQueryやS3(AthenaやRedshiftなど)と比べると高くつきます。
S3で比べてみても元々のディスクコストがに結構差がありS3の方がぐっと安いのに加えて、古くてアクセスのあまりないログに関してはStandard-Infrequent AccessやGlacier Instant Retrievalなどのストレージクラスになるようにライフサイクル設定をしておくことでさらにぐっとディスクコストを下げることができます。
また、分析用としてはTiFlashなども併用するとディスクコストが2重にかかるようになるので余計に差が大きくなります。
(一方でデータの送信周りやETLなどでの加工処理にかかるコストは減りはしますが・・・)
データ基盤を整えるというのもぼちぼち大変で人的リソースのかかる作業なので新規プロジェクトではリリースまでのスピード重視でTiDBで統一としたいと考えていますが、リリースして極端なヒットをした場合、もしくは経年(リリースして3年経ったなど)でログ量が膨大になってきた場合に恐らく何らか手を加える必要が出てくるかな・・・と思っています。
例えばリリースして数年してから古いログをS3に逃がしてTiDB上で使用しているディスクサイズを減らしたり・・・といった具合です(リリースまでは忙しいと思いますがその後は段々と数年すれば落ち着いてくるプロジェクトも多いでしょうからそのタイミングでその辺を整備するなど)。
技術的にはかなり大変そう・・・とは思っていますが、できれば長期運用することになったプロジェクトでもその辺ずっとTiDBのままでいけるととてもシンプルなので、うちのプロジェクトでももしかしたら問題になってくるかもしれない数年後とかになんらかこの辺の機能があると嬉しい・・・とは思いますw
(古いログデータはパフォーマンスは悪くなるもしくはS3 Glacier Instant Retrievalみたいに取り出しコストで課金される形で、ただしディスクコストは下げられる的なオプションなど)
Serverless版のバックアップ機能の拡充
TiDBの講義とかではバックアップ関係はDedicated版を中心にお聞きしていたのですが、本記事執筆時点ではServerless版はバックアップ周りの機能でDedicated版よりかは機能が制限されているようにドキュメントを見る限り見受けられます。
万一の時のための自動バックアップなどはありますしまだ本番環境のDBを吹っ飛ばしたりした経験はなくケースが稀なことを考えると必要十分・・・かもしれませんが、出来たらDedicated版にある手動のバックアップや別のクラスターへの復元などもサポートが入ると良いなとは少し思います。
注意が必要そうなところ
外部キー制約関係
PingCAP様とチャットでやりとりしていたりしていた時に外部キー制約周りでケースによっては負荷になりやすいという点をご共有いただきました。MySQLとその辺は挙動の雰囲気が違うため、TiDBを既に使用されている方々でMySQLの感覚で使っていた場合に負荷になる・・・といったケースがあるそうです。
具体的な挙動としては外部キーとなるIDを持つテーブル(親テーブルとします)に対して同じ行のIDで複数のユーザーがそのIDを使って別のテーブル(子テーブルとします)に対してインサートやアップデートを行う場合、LOCK IN SHARE MODEというロック方式がTiDBでは現在サポートされていないためロックの競合で負荷になりやすい・・・といった感じのようです。
参考 :
具体的に負荷になりにくい外部キー制約のケースと負荷になりやすいケースを上げてみます。
負荷になりにくい外部キー制約のケース例
親の特定行を大量のユーザーを持つ子のレコードのインサートやアップデートが走らなければロック面で影響が少ないので、例えば親のテーブルがユーザーデータの基本的なテーブルで、子のテーブル側がユーザーの所持アイテムデータのテーブルで子のテーブルに外部キー制約で親のテーブルのユーザーIDを持つとします。
この場合は親側でロックがかかる行が重複しにくいのでロックに起因して負荷になりにくくなります。例えば親のユーザーデータのテーブルが500万行あればそれぞれでロックをかける行が分散しますし、ユースケース的に他のユーザーの行を外部キーで参照する・・・といったケースは稀なため負荷になりにくいと思われます(大体は自身のユーザーIDを他の子のテーブルで使用するといったことが多いかなと)。
負荷になりやすい外部キー制約のケース例
親の特定のレコードを複数ユーザーの子のテーブルから外部キー制約で参照する場合は負荷になりやすいです。例えばアイテムデータのマスタデータがありその中に200レコード程保存されていたとします。
ユーザーのアイテムデータのテーブルでそちらのマスタデータを親として外部キー制約を貼る形にします(ユーザーのアイデムデータのテーブルが子となります)。
この場合複数の大量のユーザーから同じマスタの特定行を参照する形となり、親の行が少ない割に子の行数がぐっと多くなり、且つ複数ユーザーからも親を参照される・・・ため現在のロックの挙動的に負荷になりやすいので注意が必要です(特に子の行の書き込みが大量になりうる場合)。
キャッシュ機能の上限サイズ
前節でも触れましたが小規模なテーブルに対するキャッシュの機能(Cached Tables)はサイズが64MBまでとなります。インデックスなども含むサイズなので注意です。
書き込みなどもでぎなくなるため最初は小規模なマスタテーブルだったものの運用していて経年でいつの間にか64MBに達していた・・・みたいな感じで突然「何もしていないのに壊れた」的なケースは発生するかもしれないため、必要に応じてCached Tablesの機能を有効にしているテーブルサイズの監視などはしておくと良いかもしれません(50MB辺りを越えたらアラートが飛ぶようにして越えたらCached Tablesの設定をそのテーブルで外すなど)。
テーブル単体のサイズ確認は以下のFAQなどをご確認ください。
Cached Tablesを使った場合のテーブル構造変更
Cached Tablesの機能を設定したテーブルではキャッシュ設定を一旦外さないとALTER TABLEなどでのテーブル構造変更が効かなくなります。
Direct DDL operations on a cached table are not supported. You need to set the cached table back to a normal table first by using ALTER TABLE t NOCACHE before performing DDL operations.
引用元 :
ALTER TABLEなどをしたい場合には一旦Cached Tablesの設定をそのテーブルで外してからALTER TABLEを行い、その後キャッシュ設定を元に戻す・・・といった制御が必要になります。
分析で使う場合のディスクコスト
こちらも前節までで色々と触れてきましたが、TiFlashを使った分析はリアルタイムにログにアクセスできてログ基盤の整備の手間も減り使う技術もぐっと減らすことができて工数を節約できる・・・というメリットがありますがBigQueryやS3などと比べるとディスクコストは現状では結構高くなります。
ヒットしたり長年続くプロジェクトになってくるとログ量が積みあがってきて割とディスクコストが馬鹿にならなくなってくるのでそういった場合にはどこかのタイミングでS3に古いログを逃がすなどの対応が必要になるかもしれません。
リージョンは利用するクラウドのリージョンと合わせておく必要がある
TiDB Serverlessは裏側はAWS上とかに立つ形になります。そのため基本的にはバックエンドなどのTiDBに接続するサーバーとTiDB Serverlessのリージョンは合わせておくとVPC設定や通信料などの面で好ましいかもしれません。
TiDB Serverless側で使用できるリージョンは種類が限られているのでこの辺も注意が必要です。例えば本記事執筆時点ではドキュメントを見るとオレゴンや東京リージョンなど含め5リージョンがサポートされているように見えます。バックエンド側で別のリージョンを使っている・・・といった場合には少し考える必要があるかもしれません。
引用元 :
AUTO_INCREMENTとAUTO_RANDOM関係
TiDBでは主キーに連番を振る形のAUTO_INCREMENTはパフォーマンスの面であまり推奨されていません。
というのも分散DBでのデータ参照先の割り振りが主キーなどで判定されるようで、連番の場合は書き込みなどのアクセスが特定のサーバーに集中する(一方であまりアクセスの発生していないサーバーが発生したりする)といった具合に負荷効率の分散的にあまり好ましくない挙動になるそうです(いわゆるホットスポットなどと呼ばれます)。
これはTiDB特有の問題という感じでも無く、恐らくGoogle Spannerとかの他の分散DBでも似たような注意点はあるかもしれません(Spannerに関しては詳しくないので割愛)。
TiDBではこの問題を回避するためにAUTO_INCREMENTの代わりに使えるAUTO_RANDOMというものが用意されています(AUTO_RANDOMはユニーク且つランダムな整数が主キーに設定されます)。
この辺を使うか、もしくはハッシュ値などを主キーに使うか、もしくは自前でDjangoの保存時の処理でランダムな値を割り振るようにするか・・・などがパフォーマンス面で好ましい感じになります。
以前からのMySQLもしくはAuroraなどのDBでAUTO_INCREMENTを既に使っていて今からTiDBに移行するのでAUTO_RANDOMへの切り替えは厳しい・・・といったようなケースを除いて今後スタートするプロジェクトなどでは初手からAUTO_RANDOMなどの方の利用が無難そうです。
データ量による性能限界
スケーリングとかで考えることがぐっと減るTiDB Serverlessですが性能限界が無いわけではありません。データ量で性能限界があり、本記事執筆時点だと大体600TBを越えてくると苦しい・・・とのことです。
これは分散DBでデータ量に応じてどんどん分散量が多くなっていくわけですが、それらのやりとりでのハートビート周りでネットワーク面で先に限界を迎えるから・・・とのことです。
600TBとなると余程ヒットしてユーザーが膨大にならないと越えない気もしますが、それ以上に関しては今後のアップデートで改善するかもしれないとのことですが一応限界はあるということは頭に入れておいてもいいかもしれません(それ以上はそもそものServerlessのクラスターを分けるなどが必要になってくるかもしれません)。
参考文献・参考サイトまとめ