freeeの開発情報ポータルサイト

複数の検証環境でのDB相乗り化

この記事は freee 基盤チーム Advent Calendar 2023 の 22 日目の記事です。

こんにちは、freee のDBRE (Database Reliability Engineering) で ジャーマネ(マネージャー)としてDBRE組織を運営管理しているJuni です。 今回は何故integration環境*1を相乗り化してきたのかという話しをしていきたいと思います。

始まる前に、タイトルにも書いてある「DB相乗り」に関して一度定義していきましょう。 DB相乗りとは、複数の論理Databaseを1つの物理cluster内にまとめて乗せておく事です。

何故integration環境を相乗り化しようとしたのか?

freeeでのintegration環境は主にproductionへのリリースの前の機能テスト、QAなどで使われていまして、数十環境が構築されています。 それぞれの環境には、それぞれのサービス毎のDBが動いています。

この中で以下のような問題が台頭しました。

Aurora-clusterのhard limit問題

使っているAWSのaccountでAurora-clusterが構築できるカウント数がlimitにどんどん近ついてきて、AWSのサポートから不要のDBを削除したりする所を勧められました。

今現在productionのDBとintegration用のDBが同じaccount内で動いているため、沢山存在しているintegration用のDBを削除してリソースを確保していきたいという方針として定められました。 もちろん他のチームでaccountの分離も別途進められている所でしたが、DBREとしてできる処としてやはり不要なDBを削除していこうとしました。

各integration環境にdataをcopyする仕組みの改善、簡略化

productionのdbをcopyして、dataをmaskingする仕組みをfreee独自で構築して運用していますが、その運用コスト(maintenance、改修等)が高くて、この仕組みを簡略化したかったです。 様々な改善部分がある中で、一つポイントになってきたのはsnapshotから新たなDBをrestoreした後に中のdataをmaskingする処理時間がどんどん長くなってしまった点でした。 これの改善案として進んできた対策は、必要最低限のdataだけをproductionのDBから持ってくるような仕組み、そしてtestで使われるdataをseedとして作る対策でした。

data copyの流れ

基本的には、テスト用のデータをseedから生成する(railsでいうと、seed.rbの作成)ようにしていますが、productionからのテーブルを直接に持ってきてテストを行いたい場合には、必要とするテーブルだけをmaskingされたDBからcopyしてくるようにしています。

costの観点

costの観点からみても、効率的ではなくて無駄に多く作られているかと思いました。 多くの開発teamでの機能テストやQA テストのために各integration環境をそれぞれ構築し、非効率的に使われていました。 これを相乗り化する事でDB clusterの数を減らすと共にコストの削減効果も期待できると思いました。

DBの相乗り化での期待

DBの相乗り化を進める事で、以下のメリットが期待できます。

  1. 一つの環境にまとまる事で標準構成*2を使った運用ができる
  2. 1つの物理clusterだけを立てるのでコスト削減効果が期待できる
  3. 管理ポイントが一つにまとまるので運用管理がしやすくなる期待である
  4. 沢山のintegration用のclusterを消す事ができて、AWS accountのcluster hard limit対策になる
  5. Aurora Serverless v2, RDS proxyなどの新技術(新しい機能)をテストする環境として使える

このような期待感を持って、各自で動いているintegration環境を一つのDB clusterにまとめていく相乗り化を進めました。(以下、相乗り化したDB名を 「ainoridb」 と呼びます)

ainoridbの構成、特徴

ainoridbには以下のような特徴(メリットにもなる)がありまして、それぞれの特徴に関して軽く紹介していきます。

構成や設定をDBREの標準構成になる

ainoridbは基本的に前提条件がありまして、「integrationで動いているDBはDBREが定めている標準構成、設定に従う」という条件です。 この前提のよってほとんどのserviceをDBREの標準構成・設定に持っていけて、今後freeeの成長と共にDBがどんどん増えていても運用管理しやすくなると思いました。

DB分離の仕組み

万が一テストをする中で違う設定が必要な場合、そして特定のDBに負荷をかける事で他のDBにも影響がある場合のために、一時的な環境分離の仕組みも提供する予定です。

junidbで別の設定が必要な場合 - 作成
junidbで別の設定が必要な場合 - 削除

Aurora Serverless v2 導入

様々なapplicationのtestが業務時間内で行われているため、そのほかの時間はリソースを抑えておき、アクセスが集中される時には柔軟にリソースが増えるようにするため、Aurora Serverless v2を導入しました。

ACUの設定は、MINの所を0.5 ACUで設定しています。 以下のgraphでも確認できるように業務時間外にはちゃんと0.5 ACUまで収まってあり、コスト削減策にもできます。

ACUUtilization (1week)

RDS proxy

多くの場合、Railsプロセスは接続を維持しており、同時にqueryを実行しているわけではないため、任意の瞬間にほとんどの接続がidle状態になっています。ainoridbではRDS Proxyを使用して、すべての接続をデータベースへの実際の接続数を削減するようにproxyおよびMultiplexingしています。その結果、データベースのリソースがより効果的に利用される期待です。そして、applicationが増えてきてもapplicationからの接続数がDBのmax_connectionに至らないという期待を含めています。

RDS proxyの導入イメージ

コスト削減

例えば1つのintegration環境で20個のサービス用のDBが必要とし、それぞれのintegration環境が10個あるだけでも200DB clusterが必要とされます。これが一番小さいt3.smallで作られるとしても、

0.063 USD * 24 hours * 365 days * 200 DB cluster = 110, 376 USD = 15,783,768 Yen (1ドル143円計算)

計算になると思います。

Serverlessは他のProvisionedのインスタンスよりコストが高いと考えても大体10,000,000 yen (一千万円)のコスト削減になると思います。 これは実際のAWSでのコストだけ計算したものでして、運用管理のコストも含めるとより多くのコストが削減できるかと思います。

最後に

on-premise環境でのDB相乗りはリソース管理などの問題もあり、運用管理のコストが高くなってしまう場合もあったっと思いますが、AWS上ではこのように相乗り化をすることで、様々なメリットも考えられると思います。 integration環境での相乗り化が成熟してうまくいくとしたら、今後はproductionでのincubator環境*3として、小さいサービスや新規サービスのDBを集めて相乗り化する所も検討をしていきたいと思います。 是非、皆さんもこのような観点も認識していただけたらと思いまして、この記事を書きました。

明日は、Eijiさんからの記事になりますので、また期待していただけたらと思います。 どうもありがとうございます。

*1:integration環境は、各検証環境(A環境、B環境など)で動いているそれぞれのサービスのためのDatabaseを表しています

*2:標準構成というのは、DBREが決めたfreee内の標準のcluster構成、設定を言います

*3:incubator環境とは、新規サービスと共に新しく作られたDBを1clusterにまとめて相乗りする環境の事です