WHITEPLUS TechBlog

株式会社ホワイトプラスのエンジニアによる開発ブログです。

リアクティブシステムのケーススタディ

こんにちは。ホワイトプラスのエンジニアの古賀です。
私がシステム開発をする中で意識している(意識したい)考え方の一つに、リアクティブシステムというものがあります。
最近、設計について聞かれた時にこの考え方の話をする機会があり、改めて意識しキャッチアップしていきたいと感じたので、私の理解の範囲内でリアクティブシステムの概要について説明し、ケーススタディを通じて基本原則の実践方法を紹介したいと思います。

リアクティブシステムとは

2014年に発表されたリアクティブマニフェストの中で、昨今の高まるユーザ要求に応えられるシステムは、即応性(Responsive)、耐障害性(Resilient)、弾力性(Elastic)、メッセージ駆動(Message Driven)を備えており、この特性を備えたシステムを「リアクティブシステム」と呼ぶと定義されています。

  • 即応性(Responsive)
    • 常にユーザ要求を満たすレスポンスタイム以内に応答する(負荷増大や障害発生時であっても)。
  • 耐障害性(Resilient)
    • 障害が発生しても即応性を保ち続ける。
    • 障害をそれぞれのコンポーネントに封じ込め、コンポーネントを互いに隔離する。これによって、システムが部分的に故障してもシステム全体を危険に晒すことは無くなり、またコンポーネントのクライアントはコンポーネントの障害への対処に苦しめられることがなくなる。
  • 弾力性(Elastic)
    • ワークロードが変動しても即応性を保ち続ける。
    • システムの中に競合する場所や中心的なボトルネックが存在しないように設計し、シャーディングしたりレプリケーションしたコンポーネント間に入力を分散させる。
  • メッセージ駆動(Message Driven)
    • 非同期なメッセージパッシングに依ってコンポーネント間の境界を確立する。これによって疎結合性、隔離性などを保証する。

即応性は届けたい価値、弾力性・耐障害性は即応性を支える特性、メッセージ駆動は他の3つを支える手段、というような関係性です。
The Reactive Principles にもこれらの特性について記載されています。

ケーススタディ

既存システム全てに上記の設計原則を適用するのはかなり大変だと思いますが、部分的に適用し徐々に堅牢なシステムにしていくことは可能です。 弊社サービスである Lenet Cloak の出荷作業を例に挙げて、どのように適用できるかを考えてみたいと思います。

Lenet Cloak とは、お客様からお預かりした衣類をクリーニングした後、そのまま保管し好きなタイミングで1着から取り出せるサービスです。お客様から取り出し依頼を受けると、出荷作業を行います。

出荷作業は取り出し対象の衣類や出荷伝票の情報を読み込んだ後に出荷確定処理を行うもので、複数のサービス(1)にまたがってデータの登録・更新やお客様への通知が行われます。

このような出荷確定処理を同期処理することをまずは考えてみます。 出荷サービスが注文サービスや通知サービスを呼び出すという形です。

しかしここで、現場から出荷確定処理の応答速度は2秒以内にして欲しいという要件が出てきました(効率の良い現場作業をサポートするために応答速度の要件は結構出てくるものです)。さあどうしましょうか。

応答性を確保する

出荷確定処理で求められる応答速度を、注文サービスや通知サービスにも常に満たしてもらうよう調整することも選択肢としてありますが、パフォーマンスチューニングなどの課題が発生します。ここでは、出荷サービスだけでハンドリングする道を探ります。

出荷確定処理では、衣類の情報や出荷伝票の情報がリクエストに含まれており、これらのデータをチェックする事は必要ですが、データの登録・更新やお客様への通知は結果整合性を保てれば十分ということが分かりました。 そうした時に、非同期処理を使って以下のように処理を分けます。

出荷確定処理では、出荷確定に使った情報の検証とそれをドメインイベントとして記録することを行い、ユーザへ応答を返します。 次に登録したイベントを使って非同期的に後続処理を行うようにします。 これによって、出荷確定の中で行う処理を減らし応答速度を満たすハードルを下げる事ができました。

次に後続処理の方に目を向けてみます。

耐障害性を確保する

出荷情報の登録・注文情報の更新・お客様への通知という3つのサービスによる処理を同期的に行う場合、一部の処理が停止すると処理全体が停止してしまいます。 3つのサービスが強い一貫性をもって処理する必要があれば稼働率が下がっても同期処理にするメリットはありますが、上述の通り結果整合性が許容されているため、これらの処理は独立して実行できます。 Pub/Subモデルを使って、各サービスがイベント登録処理をサブスクライブするようにします。

こうすると、稼働しているサービスの処理は成功し後続に控えるデータ読み込み等の動作を正常に行うことができ、影響を停止しているサービスに封じ込めることができます。

リアクティブ原則はインフラとアプリケーションの一気通貫

これまでアプリケーションをメインにお話ししましたが、冒頭の4つの特性はアプリケーションとインフラの両面から見なければなりません。
先ほどの例で登場した非同期処理のメッセージング基盤で言うと、障害が発生した場合にどのようにメッセージ配信を担保するかなどです。 これは冗長化されたクラウドサービスを使うなどが手法として考えられます。

最後に

ホワイトプラスでは一緒に働く仲間を募集しています。 カジュアル面談もできますので、お気軽にご応募ください!


  1. リネットはモジュラーモノリス構成で、DDDの境界付けられたコンテキストでシステムをモジュール分割しており、モジュールをサービスと便宜上記載しています。