この記事は、Merpay Advent Calendar 2021の22日目の記事です。こんにちは、Merpay SREチームの@raviです。
DBaaSでは、さまざまなユーザー要件を満たすためにあらゆるcloudからソリューションが提供されています。 GoogleのCloud Spanner はGoogleのデータベースオプションで使用できるソリューションのひとつです。このリレーショナルデータベースでは、無制限のスケール、一貫性、99.99%の可用性(マルチリージョン設定では99.999%)を提供しており、Merpayにも適しています。
Cloud Spannerは特定数のノードを提供し、ユーザーデータはこれらのノード(またはプロセッシングユニット)間で分配されます。各ノードには特定の容量(2TB)があり、負荷に基づいてさまざまな容量のCPUを消費します。使用するデータサイズの増加に伴い、ノードやプロセッシングユニットをSpannerインスタンスに追加できます。
Merpayで使用するSpanner
しばらくCloud Spannerを使用してみると、突然トラフィックが増加するという問題が発生しました。Spannerへのクエリ数の急増は一部のmicroserviceに起因することもあれば、ユーザー操作の増加が直接の原因となることもあります。クエリ数が増えるとCPU使用率が非常に高くなり(推奨レベルの65%を超える)、クエリの速度が落ち始めます。これにより、microserviceのレイテンシが増加し、操作速度が落ちていることをユーザーが感じる場合があります。トラフィックの増加は、1時間未満で終了することもあれば、何時間も続く場合もあります。
CPU使用率増加により生じるレイテンシを解消するために推奨される方法としては、処理容量(ノード)数を追加してCloud Spannerの処理能力を増やしてあげることです。Merpayでは、すべての業務で主にTerraformを使用し、TerraformとGitHubの使用を通じてInfrastructure as Code(IaC)を実現しています。ただし、Spannerインスタンスの1つの処理容量を急に増やす必要が生じた場合、設定ファイルを変更し、承認後にプルリクエストのマージをするため、タスクとして時間がかかります。また、当然CPU使用率の増加は検出の必要があるため、CPU使用率が増加してアラートが生じた場合に処理能力の増加に対応できるよう、常に誰かが待機している必要があります。アラートを受信してから最終的に処理能力を増加させるまでにかかる全体のプロセスは、最短でも10分はかかります。Cloud Console(GUI)を使用すると少しは早くなりますが、IaCモデルからの乖離が生じます。
そのため、CPU使用率が特定の閾値に達した場合に自動でスケールアップの処理を実行する必要性があると感じました。Kubernetesのヘビーユーザーにとって、この要件はKubernetesのHorizontal Pod Autoscaler(HPA)と非常に似ているように見えると思います。Merpayのmicroserviceは全てコンテナ化されており、全てのデプロイと実行がKubernetes上で行われるため、HPAを使用して全てデプロイしているのと同様にCloud Spannerの処理能力をオートスケーリングするという考えはとても自然なものでした。
Spanner Autoscalerのはじまり
そこで、HPAと同様に機能しつつCloud SpannerのインスタンスをモニタしスケールしてくれるKubernetes operator のビルドに取りかかりました(kubebuilderを使用)。Spannerインスタンスのオートスケーリングを達成することによって、CPU使用率増加に伴う急激なレイテンシ上昇に対応するという課題を解決するだけでなく、未使用の処理ノードが削除されるためにコスト削減にも役立ちます。Spannerを積極的に使用しているユーザーであれば、処理ノードが追加されるごとにかなり大幅にSpannerインスタンスのコストが増加することを知っていると思います。そのため、レイテンシ増加を解決するためにノードを1つか2つ追加し、その後で削除するのを忘れてしまった場合、一月あたりのコストに大きな違いが生じてきます。
Spanner Autoscalerは社内のプロジェクトとして開始されたものですが、このソリューションは一般的に誰にでも使用してもらえるものではないかと思い、オープンソース化(mercari/spanner-autoscaler)しました。そして開発を続けました。
Merpayでは、オープンソーステクノロジーの使用を推奨しており、可能な限りオープンソースに積極的に貢献するように努めています。オープンソースのプロジェクトはGitHubのこちらから参照することができます。また、私たちは、GitHubのcloudsapnnerecosystemコミュニティで複数のプロジェクトに大きく貢献しています。例えば、yo、spanner-cli、wrenchなどです。
Spanner Autoscalerは完全にKuberentesネイティブであり、SpannerインスタンスのCPUメトリクスをモニタリングすることで機能しています。CPU使用率が特定の閾値に到達すると、CPUを閾値内に抑えるために追加すべきノード数を算出します。その後、必要な数のノードを追加し、Spannerインスタンスのモニタリングを続けます。同様に、Spannerインスタンスが過剰になった場合、一部の処理能力を削除してもCPU使用率が閾値内に収まるようであれば、Autoscalerは過剰なノードを削除します。
Kubernetesネイティブのソリューションであるため、既に広く知られているKustomizeや(知名度は少し下がるものの)kptを使用してk8sクラスターにインストールすることが可能です。インストール後は、カスタムリソースを作成することによって、さまざまなSpannerインスタンスをオートスケーリング用に設定できます。SpannerAutoscalerの一部リソースを以下に紹介します:
apiVersion: spanner.mercari.com/v1alpha1
kind: SpannerAutoscaler
metadata:
name: spannerautoscaler-sample
namespace: your-namespace
spec:
scaleTargetRef:
projectId: your-gcp-project-id
instanceId: your-spanner-instance-id
minNodes: 1
maxNodes: 4
targetCPUUtilization:
highPriority: 60
複数のSpannerインスタンスをオートスケールする際、これらの複数リソースを使用する方法を以下に概説します。
Spanner Autoscalerの機能
開発後もSpanner Autoscaler は改善を続けています。これを使用し、開発および本番環境において社内の数多くのSpannerインスタンスの処理能力を管理しています。また、初回バージョンではひとつの認証方法(GCP Service Account JSONキー)にしか対応していませんでしたが、今ではキーレス認証にも対応しています。
このAutoscalerの特筆すべき特徴の一部を紹介します。
- インストールが簡単:
Kustomizeおよび/または kptを使用すれば、いくつかのシンプルな手順を踏むだけであらゆるKubernetesクラスター上に簡単にインストールできます。インストールの方法はこちら。 - 操作が簡単:
Kubernetesのカスタムリソースを迅速かつ簡単に作成でき、あらゆるSpannerインスタンスの処理能力を管理できます。いくつかの例を こちらで参照できます。 - 最小限の手順でGCPのセットアップが可能:
必要なのは、GCPサービスアカウントを作成し、Spannerインスタンスの変更を許可するだけです。その後、AutoscalerはこのサービスアカウントのJSONキーを使用してノードの追加や削除を行います。詳細な手順はこちら。 - セキュリティ強化のための高度な認証方法:
さらに、キーレス認証方法を使用すると、セットアップがさらにセキュアに行えるようになります。GKEクラスター上にデプロイする場合、Autoscalerは Workload Identityと service account impersonation を使用できるようになります。これらの方法の詳細はこちら。 - オープンソース、柔軟性、拡張性:
オープンソースのソリューションであるため、コードの確認や変更を行うことができます。要件はこちらで参照できます: mercari/spanner-autoscaler。
[coming soon]スケーリングのスケジューリング:
場合によっては、オートスケーリングだけでは足りないことがあります。Merpayでは、Spannerデータベース上で一部のバッチ処理のジョブを実行することが多くありますが、これによってCPU使用率が上がり、ユーザーに影響するリクエストに問題が生じる場合があります。そこで今対応しているのがスケーリングを予定できる機能です。これによって、バッチ処理のジョブが始まる直前にSpannerインスタンスをスケールアップできるようになります。検討内容の一部はこのGitHub Issueで確認できます。
本番でのSpanner Autoscaler
Spanner Autoscalerは、本番インフラの障害回避にも役立っています。CPU使用率が増加し始めると速やかに稼働し、トラフィック増加を原因とするレイテンシ上昇によってアプリケーションが影響を受けるのを防止します。また、ユーザー数が時間と共に増加するのに伴い、処理能力を自動で徐々に増加させます。前述のとおり、処理能力の削除や追加を自動で行うことによって、インフラコストの削減にもつながっています。
トラフィック増加中のレイテンシ緩和
インシデント中にSpanner Autoscalerを使用した例を以下に紹介します。
こちらに示すとおり、CPU使用率が上昇すると、Spanner Autoscalerが処理能力を増やしてCPU使用率を閾値内に収めます。これにより、発生しているレイテンシ増加が緩和され、CPU使用率の上昇によって発生しうる新たなレイテンシ増加を回避するのに役立ちます。
夜間のダウンスケーリング
別のチームでは、Spanner Autoscalerを使用してコストを削減しつつ信頼性を向上させています。このチームがビルドしたmicroserviceは主に日中に使用されます。CPU使用率のターゲットは20%に設定し、CPU使用率の閾値を低く設定することによって、CPU使用率が大幅に増加したとしても容易に対応できるようにしました。そして、信頼性を向上させるために追加のコストは不要です。なぜなら、Spanner Autoscalerは余分なノードをトラフィックの少ない夜間に自動で削減するからです。
その様子は、以下のグラフを参照ください。
そのほかのSpanner Autoscalerとの比較
cloudspannerecosystem/autoscalerに記載のとおり、Spanner の処理能力のオートスケーリングには別のアプローチもあります。アーキテクチャからもわかるとおり、これはGCPのツールとソリューションに完全に依存するものです。
ただし、私たちは既にすべてのワークロードの実行にKubernetesを採用しているため、mercari/spanner-autoscalerはリコンサイルベースのアプローチで設計されており、IaCモデル(主にYAMLベース)に適しています。
kuberenetes以外の環境を使用しているユーザーの場合、Spannerインスタンスのオートスケール管理にはcloudspannerecosystem/autoscalerアプローチの使用が好まれるかもしれません。
Coming Soon
前述の機能紹介にも記載のとおり、リアルタイムスケーリングのほかに、現在はスケーリング機能のスケジューリング化にも積極的に取り組んでいます。これによって、ユーザーがあらかじめ設定した時刻でもSpannerインスタンスの処理能力を増加できるようになります。
MerpayではSpanner Autoscalerの開発を積極的に行っています。また、全てのSpannerインスタンスの処理能力を管理できるように導入を進めていく予定です。新しい要件やさらに改善できるポイントについて、私たちは継続的に取り組んでいきます。
ぜひmercari/spanner-autoscalerを試してみてください。フィードバックをお待ちしています!
参考
- https://github.com/mercari/spanner-autoscaler
- https://kubectl.docs.kubernetes.io/guides/introduction/kustomize/
- https://kpt.dev/
- https://cloud.google.com/spanner/docs/cpu-utilization
- https://cloud.google.com/spanner/docs/latency-guide
- https://cloud.google.com/blog/products/identity-security/enable-keyless-access-to-gcp-with-workload-identity-federation