Lernaは高い可用性とスループットを備えるシステムを構築するためのソフトウェアスタックです。クラウドを始めとするオープンな環境で高可用性システムを構築するため、障害は起こるものと捉えます。そしてLernaは、その影響をできる限り小さい範囲に留め、できる限り速く回復するよう設計されています(Design for failure)。また、高いスループットを実現するため、スケールアウトにより処理能力を向上させる弾力性を備えています。

Lernaの可用性と処理能力をベンチマークテストの結果から示します。

ベンチマークスコア

可用性を年間稼働率、処理能力をスループットと平均レスポンスタイムとして計測し以下の結果が得られました。

指標 計測結果
スループット 1,000TPS超※
平均レスポンスタイム 100ms以内
年間稼働率 99.9999%

※ スループットは 1秒あたりのトランザクション処理件数を示すTPS(Transaction per seconds)を指標とします。スケールアウトにより、さらなる上昇が見込めます。

前提条件

環境

Lernaの環境構築スクリプト(Terraform)を用いて、AWS上に以下の環境を構築しました。LernaはCQRS(コマンドクエリ責務分離)のアーキテクチャを採用しており、コマンドサイドにCassandra、クエリサイドにMariaDBと2種類のデータベースを使用します。

本ベンチマークテストでは負荷テストツールとしてGatlingを使用しました。Amazon EC2(以下、EC2)インスタンスの右上に示す数値は1,000TPSのテストを実施した際のインスタンス数です。

ユースケース

ベンチマークスコアは実装する処理により異なります。本ベンチマークテストでは決済のオーソリ業務をユースケースとして計測しました。本業務の要件として、最終的なデータ一貫性を維持する必要があります。例えば、同時に送信された決済リクエストを複数のデータセンターで処理することにより、残高がマイナスになることは許容できません。

各ベンチマークの計測方法と結果

スループット

本ベンチマークテストの目標スループットは1,000TPSとします。クライアント(Gatlingサーバー)から同時に1,000ユーザー相当の負荷を30分間与え続けた結果、すべてのリクエストに対して正常レスポンスを受信しました。

1秒あたりのレスポンス数とアクティブユーザー数

徐々にユーザー数を増やしていくランプアップ期間の後、常時秒間1,000レスポンスを受信していることから、秒間1,000トランザクションを処理していることが分かります。リクエストは売上と売上取消の2種類を本ユースケースにおいて想定される割合で送信しています。
※予め目標値を1,000TPSとしたため、それ以上の負荷を与えたテストは実施しておりません。アーキテクチャの特性上、スケールアウトすることでさらなるスループットの上昇が見込めます。

各EC2インスタンスのインスタンスタイプ、台数は次のとおりです。

ソフトウェア インスタンスタイプ EBSタイプ 台数
Keepalived c5.large gp2 2
HAProxy r5.xlarge gp2 3
Application(Akka) c5.4xlarge gp2 18
Cassanda r5.xlarge io2(3600iops) 18
MariaDB r5.xlarge io2(3600iops) 6

レスポンスタイム

クライアント(Gatlingサーバー)から同時に1,000ユーザー相当の負荷を30分間与え続けた際のレスポンスタイムを示します。

検証No 平均値 最小値 95%タイル※
1 87ms 35ms 133ms
2 93ms 34ms 141ms

※最小値から数えて95%に位置する値

2回計測し、いずれも100ms以下の結果が得られました。
検証No1のGatlingレポートを示します。

レスポンスタイム

平均レスポンスタイム(Mean)は87msとなっていることが分かります。

レスポンスタイムとアクティブユーザー数

年間稼働率

回復にかかる時間を障害発生箇所ごとに計測し、障害発生率と障害が発生したときの影響範囲を加味した上で年間障害停止時間を算出し、以下の数式で年間稼働率を求めます。

年間障害停止時間は以下の流れで算出します。

  1. Gatlingにて150TPS※の負荷をかけた状態で疑似障害を発生させ、レスポンスがエラーとなる時間を計測
  2. ネットワーク分断を含めた「単一障害時間」にサーバ台数と障害影響割合を掛けて、ユーザーが年間でサービスを利用できない時間を算出。サービス利用者のうち一人でも利用できない時間を単一障害時間とする
  3. さらに、年間障害発生回数(年間1回とする)を掛け、全障害発生箇所の停止時間をサマリーしたものを年間停止時間とする

※障害回復時間は150TPSの負荷状況で計測しました。その際の、各サーバー(EC2インスタンス)の台数は下表「サーバー台数」に示しています。

障害発生箇所ごとの回復するまでの停止時間

障害発生箇所 単一障害時間 サーバー台数 障害影響範囲 年間障害発生回数 停止時間
ロードバランサー(Keepalived) 2.78秒 1 1 1 2.78秒
ロードバランサー(HAProxy) 3.32秒 3 1/3 1 3.32秒
アプリケーション(Akka) 5.92秒 9 1/9 1 5.92秒
コマンドサイドDB(Cassandra) 0.00秒 6 1/6 1 0.00秒
クエリサイドDB(MariaDB) 1.14秒 6 1/6 1 1.14秒
AZ障害(ネットワーク分断) 8.02秒 1 1 8.02秒
年間停止時間 21.18秒

すべての障害において10秒以内で回復し、年間停止時間は21.18秒、年間稼働率は99.9999%となりました。アプリケーションレイヤの高速な障害回復は、「Akkaクラスタ」と、クラスタ上で常時エンティティを複製しおき障害が発生すると瞬時に切り替える「 akka-entity-replication 」により実現しています。

障害影響範囲について

Keepalivedの障害とAZ障害を除き、障害の影響範囲は障害の発生したサーバーが処理するリクエストに限定されます。例えば、9台のサーバーで構成するアプリケーションレイヤにおいて1台のサーバーが停止したとき、残りの8台が処理するリクエストは障害の影響を受けません。障害の影響を最小範囲に留め、影響を受けたユーザーのリクエストも僅か5.92秒後には別のサーバーで正常に処理されるようになっていることが分かります。また、障害が発生したノードは瞬時に切り離されるため、障害の影響が別レイヤに波及することはありませんでした。

Keepalivedはマスター・バックアップの構成を取るため、マスターが稼働するEC2インスタンスに障害が発生した場合は全ユーザーへ影響が及びます。Keepalivedのマスターが所属するAZに障害が発生した場合やネットワーク分断により当該AZとが孤立した場合も同様です。

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

Lernaはリアクティブシステムのアーキテクチャにインスパイアされています。リアクティブシステムは、メッセージ駆動のアーキテクチャによりユーザーの要求に可能な限り迅速にレスポンスするシステムです。高負荷状況や問題が検出された時でも応答時間を一定水準に保ち、部分的な障害が発生した時にもシステム全体を危険にさらすことなく回復させます 。 これらを、「即応性 (Responsive)」「弾力性 (Elastic)」「耐障害性 (Resilient)」「メッセージ駆動 (Message Driven)」という言葉で表現しています( リアクティブ宣言 参照)。

ユーザーの要求に可能な限り速やかに応答する「即応性」はレスポンスタイムが示し、ワークロードが変動しても即応性を保ち続ける「弾力性 (Elastic)」はスループットが示していると言えるでしょう。そして、障害に直面しても即応性を保ち続ける「耐障害性(レジリエンス)」は年間稼働率や個々の障害からの回復に要する時間が証明しています。

Lenaは、まさに「リアクティブシステム」の目指す世界観を具現化しています。その根幹にあるテクノロジーが、「メッセージ駆動」を実現する Akka と高速なフェイルオーバーを実現するライブラリ「 akka-entity-replication 」なのです。