チャットワークのScala移行と大規模メッセージDB再構築、本当にできたんですね!(前編)

2016年8月、トレタの増井雄一郎さん(「IT芸人」「フログラマー」で検索!)はPHPからScalaへの移行を表明していたChatWork CTOの山本正喜さんに「本当にScala化できるんですか?」と直球で聞きました(「PHPからScalaに乗り換えたチャットワークさん、その後どうですか?(前編)」)。そして2017年2月。「移行できたら、ぜひもう一回来てください」との誘いを受けて、再び増井さんがチャットワークにやってきました!

右から増井雄一郎氏(トレタCTO)、山本正喜氏(ChatWork 専務取締役 兼 CTO)、春日重俊氏(ChatWork 開発本部 本部長)

増井 Scala化、おめでとうございます!

山本 ありがとうございます。

増井 前回も聞きましたが、読んでない方もいるでしょうから、もう一度聞かせてください。Scalaを入れようと思った時期はいつなんでしょうか。

山本 そのあたりはBlog(「チャットワークがScalaを採用する理由、これからのチャレンジ。」)に書いたんですが、2年半前──合宿をしてScala化を決めたのが2014年4月です。宣言してからエンジニアを募集したので(笑)、プロジェクトは始まっていないんですけど。

増井 増井雄一郎氏(トレタCTO)

チャットワークをリリースしたのはいつでしたっけ?

山本 2011年3月です。

増井 じゃ、6年ぐらい前。PHPで作って3年ぐらい運用して、そこからPHPでは無理だと思ってScalaにするのに3年、みたいな感じで。

山本 作ってから3年ぐらいはがーっとやって。そうすると、規模が大きくなって技術的負債がたまってくるじゃないですか。

増井 今、トレタが3年を過ぎてコードの見通しの悪さが出てきたところですね。

山本 やばいな、コード肥大化してきたなという感じとか。障害時に疎結合になってないところがボトルネックになったりとか。

最初はPHPでリファクタリングしようと1年ぐらいがんばって、でも限界があるよねと。3年ぐらいで新世代のシステムを考え始めて。

増井 そのとき、PHPで何行ぐらいあったんですか?

山本 フレームワーク入れるかどうかはありますが、たぶん20万行ぐらいかな。

増井 実はトレタも今、同じぐらいなんです。規模が。人数も増えて見通しも悪くなるところです。

山本 エンジニアが20人規模で、コード規模もそれぐらいになると、なかなかカオスになってきますね。

増井 会社が順調に成長すると、だいたい創業3年〜4年ぐらい、遅くても5年ぐらいで開発体制を見直す時期になる。

山本 そうなんですよ。

増井 時代もあるじゃないですか。言語の流行り廃りで10年、20年のスパンがあって。5年にいっぺんぐらい、新しい言語の流行がある。Goが流行ったり、Scalaが流行ったり。

山本 フレームワークやライブラリだともっと早いですからね。

増井 するとみんな同じような問題を抱えることになる。

山本 4〜5年ぐらいで「変えたい」とエンジニアは言い出す。

年末リリースで万一の事態に備える

増井 Scalaを投入して動き始めたのは、いつからですか?

春日 昨年(2016年)の12月29日からです。

増井 おー、年末。

山本正喜氏(ChatWork 専務取締役 兼 CTO)

山本 年末、みんなで出社して。

増井 何かあってもお客様に迷惑がかからないように。うちでもそうすると思います。最悪「年末年始潰せばいいや」と。

山本 はい、潰したくはないんですけど(笑)。あと年末にしたのは、リリースした後も運用が怖いじゃないですか。

増井 切り替えた後に想定外のことはありましたか?

山本 リリース後の1カ月ぐらいは、毎週なにかしらトラブルが出て、緊急リリースを出していました。大きな影響というより、遅延がちょっと出たりとか。特定のメトリクス(指標)が跳ねてとか。

春日 今回は、裏側のインフラを(Dockerコンテナのクラスタを管理するツール)Kubernetesにがらっと変えているんですけど。サービスの特性上、日中にピークがあるのですが、その中でリリースしてコンテナ再起動して問題が出たり。

山本 Kubernetesの未知の運用上の問題が発生したり(笑)。

増井 負荷変動への対応ですが、トレタはオートスケーリングはしていないんです。時差があるところでも動いていますし、そこまで台数が多くないのでサーバー数を減らしたりするリスクと削減できるコストが釣り合わないので。

今回、Scala化したのは全部ではないんですよね。

