
著者: Shawn Ma (Product Manager and Tech Leader at PingCAP)
トランスクリエーター:Fendy Feng
編集者:Calvin Weng, Tom Dewan
最近、Google (AlloyDB) 、Snowflake (Unistore) 、Oracle (HeatWave) といった大手が参入し、HTAP (Hybrid Transactional and Analytical Processing) が話題になっています。しかし、それでも何がHTAPデータベースの特徴なのか知らない人が多いようです。
TiDBは、オープンソースの分散型HTAPデータベースです。長年にわたり、さまざまな業界の何千もの企業がTiDBのHTAP機能を利用してきました。しかし、HTAPデータベースの構築は非常に長い道のりであり、私たちはまだその途上にあります。
筆者もTiDBのHTAPアーキテクチャを設計・開発した一人です。この記事では、リアルタイム分析技術のHTAPをTiDBに搭載する設計を決定した際の裏話や、どのようにお客様から学び、お客様、研究者、開発者から信頼されるHTAPデータベースを構築したかを紹介します。
HTAPの夢のはじまり
TiDBの初期バージョン、主にTiDB 2.0以前は、水平方向のスケーラビリティ、高可用性、強力な一貫性、MySQLとの互換性を備えたオンライントランザクション処理 (OLTP) に強いデータベースとして設計されていました。
下図は、TiDBサーバー、PD (Placement Driver) 、TiKVサーバーの3つの主要コンポーネントからなるTiDBのオリジナルアーキテクチャを示したものです。このアーキテクチャは、カラムナエンジン、MPP (massively parallel processing) アーキテクチャ、ベクトル化などの最近の機能は含んでいませんでした。

TiDBのオリジナルアーキテクチャ
PDはデータベースシステム全体の頭脳であり、ストレージノードのスケジューリングとワークロードのバランスを保つ役割を担っていました。TiKVは、データを分散して保存するストレージエンジンで、ノード間でACIDトランザクションをサポートした行形式を使用します。TiDBサーバーは、古典的なvolcano execution設計のステートレスSQLコンピュートエンジンでした。
アーリーアダプターを獲得しようとしたところ、ほとんどのユーザーがミッションクリティカルなトランザクションのケースで真新しいデータベースを使うことをためらっていることがわかりました。その代わりに、分析ワークロードのバックアップ用データベースとしてTiDBを使おうという傾向がありました。以下のようなやり取りが何度もありました。
- “これはエッジの効いた分散設計です。シャーディングのない素晴らしい体験を見逃すわけにはいきませんよね” 私たちは、TiDBを採用するよう潜在的な顧客を説得しようとしました。
- “うーん” 彼らは答えました。”面白そうですね。まずは分析ワークロードの読み込み専用レプリカとして使ってもいいですか?どうなるか試してみたいです。”
分析クエリを高速化するために、コプロセッサフレームワークをTiDBに実装しました。これにより、アグリゲーションやフィルタリングなどの限定された計算をTiKVノードにプッシュダウンし、分散して実行できるようになりました。このフレームワークは非常によく機能し、多くの方にTiDBを採用していただくことができました。

TiKV コロプロセッサ
ありがとう、Apache Spark!
当初は順調だったのですが、やがてより複雑な分析シナリオに突き当たることになります。お客様からは、TiDBはOLTPシナリオでは非常によく動作するが、オンライン分析処理 (OLAP) シナリオ、特にTiDBを使って大量のデータを分析し、大きなJOINSを実行すると「ちょっと遅い」と言われました。また、TiDBはビッグデータのエコシステムとも相性がよくありませんでした。
これは、スケーラブルなストレージに対してTiDBが持つ計算能力が不釣り合いだったことが原因でした。
TiDBのストレージシステムは拡張できますが、演算コンポーネントであるTiDBサーバーは拡張できません。OLTPのシナリオでは、TiKVの上に複数のTiDBサーバを追加することでこの問題を解決することができました。しかし、OLAPのシナリオでは、1つ1つのクエリが非常に大きくなる可能性があります。TiDBはMPPアーキテクチャではなかったため、複数のTiDBサーバーで1つのクエリのワークロードを共有することはできませんでした。そのため、大規模なJOINのような処理には耐え難いほどの時間がかかっていました。そこで、データをシャッフルし、スケーラブルなストレージ層と連携して大規模なクエリに対応できるスケーラブルな演算層が急遽必要になったのです。
この問題を解決するためには、独自のMPPフレームワークを用意するか、外部のエンジンを活用する必要がありました。当時は小さなチームだったので、TiDB 3.0では、優れた統合計算エンジンであるApache Sparkを活用することにし、TiKVの上にTiSparkというSparkプラグインを構築したのです。TiKVクライアント、TiDB互換の型システム、いくつかのコプロセッサ固有の物理演算子、プランリライターが含まれていました。TiSparkは、SparkのSQLプランをコプロセッサのプランに部分的に変換し、TiKVから結果を収集し、ネイティブSparkエンジンで計算を終了させます。Sparkの柔軟な拡張フレームワークにより、Sparkのコードを1行も変更することなく、これらすべてを実現することができました。

