TiDB Cloudにおけるオートスケールの実現

DBRE (DataBase Reliability Engineering)チームの taka-h です。

2025年10月のTiDB User Dayにおいて、オートスケールについて取組み中(P. 81)であることをご紹介しました。この記事では、その後のオートスケールの取り組み状況についてお伝えします。

結論としては、2025年11月時点で、DBREが管理するTiDB移行済みの全クラスタでTiDBの水平方向オートスケール導入が完了し、その後も安定稼働しています。

次の画像は、メルカリ内のとあるCluster(l1-2)で、オートスケールがCPU利用率の平均値を60パーセント前後に保つように動作している様子を示したものです。

l1-2 Clusterでのオートスケール稼働の様子

なお、TiDB Cloudにはいくつかの製品ラインアップがありますが、本記事での以後のTiDB Cloudという言葉は、いわゆるサーバーレスではない「TiDB Cloud Dedicated」を指すものとします。

背景:なぜTiDB Cloudでオートスケールが必要だったか

メルカリでは、最初にTiDBのオートスケールの実装をすることを決め、初期の実装ターゲットをTiDBに絞ってオートスケールの導入を進めました。

まずはこの経緯を簡単に説明します。

実装決定に至った経緯

最初に既存のライブラリの実装状況を調査しました。

TiDBをKubernetes上でホスティングするためのライブラリとしては、tidb-operatorがあります。このライブラリでオートスケールが実装されていれば、我々が利用しているTiDBのマネージドサービスであるTiDB Cloudでもオートスケールが近々実現されることが想定されます。

オートスケール導入を検討した当時は、次の状況でした。

  • 当初実装されていたオートスケールの機能が削除されていた
  • TiDB Cloudの開発ロードマップにオートスケールの機能が入っていない

(最新の tidb-operator v2ではCRDのsub resourcesに対応しています)

また、TiDB Cloudは自動での水平/垂直のオートスケールの機能が提供されていない一方で、スケール変更についてAPIが提供されています。

https://docs.pingcap.com/tidbcloud/api/v1beta/#tag/Cluster/operation/UpdateCluster

APIがあれば、オートスケールは実現のための必要条件を満たすので、まずはオートスケールの実現のため実装を進めることとしました。

実装対象の選定

オートスケールの実装を決めた後、最初にオートスケール化の対象を決める必要があります。

メルカリにおけるTiDB Cloudのコストの構成としては、オートスケール導入前の時点で、大雑把にTiKVが6割程度、TiDBが2割程度でありました。TiKVが実データを持つのに対し、TiDBはステートレスでオートスケールに対する考慮事項が少なく、比較的容易に実現できますので、まずは実装対象をTiDBとし、要件を定義の上実装することにしました。

https://docs.pingcap.com/tidb/stable/tidb-architecture/

TiDBのアーキテクチャ

方針1:Kubernetes HPA活用, しかしマネージドサービス特有の壁があった (オートスケール v1)

実装範囲を決めた後、最初はKubernetes HPA(Horizontal Pod Autoscaler)を活用して実装する方針としました。ここではその最初の方針決定の経緯、そして方針変更に至った経緯を順に説明します。

要件を定義の上LLMで実装する予定でしたので、フルカスタム実装でもよかったのですが、主に、社内でElasticsearchのオートスケールが実現されていたため、これと同様にKubernetesのNativeのオートスケールの機能を活用して実現することに決定しました。

具体的には、実績があり安心できるという理由の他には、Kubernetes Nativeのオートスケールを利用すると、次の利点がありました。

  • 考慮すべき様々な一般的な考慮事項が既に満たされており、これを活用することでその実装が不要になり、開発すべき機能のスコープが絞られる
    • 例) スラッシング回避、一度に増減できるノード数上限、など
  • datadog経由のメトリクス連携を既存のオートスケールの機能でできる
    • クレデンシャルのセットアップなども追加で不要
  • 運用が他のKubenetesのものとそろう