山本 一番大きいメッセージまわりのデータベース中心のシステムを、別サービスとして切り出して、そこがScalaになってる感じですね。PHPでクライアントからのAPIリクエストを受けるんですけど、そこから内部的にメッセージングシステムに投げる。

増井 メッセージングDBみたいな感じですよね。

山本 そうです。Scala(のアプリケーション)をAPIで叩いて。裏側はCQRS(コマンドクエリ責任分離)アーキテクチャで組んでいるので、write(書き込み)のデータベースとread(読み出し)のデータベースが別なんですね。

writeのデータベースがKafka(注:LinkedInが開発してオープンソースで公開したPublish-Subscribeモデルのメッセージングシステム)になってるんですよ。Scalaで受けて、Kafkaにがーっといったん書き込むんです。

KafkaをsubscribeしているScalaの別のロールがあって、そいつがKafkaから読み出してHBase(注:オープンソースの列指向分散データベース、Facebook Messengerなど利用例がある)に書き込む。

増井 メッセージの本体は全部HBaseに入ってるんですか?

山本 いったんKafkaに書き込んで、HBaseにコピーする形ですね。

増井 MySQLとか、既存のデータベースも残っているんですか?

山本 既存のデータベースにdouble writeして並行運用しています。万が一、消えると怖いのでいざという時に切り戻せるように。一定期間後にHBaseのみにします。

増井 消えるといえば、GitLabが凄いことになりましたね(注:2017年2月1日、GitHubのクローン的な位置づけのリポジトリサービスGitLabで、ミスが重なりデータが失われる事故が起きた)。

山本 あれ、凄かったですね。復旧作業をライブ中継して。

増井 あの開き直りは新しいですよね。データの飛ばし方も、僕らが心の中で「やったら怖いな」と思うことを全部踏んでるじゃないですか。複数の手段でバックアップ取っていたはずが、全部取れてませんでした! と。

山本 豪快ですよね。あわててマスター消しちゃったみたいな。

「並列、非同期・・大変じゃないですか?」

増井 (アーキテクチャの図を見ながら)一回Kafkaクラスタに書いて、そいつがHBaseに……遅延とか難しくないですか? writeしてからreadできるようになるまで時間がかかるけど、チャットとかけっこうリアルタイム性が求められるから。

春日重俊氏(ChatWork 開発本部 本部長)

春日 自分たちだけでなく外部の有識者を交えて検討しました。Webフック(アプリケーション間で通知やデータを渡す手段)などの要望もあるので、イベントベースで伝搬させることを考えてKafkaを取り入れています。

増井 Kafkaは使ったことがないんですが、メッセージングサービスですよね?

山本 分散キューイングのシステムですね。

増井 キューの受け先の一つがScalaになってるんですね。場合によっては、さっき言ってたWebフックとか、別のクライアントがsubscribeしてもいいんですね。

春日 Kafkaは複数のクライアントからsubscribeして、同じキューを見れるので。

山本 Scalaのアクター(並行処理フレームワーク)を使っていて、遅延がないように高速にwriteしている。タイムラグはモニタリングしていて。

増井 遅延が起きても分かるように。

山本 そこは数十msとかですよね。

春日 現行と比べてもかなり高速な数字が出てます。

山本 HBaseにメッセージを書いてから、後処理があります。「書いたよ」とPHP側の受け口に送る。PHP側はそれを受けて、さらにAmazon Aurora(AWSのMySQL互換RDBサービス)にdouble writeで書き込む。各ルームごとのメッセージ数のような諸々のメタ情報もアップデートする。

増井 僕はHBaseは本格的に使ったことはないんですけど、難しい印象が。拡張していったときSQLデータベースに比べてどうなんでしょうか。

春日 バックエンドがAmazon Auroraだったんですけど、サービスで一番上のランクを使っていても限界で、もうフルマネージドサービスでは耐えきれないなと。寿命が見えていました。

一方、事業課題としてはサービスを拡張してAPIを公開していき、メッセージ数を爆発的に伸ばしたい。どれだけメッセージが増えても大丈夫な仕組みを作りたいとなると、やはり分散DBだと。すると、そんなに選択肢がなかった(笑)。

山本 スケールアウトできるデータベースというとKVSになっちゃう。CassandraとかHBaseとか。

増井 でもMySQLやAuroraでシャーディング(負荷分散)する方法ってありますよね。

山本 それはそれで茨の道なので(笑)。

増井 チャットだと組織単位がはっきりしてるじゃないですか。組織をまたいでメッセージを交換したり検索したりはないのでアクセスが局所化できてシャーディングが機能しやすいのでは。