TiSparkのアーキテクチャ
TiSparkは、大規模な分析クエリではTiDBを強力にサポートしますが、中小規模のクエリではあまりうまく機能しませんでした。この問題を解決するため、TiDBのネイティブ計算エンジンも改良しました。TiDBのオプティマイザをルールベースからコストベースに変更し、ジャストインタイム (JIT) 設計も改善したのです。
もう一点、TiSparkはTiDBとビッグデータエコシステムの間のギャップを埋めました。多くのシナリオで、TiDBはSparkのシームレスな統合により、OLTPレイヤーとデータレイクの間のウォームデータプラットフォームとして機能しています。
カラムナーストア無くしてHTAPは無い
TiDB 3.0に搭載されていた機能をもう一度おさらいしてみましょう。ストレージレイヤーの上にコプロセッサがあり、スマートな演算子を持つコストベースのオプティマイザ、シングルノードのベクトル化された計算エンジン、そしてSparkアクセラレータを備えていました。これらすべてを備えていたにもかかわらず、TiDBはまだ真のHTAPデータベースではありませんでした。
第一に、TiDBは分析に不可欠なカラムナストレージエンジンを持っていませんでした。第二に、TiDBはワークロードの分離をサポートしておらず、ワークロードの干渉が頻繁に発生していました。世界最大級の物流企業であるZTO Expressの場合、行フォーマットの非効率性とワークロード分離の悪さから、TiSpark用にかなり多くのTiKVリソースを確保しなければなりませんでした。パフォーマンスプロファイリングにより、TiKV上のTiSparkは、未使用の列に対して不必要なI/O帯域とCPUを消費していることがわかりました。さらに、ZTO Expressでは、リソースのピーク使用率を下げ、OLTPワークロードに十分な安全領域を確保するために、かなりの数のTiKVノードを追加する必要がありました。そうしないと、個々のパッケージに対する並列性の高いクエリがレポーティングに大きな影響を与え、パフォーマンスが不安定になるためです。
私たちは、スレッドプールやいくつかの「スマート」なスケジューリング技術を試しましたが、それらはリスクが高く、2つのワークロードを同じマシンに入れるほどの柔軟性はありませんでした。いくつかの実験に失敗した後、私たちはこれらの頭痛の種を軽減する特別なコンポーネントTiFlashを作りました。TiFlashは、TiKVのデータをカラムナ形式で複製する分散カラムナストアです。
TiFlashは今のものとは少し違っていました。TiFlashのプロトタイプは、オープンソースのソフトウェア定義ストレージプラットフォームであるCephの上に乗っており、データのレプリケーションチャネルとしてCDC (Change Data Capture) を使っていたのです。これは、オブジェクトストレージの上にSnowflakeが乗っているのと似ています。今でもオブジェクトストレージのサポートを追加しているので、これを「間違った決断」とまでは言いませんが、ほとんどのTiDBユーザーにとってアグレッシブすぎる決断だったようです。当時、彼らはオンプレミスのソリューションを好んでおり、我々の製品にCephを追加すると何かと面倒過ぎるのです。
いくつかのユーザートライアルに失敗した後、私たちはRaft learnerを元にしたデザインに目を向けました。TiFlashは、TiKVからRaftプロトコルを介してデータを複製し、投票権を持たない役割としました。ユーザーは、分析エンジンの実行とOLTPエンジンからの非同期レプリケーションのために、それぞれ別のマシンを割り当てることができます。Raftプロトコルを利用することで、TiFlashはレプリケーションの進捗状況やMVCC (マルチバージョン・コンカレンシー・コントロール) をチェックし、一貫したスナップショットの読み取りを行うことも可能でした。これにより、ワークロードを完全に分離することができたのです。
下の図は、TiKVとTiFlashのアーキテクチャを示しています。左下はTiFlashストレージ層、右下はTiKVストレージ層です。データはTiDBサーバーに書き込まれ、Raft学習プロトコルを介してTiKVからTiFlashに同期されました。非同期レプリケーションは、TiKVの通常のOLTPワークロードに影響を与えませんでした。

