kubell Creator's Note

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

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

読者になる

Chatwork の Scala プロダクトとそれを支えるチーム その壱

これは Chatwork Advent Calendar 2020 / Scala Advent Calendar 2020 10日目 の記事になります。

こんにちは。サーバーサイド開発部の Scala プロダクトを開発運用する部署でマネージャーをしている、 hayasshi です。

Chatwork は Scala を採用すると決めてから、約 6 年経ちました。
その中で、失敗もしながら、少しずつ Scala のシステム領域を広げてきました。

今回と次回の二記事にて、この 6 年で開発し、いま実際に稼働運用されている、 Chatwork の Scala プロダクトの紹介と、それを普段どのように開発運用しているかについて、書きたいと思います。

Scala プロダクトの紹介

今回は Chatwork の Scala プロダクトについてご紹介します。

特に下記の項目についてそれぞれ記載したいと思います。

  • どのような役割を持ったシステムか
  • 利用されている技術(ミドルウェア、ライブラリ)

プロダクトによっては構成図も交えながらご説明したいと思います。

Chatwork の Scala プロダクトは、そのほとんどが Kubernetes 上でコンテナとして動作しています。
Kubernetes に関する記事も別途ありますので、今回はその説明は割愛します。

また Chatwork では、プロジェクトにコードネームをつける慣習があり、プロダクトもその愛称で呼ばれることが多いので、ここでは社内でよく呼ばれる愛称でご紹介します。

Falcon

どのような役割を持ったシステムか

Falcon は、Chatwork にスケーラブルなメッセージの読み書きを提供する、メッセージシステムです。

メッセージ投稿や読み出しの際、事前条件(権限やチャットルームへの参加有無など)チェックをしたあとで、メッセージを永続化するために呼び出します。

呼び出しは HTTP ベースでおこない、書き込み(投稿や編集)リクエストが受け付けられ実際に永続化されるまでは非同期に処理されます。

構成図
Falcon 構成図

※ チャットログエクスポート機能のためのコンポーネントもいくつかありますが、今回は省略しています

書き込みリクエストを、イベントとして Kafka に一旦キューイングし、それをベースに処理することで、スケーラビリティとイベントベースなシステムの柔軟性を獲得することができました。

このあたりのことは、Chatwork でも何度か発信をしていますので、より詳細を知りたい方は是非下記の資料もお読みいただければと思います。

利用されている技術(ミドルウェア、ライブラリ)

ミドルウェア:HBase、Kafka
ライブラリ:Akka、AkkaHTTP、AkkaStreams、KafkaStreams、Circeなど

Webhook

どのような役割を持ったシステムか

Chatwork で発生したイベントを、設定された条件に従い、外部へ HTTP リクエストを用いて通知する、いわゆる Outgoing WebHook をおこなうシステムになります。
(社内では Webhook と一語で表現する事が多いです)

Falcon で扱えるようになったメッセージイベントを筆頭に、Kafka を利用したストリーム処理を中心にしたシステム構成になっています。

構成図
Webhook 構成図

Kafka の at least once delivery の特性を活かし、極力ロストしないようにする代わりに、重複して実行される可能性があるというのは、達成すべき非機能要件の観点から WebHook を取り扱うシステムと非常に相性が良いと感じています。

利用されている技術(ミドルウェア、ライブラリ)

ミドルウェア:Kafka、AWS Aurora
ライブラリ:AkkaStreams、Alpakka Kafka、AkkaHTTP、ScalikeJDBC、Scalaz、Circeなど

Astraea

どのような役割を持ったシステムか

RFC6749 に準拠した認可APIサーバーを、フルスクラッチで構築したものになります。

Webhook と同時期に構築されたもので、サードパーティのサービス提供者が、ユーザーの同意のもと、安全に Chatwork API にアクセスするためのトークンを発行する仕組みを担います。

RFC6749 を準拠する認可処理のモデリングをおこない、堅牢に構築されています。

Astraea をつかった Chatwork の OAuth に関するブログもいくつかありますので、詳細を知りたい方は下記もご覧ください。
Chatwork Creator's Note > Category > OAuth

利用されている技術(ミドルウェア、ライブラリ)

ミドルウェア:Amazon Aurora、Amazon ElastiCache、Amazon SQS、Amazon S3
ライブラリ:AkkaHTTP、AkkaStreams、Slick、Cats、Circeなど

Synapse

どのような役割を持ったシステムか

外部サービスと Chatwork API の間に立ち、それぞれのインターフェースを吸収して接続する、連携のためのハブ・アプリケーションです。

例えば Chatwork では、IFTTT の Service を提供していますが、IFTTT 側の要求するインターフェースを Synapse に実装し、Chatwork API に連携しています。

このような「他のサービスの都合による実装」を、リソースサーバーから分離、疎結合にすることで、コアプロダクトの肥大化やコアドメインへの集中を維持する目的で作成しました。

利用されている技術(ミドルウェア、ライブラリ)

