kubell Creator's Note

ビジネスチャット「Chatwork」のエンジニアのブログです。

ビジネスチャット「Chatwork」のエンジニアのブログです。

読者になる

プロダクトオーナー目線でふりかえる大規模DBリプレイス

みなさんこんにちは、株式会社kubell(旧Chatwork株式会社)で エンジニアリング・マネージャー(まだ見習い)兼プロダクトオーナー(これも半人前)をやっております、辻(@crossroad0201)です。

この記事は弊社 kubell の Advent Calendar 2024 、12月20日の記事です。 こちらのアドベントカレンダーではエンジニアのみならず、プロダクトマネージャーやデザイナー、弊社のさまざまな職種のメンバーが記事を寄せていますので、ぜひほかの記事も見てみていただければと思います。

この記事では、私の所属チームが今年取り組んだ仕事の中でも最も規模が大きかった「メッセージDBリプレイスプロジェクト」についてふりかえりたいと思います。 技術的なことは後日エンジニアが記事を書いてくれるはず(!)なので、私からはプロダクトオーナー目線、プロジェクト運営の観点から見てみます。

自己紹介

最初にかるく自己紹介です。

あらためまして、kubell の辻です。 弊社は現在いくつかのグループ会社・事業本部がありますが、その中でもビジネスチャットサービス Chatwork の事業展開をしている「コミュニケーションプラットフォーム本部」で、主にバックエンドシステムの開発・運用保守を担当する部署のマネージャーをしています。

マネージャーと言ってもまだなりたてでして、それまでは Scalaエンジニア をやっていて、リアクティブシステムとかマイクロサービスとかドメイン駆動設計とか...そういうのが好物でございました。

年のせいか、以前ほど技術への思い入れが...と思っていたところで、プロダクトオーナーやら、マネージャーやらにチャレンジする機会が回ってきたので、キャリアの方向性を変えたと言うところです。(弊社はそういうキャリアチェンジができまっせ、と言う宣伝です)

プロジェクトについて

プロローグ

まずはこの記事で取り上げる「メッセージDBリプレイスプロジェクト」について、ざっくりご説明したいと思います。

Chatwork の技術記事をご覧いただいている方だと「お、あれかな?」とお気づきかもしれません。そうです、「Falcon」です。

Chatwork はビジネスチャットサービスですので、常に大量のメッセージ送受信があり、高い応答性と可用性が求められています。もともとPHP+RDBMSで作られていたメッセージ機能を事業拡大に対応させるために開発されたのが Falcon でした。

※Falcon についての詳細はこちらの記事を参照ください。 creators-note.chatwork.com

Falcon がローンチしたのが 2017年、アーキテクチャが優れていたこともあって約7年間も大きな改修を必要とすることもなく稼働し続けてきたのですが、そこにDBのEOL(=End of Life。サポート切れ)が迫っていました...

この問題に対処するため、私がプロダクトオーナーをしているチームで対応に乗り出したのです。

対象DB

Falcon は内部的に CQRS+ES なアーキテクチャを採用していますが、対象となったのはクエリ用のDB(いわゆる Read DB)です。 これには Apache HBase を採用していました。

AWS EC2 でセルフホスティングしてカリカリにチューニングされており、どんな遅いクエリでも2〜3msで結果を返すようなハイスペックなシロモノです。

また、Chatwork はローンチからすでに10年以上に渡り利用されてきているため、蓄積されているデータ量も約130億件となかなかのボリュームです。

EOLと対応方針

今回は、この HBase を動かしているOSがEOLを迎えました。

OSをバージョンアップするだけで済めば良かったのですが、互換性の問題から HBase もバージョンアップせざるを得なくなり、そうするとあれやこれや...と芋づる式にやることが出てきてしまい一筋縄ではいかないことがわかりました。 また、もともとセルフホスティングするのは運用負担も大きいと言う課題もあったので、この際、他のストレージにリプレイスすることにしたのです。

代替ストレージはいくつか候補を挙げて Pros. / Cons. を出して比較評価し、ランニングコストの試算や負荷検証なども行った結果、最終的に Amazon DynamoDB を選択しました。

この判断により、プロジェクトとしては

  • アクセスパターンを考慮したDynamoDB のスキーマ設計
  • Falcon を DynamoDB に対応させるための改修
  • 機能試験、負荷試験、その他スケーリングなどの試験
  • DynamoDB のキャパシティ割当てやバックアップなどの運用設計
  • 全データの HBase から DynamoDB への移行とその妥当性検証
  • ユーザー影響を考慮した本番のDB切り替え方法の検討とその実施
  • 不要になった HBase の廃止

といった作業を行うことになりました。

結果

プロジェクトのその後は...結果から申しますと、開始から約9ヶ月、無事に終わりました。 ユーザーさんから見れば何も違いはありませんが、Chatwork は新しいDBで動いています。

DynamoDB になったことで、(このDBに限っては)EOLからは開放されました。 また、結果的に、ではあるのですがランニングコストも大幅に圧縮することができました。

一方で、応答時間は実は若干悪化していて、2〜3ms だったのが 10ms くらいになっています。(後述)

ふりかえり

約9ヶ月、エンジニア7名で完了した当プロジェクトについて、プロジェクト運営目線でふりかえってみたいと思います。

Good