既存のパターンとの違い: Podが管理するClusterに存在しない

既存のElasticsearchのオートスケールと今回のTiDB Cloudでは、前提条件が大きく異なります。既存のパターンは「自分たちが運用するKubernetesクラスタ上でPodが動いている」ことを前提に、HPAがPodのスケールを制御していました。

一方で、TiDB Cloudを利用する場合、実際のPodはTiDB Cloud上で動作しており、メルカリが管理するKubernetesクラスタ上には存在しません。このため、既存パターンと同様にHPAを適用しようとすると「スケール対象として参照できるPodがない」という問題に直面します。

そこで、TiDB Clusterを表すCustom Resourceを定義し、これをHPAのスケール対象として扱う方針で検討を進めました(次節で説明します)。

実際のPodがない対象へのHPA

ここでやりたかったのは、TiDB CloudのTiDBノード数変更を、KubernetesのHPAの仕組みに乗せて自動化することです。そのために、TiDB Clusterを表すCustom Resourceを定義し、HPAがそのreplicasを増減できる構成を検討しました。
しかし、HPAがCustom Resourceをスケール対象として扱うには、scale subresource/scale)を提供する必要があり、あわせて labelSelectorPath の定義が求められます。labelSelectorPath は、本来スケール対象に紐づくPod群を特定するための情報です。

https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#scale-subresource

TiDB Cloudでは該当Podが自クラスタに存在しないため、この前提を満たせず、通常の形ではHPAが成立しませんでした。一方で、External Metricsで AverageValue を使う場合に限り、結果的にselectorが評価に使われない挙動があり、labelSelectorPath をダミーにしても動作しました(ただし仕様保証がなく、運用上のリスクが残ります)。

https://docs.cloud.google.com/kubernetes-engine/docs/tutorials/autoscaling-metrics

: autoscaling/v1beta1(旧形式)
metrics:
- type: External
  external:
    metricName: pubsub.googleapis.com|subscription|num_undelivered_messages
    metricSelector:
      matchLabels:
        resource.labels.subscription_id: my-subscription
    targetAverageValue: "2"

: autoscaling/v2 (現行推奨)
metrics:
- type: External
  external:
    metric:
      name: pubsub.googleapis.com|subscription|num_undelivered_messages
      selector:
        matchLabels:
          resource.labels.subscription_id: my-subscription
    target:
      type: AverageValue
      averageValue: "2"

方針2: フルカスタムへ切り替え、運用可能な形へ収束 (オートスケール v2)

ステージング環境までは、何とかこの実装で動作はしたのですが、External Metrics連携が想定通りに動作せず、次の理由からCustom Resourceを定義し、reconcileのループを回すところだけ残し、その他をフルカスタム実装に切り替えることにしました。

  • Native HPAの機能を活用している既存の実装は、現状利用している特定のパターンが将来的に利用できなくなる可能性が払拭できない
  • デバッグが困難を極めた
  • LLMでオートスケールのような「よくある」実装が非常に容易になっている

フルカスタム実装に切替えてから、オートスケールで考慮すべき一般的な考慮事項についての学びを1つ1つ獲得しながら、下記の方針で、迅速にそして大きな問題なくオートスケールを導入完了できました。

  1. 最低限担保すべき範囲が明確になっており、そこが正確に実装できていること
  2. 想定外であった場合に、それを検知する実装/設計になっていること

つまり、当初は実装精度が十分ではなく、オートスケールの制御精度もやや低い状態でした。そこで初期は目標値を保守的に設定し、まずは一定のコスト削減を達成しました。あわせて、目標値との差分(猶予)を確保しつつ、想定外を検知できる仕組みを用意しました。そのうえで、運用しながら段階的に精度を高めていきました。精度が低い状態を許容するには、想定外の事態や異常の検知が十分に検討され、適切に実装されていることが前提になります。

