ビデオ通話サーバのリアーキテクチャ

Koki Kitamura
MICIN Developers
Published in
Apr 20, 2022

初めまして、プラットフォームチームでアプリケーションエンジニアをしている北村 光毅です。最近、ビデオ通話周りのアーキテクチャを見直しました。本記事ではそのことについて紹介します。

背景

callregとは

オンライン診療サービス「curon(クロン)」、薬局向けサービス「curonお薬サポート」、MiROHA オンライン診療など、MICINの多くのプロダクトではビデオ通話機能が実装されています。同じ実装を各プロダクトで実装する必要がないように、ビデオ通話サーバとして切り出しています。MICIN内ではこのサーバをcallregと呼んでいます。

また、ビデオ通話のためのフロントエンドの社内パッケージも提供しています。これはcall-libと呼んでいます。

callregの役割

MICINのビデオ通話機能は外部のビデオ通話プロバイダを使っています。一方で、callregの担っている役割は次の通りです。

  • ビデオ通話プロバイダの接続に必要なクレデンシャルを発行する
  • ビデオ通話プロバイダごとの差異を吸収する
  • ビデオ通話プロバイダに無い機能を提供する

SFUサーバとシグナリングサーバを自前でホスティングした時期もありますが、端末と帯域幅によっては安定しませんでした。また、歴史的経緯でプロダクトごとに使っているビデオ通話プロバイダが異なります。ビデオ通話プロバイダに無い機能は次のようなものがあります。

  • ビデオ通話ルームに入る前に既にルームに参加しているユーザを取得
  • 通話中のリアルタイムチャット
  • ビデオ通話の入退室時刻の記録

これらはcallregで提供していきます。

なぜリアーキテクチャが必要なのか

callregをサーバとして切り出した頃は、社内でマイクロサービス化を検討し始めていた時期です。当時、開発していたモノリシックなアプリケーションサーバが肥大化していき徐々に開発工数が大きくなっていました。

マイクロサービスのコンポーネント図
マイクロサービスのコンポーネント図

その経緯もあってcallregはインターナルなマイクロサービスとして切り出しました。callregを運用していく内に課題感も見えてきました。

  • VPC間をAWS Transit GatewayやVPC Peeringで接続する必要がある
  • gRPCでサービス間通信の実装をする必要がある
  • callregのgRPCのインターフェース変更したら、プロダクトが側で対応してもらう必要がある

MICINではプロダクトと環境ごとにAWSアカウントを分けています。そのため、callregとインターナルな通信をする場合はVPCを跨ぐ必要があります。

ビデオ通話をoffer/anwser形式(call形式)からRoom形式に変更した際は、各プロダクトでやや大きめの改修をしてもらう必要がありました。

これらの課題を解決できないかアーキテクチャを見直します。

アーキテクチャの見直し

アプリケーションサーバで認証認可を行い、callregではビデオ通話プロバイダのサーバに繋ぎこむためのトークンを発行します。そのトークンをcall-libに渡します。そして、call-libがビデオ通話プロバイダのサーバに接続します。

赤枠がプラットフォームチームがメンテナンスするコンポーネントです。

現在のアーキテクチャ
現在のアーキテクチャ

アプリケーションサーバの役割は認証認可のみですが、アプリケーションサーバとcallreg間でVPCを跨いだ通信が行われています。

新しいアーキテクチャ

JWTを使うと認証認可のためのアプリケーションサーバとcallregのサーバ間通信を無くすことができます。JWTを有効期限内に失効させるためにはサーバ間通信が必要です。そのため、この方式によるトークンの失効は諦めて、JWTの有効期限を短くすることで代用します。

アーキテクチャは次のようになります。

新しいアーキテクチャ
新しいアーキテクチャ

インターナルなサーバ間通信がなくなり、アプリケーションサーバとcallregと疎結合になります。callregとcall-libはプラットフォームチームがメンテナンスしているので、比較的自由度高く変更を加えることができるようになりました。

課題は解決できるのか

JWTにより、サーバ間通信がなくなったので前述した課題は全て解決できます。

移行手順

古いアーキテクチャのcallregをプライベートなcallreg、新しいアーキテクチャのcallregをパブリックなcallregと呼ぶこととします。移行手順は次の流れて進めます。

  1. パブリックなcallregサーバをデプロイする
  2. 通信経路をパブリックなcallregに切り替える
  3. プライベートなcallregを削除する

1. パブリックなcallregをデプロイする

パブリックなcallregを新たにデプロイします。参照するデータベースはプライベートなcallregと同じです。この時点ではパブリックなcallregに通信は発生してないです。

移行段階1
移行段階1

正確には、アプリケーションサーバとパブリックなcallregはプライベートサブネットに属しており、それぞれのロードバランサがパブリックサブネットに属しています。

2. 通信をパブリックなcallregに切り替える

通信をパブリックなcallregを切り替えます。各プロダクトで別々のタイミングで問題ないです。

移行段階2
移行段階2

3. プライベートなcallregを削除する

プライベートなcallregへの通信がなくなったら削除します。

移行段階3
移行段階3

まとめ

最初に設計したアーキテクチャが今後常に最適であることはないはずです。運用していく中で新たな課題が出てきたり、プロダクトが成長して当初は適切であったが徐々に適切でなくなっていくこともあります。その時は投資対効果を考えてシステムをリアーキテクチャする必要があります。今回はその一例を紹介しました。

--

--