目的の明確化と必要十分な開発スコープ

まず無事にプロジェクトを終えられた要因として、必要以上の開発をしなかった、と言うことが挙げられます。

得てして、技術的課題に取り組む際は、いろいろな目的を入れ込んでしまいがちです。 なぜなら、一手であれもこれも解決してしまうことができれば、そのほうが全体的なコストを抑えることができ、合理的に思えるからだと思います。

しかしながら、それはなかなかに甘い罠です。 特に、一昔前の ステートレスなWebアプリケーションサーバー + RDBMS なシンプルなシステムならともかく、昨今の高い要求に適材適所で技術を組み合わせることが求められるシステムでは、一発で最適解を導き出すのは非常に難しく時間もコストもかかります。 結果、プロジェクト失敗のリスクも高くなってしまいます。

今回のプロジェクトのトリガーはEOL、すなわち対処しなければ最悪システムが動かなくなり、事業継続ができなくなります。 それだけは避けなければなりません。

よって、それ以外はすべてプロジェクトの必須条件から外しました。

応答時間を旧DB同等にすることは早々に諦め、ユーザーの操作感が悪化しない程度に収まれば許容するとしました。 また、ランニングコストも安くすることを目的とはせず、旧DBと同等程度であれば良しとしました。

AWS に詳しい方であれば、DynamoDB と聞けばキャッシュ機構である DAX を思いつくと思います。 DAXを導入すれば応答時間の悪化をより小さく抑えたり、さらなるランニングコストの圧縮もできると考えるでしょう。

しかし、それはあえてしませんでした。 "より良い"エンジニアリングを目指すのであればDAXを導入すべきでしょう。 ただ、今回のプロジェクトの目的はあくまでも事業継続であり、しかもチームにDAXの知見を持つエンジニアもいないし、DAXクラスタの運用設計なども考えれば、そこは不必要なエンジニアリングだと判断しました。

このように目的のために妥協できるところを妥協し、事業継続不可と言う最も避けなければならない事態に対処することに集中したことで、妥当な期間内にプロジェクトが完了できたと思います。

ロードマップによる現在地確認

今回は数ヶ月に及ぶプロジェクトでかつ不確実性の高いプロジェクトであったため、常に自分たちの現在地を確認し、先の見通しを立てておくことが重要だったと思います。

私のチームでは普段 Jira でタスク管理をしてますが、これだけではプロジェクト全体の工程がビジュアル(人間はビジュアルにモノゴトを理解する)に鳥瞰しづらいため、別途簡単なロードマップ図を描きました。

チームはスクラムで開発をしていますが、リファインメントやプランニングなどのスクラムイベントでは、「おさらいしますが〜」と毎回しつこいくらいに現在地と次に取り組むところを確認しました。 これにより、数ヶ月に及ぶプロジェクトでも迷子にならずに済んだのではないかと思います。

リスクヘッジのためのバックアッププラン

今回は事業継続に直結するプロジェクトであったため、万が一へのバックアッププランも立てていました。 つまり、EOLまでに対応に間に合わなかった場合に備えて、旧DBの延命処置をしました(弊社のインフラを預かるSREチームに依頼してやってもらいました)

実は、プロジェクトはEOLには間に合いませんでした。 しかしながら、バックアッププランを講じておいたことで落ち着いてプロジェクトを進め、完了させることができたと思います。

上述のロードマップを立てることで、何がプロジェクトのリスク・分岐点なのかを理解し、そこに対して先んじて手を打っておくことができたと思います。

助けを求め、集中を保つ

今回のプロジェクトは9ヶ月に及びましたが、その間、チームに他に仕事がなかったわけではありません。 他にも、ある程度規模の大きな作業や、会社の事業戦略的に重要な作業もありました。

しかし、このプロジェクトは非常に難易度が高く、かつ精密な仕事が要求される故に、チームの開発者の集中力を途切れさせるべきではないと考えました。

そこで、他の仕事はシャットアウトしました。 正直、今思えば稚拙なコミュニケーションだったとは思いますが、「自分たちはこれを終わらせるために、他の仕事はできない」と主張しました。 もしかすると、頑張ったら全部できたかもしれませんが、人間の集中力は程度の差こそあれ必ず低下すると思います。 そのリスクは取り得ない、そこを100%集中させることがプロダクトオーナーとしてやるべきことだと考えました。

結果、他のチームに負担を強いることにはなってしまい、感謝してもしきれませんが、事業としては最善の手、ベストを尽くしたと思っています。

Bad

後手に回ったEOL対応

正直、プロジェクト自体は自分自身も含めてチームとしてベストを尽くした自負はあるので悪い要素は思いつかないのですが、あるとすれば初動が遅れたことかもしれません。

今回のメッセージDBのEOLはかなり前から分かっていたことでしたが、他の緊急度の高い作業によって後手後手に回っていたように思います。 デッドラインの決まっている事案なので、(当たり前の話ではあるのですが)余裕を持って早め早めに計画的に対応していくことが、常に次の手の選択肢を多く持てることになると改めて思いました。

おわりに

文字ばっかりな記事になってしまいましたが、最後までお読みいただきありがとうございました。

詰まるところケースバイケース、その目的が何なのかを見極めて必要十分なモノづくりをする、それが事業としてのエンジニアリングなのではないかなと思う今日このごろです。