最低限担保すべき範囲

オートスケールでは、ある指定されたメトリックが目標値になるようリソースを増減させます。
運用開始時に、この目標値に余裕を持たせる前提であれば、

  • 最小ノード数を一定以下にしないこと
  • 一度に可能な増減ノード数を制御できていること
  • ノード増減操作の連続操作に制約を与えること
    が期待通りに動作していれば、提供するサービス品質に影響が発生するということはないと考えました。

想定外を検知する実装/設計

最低限担保する範囲を厳密に守りながら、実装速度を優先し、運用中に改善を重ねていく前提で開発を進める方針でしたので、運用中の改善を許容するためには「異常な状態」をうまく検知できる必要があり、そのために必要なメトリクス/アラートについて、事前に多くの検討を行いました。

ここでの検討事項には、次の3つのポイントがありました。

1. 制御するパラメータに対する適切なアラート設計/設定

現時点ではCPU利用率を一定範囲にコントロールすることを目標にオートスケールを運用しています。当たり前ですが、利用率が低すぎれば、それはリソースが有効に活用できておらず、利用率が高すぎれば、サービスの提供品質に問題がでる、こういったことが起きない範囲にコントロールすることを目指します。

  • オートスケールでの制御目標値
  • 実際のアラートの閾値(Cluster/Node)

上記のような値を適切な上下関係に設定し、運用を行うこととしました。

CPU利用率の閾値の設定例

2. 依存関係のモニタリング

オートスケールが依存しているAPIの品質/問題に対して異常検知を行うことが重要であると考えました。今回は現状のメトリクスを把握するためのdatadogのAPI、そしてTiDB CloudのAPIが該当します。

例えば、APIレスポンスが遅くなったり、特定のエラーコードが一定以上発生したり、データ点が欠損したり、あるいは、変更操作を起こった際の所要時間が通常より長くなっていないか、などを観測する、といったことです。

メトリクス欠損の監視例

変更中状態の継続期間の監視

3. オートスケールの想定内・想定外の規定

オートスケールでは、ノードを追加したり、削除したり、変更操作を随時行っています。

一方で、あるノードの予期せぬ再起動、といったことも発生します。

外部から観測できるメトリクス(Clusterの状態や、NodeのUptimeなど)から、どのような状態/変化が想定通りか、あるいは想定外かを考え、規定しています。

これらを可能にした周辺改善

オートスケールは、当たり前のように実施しなければならない項目ではありますが、それを実現するために、メルカリ社そしてTiDB Cloudの提供元であるPingCAP社の様々な改善がありました。

一番大きなものは、TiDB CloudのTiDBのスケール操作(スケールアップ/スケールダウン/スケールイン)がgracefulではなかった点を、メルカリ/PingCAP社で改善したことです(TiDB User Day 2025 P.36~)。

そして、TiDB CloudのdatadogのCPUメトリクスの値の信頼性が十分でなく、オートスケールなどに利用するのが難しい、といった問題への対処、また、オートスケールをAPIで実施する際の権限制御の改善、などがありました。

度重なる要望に対して、改善を積み重ねていただいたPingCAP社には改めて感謝します。

今後: TiKVへの展開の難しさと次の一手

現在、より大きなコスト割合を占めるTiKVのスケーリングに取り組んでいます。

TiKVはデータを保持するため、これを水平スケールする際には、データの偏りをなくすためのリバランスが必要です。水平スケールの戦略を取るためには、スケールインの際には削除対象のノードのすべてのデータを他のノードに移動してからではないと、ノードを削除できません。

現在、「1日の中で負荷が上下し、TiKVで必要なリソースが変化するので、これに最適なリソースにし、コストを抑制しながら必要なリソースを必要なだけ確保したい」という要望があります。データのリバランスは、既存のノードの性能にも影響を与える可能性があり、そのため一般的にはその速度がある程度抑制されています。水平スケールに求めるスケール速度が、このような1日の中でノードを増減する必要がある、という場合においてスケールインは不向きであるといえるでしょう。また、逆にもう少し長いスパンでのスケールの自動追従であれば、コストに対するインパクトがそこまでないため実現の重要性は下がるでしょう。