ミドルウェア:Amazon ElastiCache、Amazon S3
ライブラリ:AkkaHTTP(server + client)、Cats、Circeなど

Reaction

どのような役割を持ったシステムか

その名の通り、リアクションデータを永続化するためのシステムです。

Falcon と同様、事前条件(権限やチャットルームへの参加有無など)チェックをしたあとで、呼び出されます。

これまでの HTTP リクエストを受け付けるアプリケーションでは、Akka を主軸にした実装でしたが、このプロダクトでは、HTTP ルーティングこそ AkkaHTTP ですが、そこから先は Monix を用いたモナドベースでのユースケース実装をしています。

当時の開発プロジェクトでおこなわれたこと(PoC、技術選定、負荷試験など)を紹介した資料もありますので、別途詳細を見たい方は、下記も合わせてご覧ください。
Chatworkでリアクション機能をリリースした話

利用されている技術(ミドルウェア、ライブラリ)

ミドルウェア:Amazon DynamoDB
ライブラリ:AkkaHTTP、Monix(Task)、Cats、Circeなど

Biryani

どのような役割を持ったシステムか

メッセージ検索インデックスを作成するアプリケーションです。

Falcon のメッセージイベントを、Amazon Elasticsearch Service にインデックスを作成するストリーム処理をおこないます。

構文解析こそ Elasticsearch にお任せしていますが、メッセージの言語判定はアプリケーション内部でおこなっています。

Chatwork の複雑になっていた検索インデックス作成処理を見直し、時間短縮、コスト削減をおこなったスゴイやつです。

そのプロジェクトの詳細は、当時のプロジェクトメンバーがブログにまとめていますので、下記も合わせてご覧ください。
Chatwork Creator's Note > Category > Elasticsearch

利用されている技術(ミドルウェア、ライブラリ)

ミドルウェア:Kafka、Amazon Elasticsearch Service
ライブラリ:AkkaStreams、Alpakka Kafka、Elasticsearch Client、Circeなど

LinkPreview

どのような役割を持ったシステムか

Chatwork のタイムラインに表示されている URL プレビューの情報を取得するためのものです。

Chatwork は読み込みの要求が大きい(read heavy)ので、キャッシュをうまく取り扱い、かつ柔軟にスケールしやすい単機能なものということで、CloudFront + AWS Lambda を採用した、サーバーサイド開発部 Scala 初のサーバーレスアプリケーションになりました。

構成図
LinkPreview 構成図

実は、JVM のスピンアップの遅さに対応するため、GraalVM Native Image ツールをつかい、ネイティブアプリケーションとして AWS Lambda で動かしています。

その他にも、URL 先に多大な負荷を与えないためのスロットリングの仕組みや、同じ URL に対する同時実行数の抑制をおこなう仕組みなどを実装し、システムをコントロールしています。

利用されている技術(ミドルウェア、ライブラリ)

インフラ:Amazon CloudFront、Amazon API Gateway、AWS Lambda
ミドルウェア:Amazon DynamoDB
ライブラリ:AWS SDK、Akka、scalaj-http など

Pegasus

どのような役割を持ったシステムか

Falcon にしろ Reaction にしろ、これまでの Chatwork のコアドメイン(チャット)に関する機能は、Scala プロダクトとしては永続化層として扱われてきました。
現行システム側のドメインロジックを通った上で、Scala プロダクトが呼び出されるというようなパターンです。

このままでは Scala プロダクトにロジックがたまらず、新規機能開発や改善をおこなう際に、かならず現行システムのメンバーが必要になってしまいます。

このプロダクトは、そうせざるを得なかった問題に対して、回避も含めた対応をおこない、Scala プロダクト単独で機能追加を可能にすることを目的に開発されました。

直接リクエストを受け、ビジネスロジックを書くことができるようになったことで、例えば Reaction など、本来 Chatwork のコアドメインとしてまとまっておくべき機能を統合するなどし、システム全体をシンプルにしていく取り組みもおこなえるようになりました。

利用されている技術(ミドルウェア、ライブラリ)

ミドルウェア:Amazon Aurora、Amazon DynamoDB、Amazon SQS など
ライブラリ:AkkaHTTP、Slick、Circe など


以上が、現在稼働している Scala プロダクトの紹介になります。

さいごに

私自身、入社 5 年が経ち、振り返ると様々な開発をおこなってきました。

最初の方は開発することに意識が先行し、開発したプロダクトの運用について十分に検討ができていなかったり、チームが維持できなかったりと度々問題課題と対峙してきました。

最近はようやく、開発と運用を一緒におこなっていくチームができ、これまでの反省を活かしながらシステムやアーキテクチャの設計をおこなっています。

このプロダクト紹介を見て、「技術的な詳細が知りたい!」「こうなった経緯や課題問題を深く聞きたい!」「コードネームの由来を聞いてみたい!」と思われた方、ぜひぜひカジュアルにお話させていただければと思いますので、下記からお問い合わせください!

www.wantedly.com

次回は、このチームでおこなっている開発について書きたいと思います。