こんにちは。サーバー基盤グループでサーバーエンジニアをやっている尾山です。
コロプラ社の最新タイトルでは TiDB Cloud という分散型データベースをマスターデータの運用に使っています。TiDB Cloud とは PingCAP 社が提供する OSS、TiDB をベースとしたマネージドなデータベースサービスです。本記事は、その TiDB Cloud を選んだ理由を経緯と交えて紹介させていただきます。
経緯
弊社では TiDB Cloud を選択するまでに多くの紆余曲折があり、理由を説明するにはかなり昔まで遡って話をする必要があります。コロプラでは2017年頃までにリリースしたタイトルでは、全てのデータをGCEなどのIaaS上の MySQL で運営していました。元々はベンダーロックインを避けるためと、メンテナンスによるダウンタイムを作らないことを目的としてこの方法で運営していました。しかし、運営するタイトルが増え、Failover やスケーリングの対応が大変になったことを背景に、マネージドデータベースへ移行しました。
この時に採用したのが Google Cloud が提供する分散型データベースである Cloud Spanner でした。Cloud Spanner は非常に優秀で、WebUIから簡単にスケールアウトやスケールインできたり、メンテナンスによるダウンタイムがなかったりと、魅力的な機能が多く移行により運営は大幅に改善しました(Cloud Spanner については過去の勉強会で話しています)。しかし、Cloud Spanner は分散しやすいユーザーデータの運用には適していましたが、アクセスが分散しにくいマスターデータの運用においてはいくつか問題が発生しました。
まず、マスターデータは少ないデータに対して大量のアクセスが集中するアクセスパターンになりやすく、同じデータをレプリケーションして負荷を分散するのが好ましいのですが、 Cloud Spanner は 1つのノードにつき 1 leader 2 follower の構成になっており、1つのレコードを読み込めるノードは瞬間的に3台までとなってしまうため、1つのレコードに負荷がかかりすぎると処理を分散できず処理が詰まってしまうリスクがありました。
また、イベントや新機能追加時などには数万レコードのマスターデータを一括で更新する必要があるのですが、Cloud Spanner には 1トランザクションで 2万ミューテーション分しか更新できないという制限があり、それを超えてしまう場合、データを数回に分けてコミットすることになります。この場合、新しいデータと古いデータ混在するタイミングが発生してしまうため、親子関係があるデータは子を先に挿入したりなど、挿入順番に気を使わないといけないため、コストもリスクも高い運用になっていました。
そこで、これらの問題を解決するために、マスターデータの管理方法について見直すことになりました。まずはデータベースを変更せずにできる方法を模索しました。
処理が詰まってしまう問題に関しては、全てのテーブル定義に shard_number という int のカラムを追加し、異なる shard_number を付与した同じデータを複数個用意することで擬似的にレプリカがある状態を再現することで対応することも検討しましたが、アプリ側のコードに大幅な改修が必要になることと、ミューテーションの問題をさらに難しくしてしまうことから見送りました。
他にも細かい提案が多々ありましたが、やはりアクセスパターンが異なるデータにはそれに適したデータベースを用意するのが良いという結論になり、マスターデータを運用しやすいマネージドサービスを探すことになりました。
探すにあたって以下の要件を満たしてくれるマネージドサービスを探しました。
ここで真っ先に CloudSQL を使う案が出ました。Cloud SQL は GCP ネイティブなサービスなので運用が楽ですし、MySQL 互換、レプリケーション可能、一括更新が可能など、期待していた機能が揃っていました。しかし、Cloud SQL は我々のユースケースには合わない点がありました。
まず、CloudSQL はレプリカの追加は1台ずつしかできないという制限があり、突発的な高負荷時に一括で大量に追加したい場合に対応できないという問題がありました。また、CloudSQL にはメンテナンスが存在し、最大で 60秒ほどのダウンタイムがあり、コロプラでは原則ノーメンテナンスでの運営をしているので要件に合いませんでした。結果的にはこちらも運営が難しいという理由から採用に至りませんでした。
そこで、TiDB Cloud が候補に上がりました。TiDB も CloudSQL 同様、MySQLへの互換性やレプリケーション機能など最低限必要な機能が備わっていましたし、TiDB Cloud は Cloud Spanner のようにボタン一つでスケールアウトやスケールインできる機能も備わっていました。気になっていたメンテナンスは存在しましたが、検証してみた結果、short connection を使っていれば、多少のレイテンシーの増加がある程度(サービスの許容範囲内)で、ダウンタイムやエラーが発生することはありませんでした。また、TiDB Cloud にも Cloud Spanner 同様、トランザクションでコミットできる情報量に制限がありましたが、キーとバリューのデータ全体で 100MB 以内など、Cloud Spanner と比べると緩めで、運用するほとんどのデータは範囲内に収まる容量でした。
各サービスをまとめると以下のような表になります。
DB |
言語 |
メンテナンス時の |
Commit 制限 |
Replicas |
Cloud Spanner |
ZetaSQL |
あり |
20,000 mutations |
2で固定 |
CloudSQL |
なし |
143 MB 以内 |
最大 10 |
|
TiDB |
あり |
100 MB 以内 |
設定可能 |
こういう理由から TiDB Cloud はマスターデータの運用に適していると判断し、現在に至るまでのタイトルで使用されるようになりました。コロプラではすでにいくつかのサービスにおいて本番環境に導入しており、非常に安定した動作をしています。TiDB Cloud は技術的なサポートやアップデートがしっかりしており、今まで多くの提案やチューニングを提供していただいていて、サービスのユーザーとして非常に満足しています。また、TiDB には データの少ないテーブルをまるごとキャッシュしてパフォーマンスを上げる Cached Tables や負荷分散できる AUTO_INCREMENT 代替の AUTO_RANDOM など、他社にない機能が備わっているので、いずれそちらも運用に活かせたらと思っています。ちなみに、採用するにあたって TiDB にしかない一部の機能をlaravel プロジェクトで簡単に使えるように専用の Laravel のドライバーを作成し、OSSとして公開しています。もし興味があればスターをいただけると幸いです。
まとめ
この記事では我々がいかにマスターデータの運用で今まで試行錯誤し、データベースの制限を運営でカバーしてきたか、そしてそれを解決するためになぜ TiDB Cloud を選んだかを経緯を追って紹介しました。
今日の紹介はここまでとなりますが、この記事を通して少しでもコロプラのエンジニアリングに興味を持ってもらえたら幸いです。