これに対して、リバランスの速度を調整する、という選択肢も考えられます。しかし、現状ではTiDBではこのリバランスの設定を含む、TiKVの設定変更に対してAPIが提供されておらず、現状取りうる手段は、サポートチケット経由での設定の変更依頼となります。

そこで、まずは垂直スケールの機能の導入を目指しています。

TiKVの垂直スケールにおけるメモリ有効活用

今後も追加で様々な課題が見つかるかとは思いますが、現状、大きなインスタンスクラスでTiKVを運用した場合、メモリを有効活用できない課題がありましたので、それを解決しています。

MySQLやその他のデータストアや、システムでもよくある問題ですが、データベースをホストしているノードの安定稼働のために、データベース以外、あるいは主に利用するリソース以外で利用するリソースを一定割合確保するため、主に利用するメモリの利用率を保守的に設定することがあります。

TiDBにおいては、TiKVのblock_cache.capacity, memory_usage_limitといった設定が主に積極的に活用したいリソースでありますが、現状のTiKVの実装状況で発生している拘束条件として、これらのパラメータについては、初期値は固定の割合で指定されるものの、初期値ではない値に変更する場合に、利用するメモリ利用量を数値で指定する必要がありました。

https://docs.pingcap.com/tidb/stable/tikv-configuration-file/#memory-usage-limit

https://docs.pingcap.com/tidb/stable/tikv-configuration-file/#capacity

block-cache.capacityのドキュメント

先述の通り、TiDB Cloudではこれらの設定を変更するAPIもありませんので、メモリを有効活用するためにメモリ利用量を、値を指定して変更する場合、現状サポートチケット経由で変更依頼が必要です。この状況では、負荷に合わせて自動で垂直スケールしたい、といった場合に、サポートチケット経由での変更が必要になり、人の手の介入が発生するため、結果として適切にメモリ利用量を自動で追従させられません。

すなわち、TiKVを大きなインスタンスクラスで運用した場合、メモリが余剰しリソースを有効活用できない、という問題がありました。具体的にはblock-cache.capacityのデフォルト値の45%に近い、50%前後までしか、メモリを活用できませんでした。

そこで、TiKVのメモリを割合で指定し、大きなインスタンスタンスクラスで運用する場合に、これを大きな値に設定することができるように修正しました。この修正はmasterブランチにマージ済みで、次のマイナーバージョンである8.5.7で利用可能になる見込みです。

https://github.com/tikv/tikv/pull/19419

まとめ

メルカリではTiDB Cloudを運用しており、負荷に合わせTiDBの水平方向のオートスケールを安定的に運用しています。これにより、TiDBの50%前後のコストが削減されました(トータルでは、全体の2割の約半分、の削減効果)。

既存のKubernetesのNativeの機能を活用する方針で初期の検討を始め、ステージング環境までも動作させたものの、LLMにて再実装を行ったこと、また、LLMでの実装については、

  1. 最低限担保すべき範囲が明確になっており、そこが正確に実装できていること
  2. 想定外であった場合に、それを検知する実装/設計になっていること

を基本方針として迅速に実装を完了させたこと、

一見当たり前のようにみえる、オートスケールの実現自体には、実はとても大変な基礎的な改善の数々があること、また、最後にTiKVの垂直スケールでメモリを有効活用するため、修正をコントリビュートしていること、をお伝えしました。

最後に、現在メルカリでは、この記事の発行者の所属する DBREチーム の EM(Engineering Manager) を募集しています。詳しくはこちらをご覧ください。

  • X
  • Facebook
  • linkedin
  • このエントリーをはてなブックマークに追加