TiFalshとTiKVのアーキテクチャ
TiFlashは更新可能なカラムナーストアを備えていました。一般に、カラムナーストアは主キーに基づくオンライン更新には適していません。従来のデータウェアハウスやデータベースでは、1時間ごとや1日ごとのバッチ更新にしか対応していませんでした。この問題を解決するために、B+ツリーとログ構造マージ (LSM) ツリーを組み合わせたような新しい設計であるデルタツリーを導入しました。しかし、デルタツリーはB+ツリーよりも大きなリーフノードを持ち、LSMツリーの2倍のレイヤーを持っています。また、デルタツリーは、カラムエンジンを書き込み最適化領域と読み出し最適化領域に分割しています。

LSMツリーとデルタツリーの比較
TiFlashの登場により、TiDB 4.0は真のHTAPデータベースとなりました。HTAPの設計についてもっと知りたい方は、論文 TiDB: A Raft-based HTAP Database をぜひ読んでみてください。
スマートなMPP設計とさらにスマートなオプティマイザー
TiDBはTiDB 4.0でTiFlashを導入し、真のHTAPデータベースとなりましたが、まだ技術的な課題が残っていました。TiSparkはTiDBのエコシステムの中で唯一の分散クエリエンジンでしたが、中小規模のインタラクティブなケースには向かず、MRスタイルのシャッフルモデルはかなり重かったのです。そこで、MPPスタイルの分散フレームワークのネイティブ計算エンジンが必要になったのです。加えて、新機能の追加やコードの最適化を行うには、Sparkエンジンそのものを変更する必要があるという難点もありました。しかし、そんなことをすれば、アップストリームと同期するための負担が大きくなってしまいます。
激しい議論の末、TiDB 5.0ではMPPアーキテクチャを採用することにししました。この新しいアーキテクチャでは、TiFlashは単なるストレージノードではなく、完全に機能する分析エンジンとなるでしょう。TiDBサーバーはこれまで通りSQLの唯一の入り口であり、オプティマイザーはコストに基づいて最も効率的なクエリ実行プランを選択しますが、そこにもう1つ、MPPエンジンという選択肢が加わったのです。
TiDBのMPPモードでは、TiFlashがTiDBサーバーの演算能力を補完します。TiDBサーバーがOLAPワークロードを処理するときは、マスターノードとして後方に下がります。ユーザーがTiDBサーバーにリクエストを送ると、すべてのTiDBサーバーがテーブルの結合処理を行い、その結果をオプティマイザーに送信して意思決定します。オプティマイザは、すべての実行プラン (行ベース、列ベース、インデックス、シングルサーバエンジン、MPPエンジン) を評価し、最適なものを選択します。

TiDBのMPPモード
下図は、TiDBのMPPモードにおいて、分析エンジンがどのように実行計画を分解し、処理するのかを示しています。各点線枠は、ノードの物理的な境界を表しています。