山本 チャットワークは他のチャットと違って、ワンワールドなんです。組織と個人が区別されない世界観でC(コンシューマ)向けサービスみたいな作りなんです。なので、非常に割りにくい(アクセスを局所化しにくい)んです。

増井 そうなるとシャーディングはやりにくいですね。HBaseはAmazon EC2で動いているんですか?

春日 そうです。

増井 HBaseでためたデータは普通にAmazon EBSに入っている感じで。容量は必要だったら増やす、みたいなイメージですね。

春日 台数は6台でこなせてます。

増井 少ないですね!

春日 今支援していただいている方によればHBaseは1000台規模で動いている実績がある。しばらくの間は、データ量がどれだけ増えても大丈夫です。

増井 むしろ、困るぐらいにビジネスが伸びてほしいと。

山本 性能的には、RDBでやっていた頃に比べると4倍ぐらいスループットが出ています。

フロントエンド側を全面的に非同期処理に書き換え

増井 フロントエンド側は変わったのがユーザーからは分からない感じですか?

山本 分からないようがんばって工夫したという形です。今までのRDBだと強い一貫性があるので結果がすぐ反映されるんですけど、そうじゃなくて書き込んでもすぐには読み出せないデータベースに変わるので。

増井 非同期性がすごく上がりますよね。

山本 そうです。クライアントのJavaScriptやモバイルアプリも、それまではAPIを叩いたらすぐ結果が帰ってくるのを前提に組んでいたのを、全部非同期にしなきゃいけない。

増井 ブラウザからの通信はそもそも非同期ですが、それだけでなく命令の発行とデータの取得の間も別のリクエストになるので、コードが複雑になりますよね。

さっき遅延を気になった理由がそこで、writeでキューに入れる設計ってけっこう気軽に考えますけど、実装してみるとサーバサイドだけではなく、クライアントまで含めて影響範囲が大きくて難しいですよね。

春日 UXへの影響が大きいですね。

山本 なので、変えたのはメッセージだけなんですけど、クライアント側を全部巻き込んで巨大なプロジェクトになるんですよ。

増井 一番奥の部分のデータベースを変えているだけなんだけど、それを見せないようにフロントエンド側を変更する部分は大きいですね。

山本 けっこう、これ大変でした(笑)。今回のシステムは全部非同期APIなので。

増井 PHPは全部を同期で書けるので楽です。Scalaの導入で並列処理や非同期処理が増えると、大変になるのでは。ネットワーク障害に対してどう対応するかとか。

山本 分散コンピューティングの世界になってきますね。

増井 話としては萌えるんですけど、やれと言われるとやりたくない(笑)。

山本 テストどうするの、みたいな。

増井 JS側も、ブラウザやバージョンごとにサポートされてるAPIが違ったりしますけど、テストはいったいどうやっているんですか? ユーザーに分からないように差し替えるのってすごく難しいと思うんですが。

山本 実は本番運用のテストを2カ月ぐらい前からやっていました。2016年12月29日にリリースしたんですけど、その前の2016年11月から本番システムの裏側で新システムをステルスリリースの形で稼働させていました。本番相当の負荷がすでに入っていて。読み出しは既存システムのAuroraから。

春日 テストは(負荷テストツール)Gatlingを使って現行の数倍規模の負荷をかけて、いろいろなケースで叩いて、並行運用しながら実施しました。そこで初めてUX上の影響とか考慮漏れが分かる。

山本 あえて遅延するデータベースを用意したり。

春日 こちらが想定している通りのUXになっているかどうか。メンバー総動員でテストしました。

山本 もうひとつ、iOS版モバイルアプリは事前にAppStoreの申請をしないといけないので、そこが難しかったですね。

増井 あれは本当に辛いですね。最近は以前より早くリリースされるようになりましたが。

山本 アプリはWebと違って古いアプリを使い続ける人がいるので。大丈夫なようにかなり前からこれ対応のものを出してアップデートを促す形にしています。

増井 じゃiOSクライアントの古いバージョンは非互換になっているんですか?

山本 まだです。それは今年に入って、ある程度たった時期に。

増井 じゃAPIに新旧バージョンが?

山本 はい、クライアント側を新旧両方対応できるように改修しています。

増井 うち(トレタ)も3年前のクライアントを使っている人がいるんですよ。はじめのバージョンから使っていて一度もアップデートしていない人もいるんです。お客さんに新しいバージョンアップデートしたもらうのも一苦労ですよね。頑張ってください(笑)

【インタビュー後編はこちら:2年半を費やしたチャットワークのScala移行、もしやり直すならどうしますか?(後編)