MPPモードでのクエリ実行プラン
私たちのMPPフレームワークは、最初のバージョンですでにGreenplumのような従来の分析データベースのいくつかのTPC-H性能を上回りました。また、TiDBのユースケースを大きく広げ、2021年には、相当数の重要なHTAP顧客の獲得に貢献しました。昼夜を問わず顧客先に出向いたことが、TiDB 6.0におけるMPPアーキテクチャの確かな改良につながったのです。最後に搭載されたTiFlashエンジンは、急速に成熟していきました。
より速く (Citius) 、より高く (Altius) 、より強く (Fortius)
TiDB 5.0 では、より広範なアプリケーションシナリオに対応するため、MPP実行モードを備えたTiFlash分析エンジンの最初のバージョンが提供されました。TiDB 6.0では、TiFlash が以下をサポートするように、さらに改善されました。
- 演算子や関数の強化。TiDB 6.0の解析エンジンは、110以上の組み込み関数と複数のJOIN演算子を追加しました。さらに、MPPモードでは、ウィンドウ関数フレームワークとパーティションテーブルをサポートしています。このリリースは、TiDB解析エンジンのパフォーマンスを大幅に向上させ、計算の効率化に貢献します。
- 最適化されたスレッドモデル。以前のバージョンのTiDBでは、MPPモードでのスレッドリソース使用量をほぼ制限していませんでした。そのため、同時実効性の高いショートクエリを処理する際に、大量のリソースを浪費してしまうことがありました。また、複雑な計算を行う場合、MPPエンジンは多くのスレッドを占有し、パフォーマンスと安定性の問題につながっていました。この問題に対処するため、TiDB 6.0では柔軟なスレッドプールを導入し、演算子がスレッドを保持する方法を再構築しました。これにより、MPPモードでのリソース利用が最適化され、ショートクエリでは同じ計算資源で性能を倍増させ、負荷の高いのクエリでは信頼性を向上させることができました。
- さらに高効率なカラムエンジン。ストレージエンジンのファイル構造とI/Oモデルを調整することで、TiDB 6.0は異なるノード上のレプリカとファイルブロックにアクセスする計画を最適化するだけでなく、書き込み増幅とコード全体の効率も向上させました。お客様からのテスト結果によると、CPUを使用した読み書きの多いハイブリッドなワークロードにおいて、並行処理能力が50%から100%以上向上し、メモリリソースの使用量が劇的に削減されたことが確認されています。
今後の展望
HTAPデータベースの構築は長い道のりですが、私たちの努力は報われました。多くのTiDBユーザーが、より迅速な意思決定、より良いユーザー体験、そしてよりスピーディな市場投入のため、TiDBに搭載されたHTAP技術の恩恵を受けています。
ここまで来ても、まだ長い道のりがあります。実際、HTAPとは決して単なる技術用語ではなく、ユーザーのニーズを代弁したものでもあります。ごく初期のインメモリ技術から、今日の多様なデザインに至るまで、長年にわたって進化を続けているのです。例えば、SingleStoreは単一エンジンによる「古典的」なインメモリアーキテクチャを踏襲し、Oracle MySQL HeatWaveはインメモリが中心でエンジンを分離、TiDBとAlloyDBはディスクストレージを使用しワークロードを異なるリソースに分離しています。HTAPを開発している人たちは、それぞれ異なる設計上の決定を下していますが、1つの共通することは、ユーザーのニーズが最も重要であるということです。HTAPの設計は、ユーザーの問題をスマートに解決するために、これからも進化し続けるでしょう。ユーザーが抱える問題、例えばリアルタイムのデータモデリングや変換、クラウドインフラの活用など、まだまだ解決しなければならない課題が多くあります。
それでも、データベースの世界では、いずれHTAPデータベースが主流になると信じています。その日が来るまで、私たちは長い探検を続けていきます。
TiDBにご興味をお持ちの方は、ぜひSlackのコミュニティやTiDB Internalsにご参加いただき、ご意見をお聞かせください。また、最新情報はTwitter、LinkedIn、GitHubでフォローしてください。
こちらも併せてお読みください。
RetoolとTiDB Cloudを使って30分でリアルタイムカンバンを作る
より良いGitHubインサイトツールを1週間で作る?実話
HTAPの魅力:TiDBとAlloyDBの比較・分析
TiDB Cloud Dedicated
TiDB Cloudのエンタープライズ版。
専用VPC上に構築された専有DBaaSでAWSとGoogle Cloudで利用可能。
TiDB Cloud Serverless
TiDB Cloudのライト版。
TiDBの機能をフルマネージド環境で使用でき無料かつお客様の裁量で利用開始。