コーポレートサイトの可用性、拡張性をさらに高める方法の一つとして、「疎結合」が挙げられます。ここでいう疎結合とは、複雑なシステムを互いに過度に依存し合わないシンプルなコンポーネントに分割することです。疎結合にすることで、各コンポーネントが拡張しやすくなったり、耐障害性を高めたりすることができます。

 実はこれまでに強化してきたコーポレートサイトでも、ELB(Elastic Load Balancing)によってWeb・APサーバーを疎結合化しています。Web・APサーバーの1台に障害が発生したとき、ELBが検知してそのサーバーにトラフィックを流さないようにして、システム全体として処理を継続します。

 スケーリングでは、Web・APサーバーの仮想マシンを新規作成してELBに登録するだけです。その際、DNS(Domain Name System)のレコードはELBを参照するようにしておくことで、設定変更の必要がなくなります。DNSサーバーに登録するのはELBの情報だけ。Web・APサーバーを登録する必要はありません。

 ELBが無いとDNSサーバーに全てのWeb・APサーバーの情報を登録する必要があり、仮想マシンの追加や故障のたびにDNSレコードを更新しなければなりません。

 疎結合はメインフレーム全盛の時代から脈々と続いてきた考え方ですが、AWSをはじめとするパブリッククラウドではELBのようなサービスによって疎結合化を進めやすくなっています。

 ここでは、疎結合化を進めるうえでカギとなるAWSのサービスとして、メッセージキューイングの「Amazon SQS(Simple Queue Service)」とプッシュ配信の「Amazon SNS(Simple Notification Service)」を取り上げます。

キューでRDBの負荷急増を回避する

 メッセージキューイングはメインフレームの時代からある概念で「MQ(エムキュー)」と略されます。二つのコンポーネントがメッセージをやり取りする際に、メッセージを格納するキューを介する仕組みです。送信側はキューにメッセージを送り、受信側はキューに問い合わせて受け取ります。この仕組みにより、システム全体の可用性と拡張性を高めます。

 例えば、コーポレートサイトで人気のある景品を時間限定でプレゼントするとします。申し込みのアクセスが殺到すると、リレーショナルデータベース(RDB)の性能によっては負荷に耐えられなくなります。

 このときMQを使うと、キューがメッセージ(ユーザーからのリクエスト)のバッファーになります。キューはメッセージを並行して受信しためていき、受信側はキューにたまったメッセージを順次取り出して処理しRDBにアクセスするので、負荷が平準化されます。受信側が一時的に停止しても、メッセージはキューにたまっており、復旧したとき処理を再開できる利点もあります。

 ここまでの説明で、キューに障害が起きるとシステム停止やデータ消失につながるのでは、と思ったかもしれません。その考えは正しく、オンプレミス(自社所有)環境ではキューの可用性やサイジングを管理する必要がありました。

 これに対してAWSでは、Amazon SQSというMQのサービスを提供しています。マネージドサービスで、サイジングや運用管理の大部分をAWSが行います。

 なお2017年11月に「Amazon MQ」というMQの新サービスが登場しました。「Apache ActiveMQ」というオープンソースソフトをベースにしており、対応プロトコルが多く、オンプレミス環境から移行しやすいという特徴があります。

 ここでは利用実績の多いSQSに絞って説明します。

SQSは自動的にスケールアウトし性能を維持

 SQSでは、サイジングや運用管理の大部分をAWSが行うと説明しました。具体的には、メッセージを複数のデータセンターに冗長化して保存するので、メッセージが消失する心配はほとんどありません。容量が無制限で、数百万件といったメッセージでもキューに保存できます。処理性能についても、分散キューという仕組みで自動的にスケールアウトし、高いスループットを維持します。

 料金は、毎月100万件のリクエストまでは無料で、それ以降は使った分だけの従量課金です。

 SQSを利用するのは簡単です。マネジメントコンソールやAPIを介してキューを作成すると、URLが払い出されます。SQSのクライアントは、このURLに対してマネジメントコンソールやAPIを介してメッセージの送信、受信(ポーリング)、削除のリクエストを送ります。1度のポーリングで受信するメッセージは1~10個で、ユーザーが設定します。

 クライアントがメッセージの削除リクエストを送るのは、クライアントがキューからメッセージを受信してもSQSはそのメッセージを削除しないためです。受信側のクライアントが障害などでメッセージの処理に失敗したとき、そのクライアントや他のクライアントがメッセージを再取得できるように、クライアントからメッセージの削除をリクエストする仕組みにしています。

 SQSの主要機能である「可視性タイムアウト(VisibilityTimeout)」「遅延キュー(DelaySeconds)」「デッドレターキュー」を説明します。

 可視性タイムアウトとは、クライアントがキューからメッセージを受信したあと、他のクライアントにはそのメッセージを不可視にして取り出せなくする期間のことです。メッセージを受信したクライアントは通常、可視性タイムアウト期間中にそのメッセージを処理してキューから削除します。これにより、メッセージの重複処理を防ぎます。ただし、完全に防げるわけではありません。詳細は後述します。

 メッセージを処理中のクライアントが障害などで処理できなくなっても、可視性タイムアウト期間が過ぎると別のクライアントがそのメッセージを取得し処理できるようになるので、システムの耐障害性を高められます。

 クライアントがメッセージの処理により長い時間を要し、指定した時間以内に処理が終わらない場合、API(ChangeMessageVisibility操作)によって可視性タイムアウトの値を動的に変更できます。

 遅延キューは、キューに送られた新しいメッセージを一定時間不可視にする機能です。後続処理のタイミングを合わせるなどの理由で、時間を空けてメッセージを処理するときに用います。0~900秒の間で指定します。

 キューに送られたメッセージのなかには、受信クライアントが何度処理してもエラーとなるものがあります。クライアントからそのメッセージの削除リクエストが届かないのでキューに残り続け、クライアントが延々と受け取ることになります。

 デッドレターキューは、この無駄を回避する機能です。クライアントによるメッセージの受け取りが指定回数に達すると、クライアントから見えないデッドレターキューに移します。デッドレターキューのメッセージを調査すれば、システムの品質向上につながります。

SQSを使用する際の注意点

 SQSは分散キューのため、利用するうえでいくつか注意点があります。以下に三つ挙げます(図1)。

図1●Amazon SQS(標準キュー)を使ううえでの注意点
[画像のクリックで拡大表示]

重複処理の可能性がある

 1個のメッセージには任意の形式のテキストを256KB格納でき、各メッセージは少なくとも1回はクライアントが受け取ることが保証されます。

 ただしまれに、同一メッセージを重複してクライアントが受け取る可能性があります。これはSQSが複数のデータセンターにメッセージを冗長化して保存するためです。メッセージの削除時にサーバーが一時的にダウンしていた場合、復旧後にそのメッセージをクライアントが受け取ることがある、というわけです。

 このためSQSを使う場合は、同じメッセージを複数回処理しても結果が同じになる「冪等性(べきとうせい)」を考慮し、アプリケーションを設計することが必要です。

順序が守られない

 SQSでは基本的に、キューに届いた順序通りにメッセージをクライアントに渡しますが、その順序性はベストエフォートです。FIFO(先入れ先出し)は保証しません。メッセージの順序性を保つ必要があるなら、メッセージにタイムスタンプやシーケンシャル番号を付与したうえで並べ替えるといった機能を、送信側・受信側のクライアントに付加します。

ショートポーリングはメッセージを受け取れないことも

 クライアントからキューにメッセージの有無を問い合わせるポーリングについて、ショートまたはロングを選択できます。お勧めはロングポーリングです。SQSではAPIのコール回数に対して課金されるのでコストを抑えられるうえに、受信側の処理負荷を抑えられるからです。

 ショートポーリングの場合、特定の受信リクエストによって全てのメッセージが返されるとは限りません。クライアントがキューからメッセージを取り出すとき、SQSはメッセージを保持するサーバー全体から重み付けランダム分散で一部を選び出し、それらのサーバーからメッセージを返すからです。選んだサーバーに全てのメッセージが入っていないことがあります。

 同様の理由でキュー内のメッセージが1000個未満の場合、受信リクエストを送信しても、キューが空のサーバーばかりが選ばれて、メッセージが返されない場合があります。

 解決方法は、繰り返し受信リクエストを行うことです。そうすることで、選ばれないサーバーがなくなり、全てのメッセージを受信できます。このためショートポーリングの場合、ポーリングの回数が増えてコスト高になる可能性があります。

 ロングポーリングでは全サーバーに問い合わせるので、このような問題は発生しません。

 2016年末にSQSに「FIFOキュー」という機能が追加され、従来のキューは「標準(スタンダード)キュー」と呼ばれるようになりました。FIFOキューでは、メッセージの先入れ先出しと順序性が保証されます。代わりに、標準キューより処理性能が少し落ち、若干割高です。

トピックを介しメッセージを受け渡すSNS

 続いてAmazon SNSを取り上げます。SNSは、登録しているエンドポイントやクライアントにメッセージをプッシュ配信するサービスです。

 SNSではメッセージを送信する側を「パブリッシャー」、受信する側を「サブスクライバー」と呼びます。パブリッシャーからサブスクライバーへのメッセージの受け渡しはトピックと呼ぶ箱を介して行います。

 SNSの利用も簡単です。まず、マネジメントコンソールまたはAPIを介してトピックを作成し、アクセス制限のためトピックと通信できるパブリッシャーとサブスクライバーをポリシーとして定義します。そのうえで、トピックにサブスクライバーを登録します。1個のトピックに複数のサブスクライバーを登録できます。

 これで準備は完了です。あとは、パブリッシャーがトピックにメッセージを発行すると、SNSはそのトピックに登録されているサブスクライバーにメッセージを送信します。サブスクライバーは、登録されているトピックに届いた全メッセージを受信します。

 SNSはマルチプロトコルに対応した通知サービスです。サブスクライバーとして登録できるタイプには、メール(平文またはJSON)、HTTP/HTTPS、ショートメッセージサービス(SMS)、モバイルプッシュメッセージング、SQSキュー、Lambdaファンクションがあります。例えばサブスクライバーとしてメールアドレスを登録すると、監視サービスのAmazon CloudWatchから受け取った障害通知などをメールで送れます。HTTP/HTTPSのエンドポイントを登録すれば、SNSを介して二つのシステム間でメッセージをやり取りできます。Lambdaファンクションを登録すれば、トピックにメッセージを発行することにより、任意のコードを実行できます。

 SNSによって、モバイルデバイスのアプリケーションにメッセージを直接プッシュ配信できます。SNSからモバイルエンドポイントにメッセージをプッシュ配信すると、メッセージアラート、バッチ更新、または音声アラートとしてモバイルアプリケーションに表示できます。

 iOS、Androidといったプッシュ配信の仕様の異なる複数のデバイスを一つのトピックに登録でき、SNSが各デバイスの仕様に合わせてプッシュ配信します。このため、デバイスへのプッシュ配信機能を容易に開発できます。

 SNSとSQSには一長一短があります。

 SNSでは、メッセージをサブスクライバーにプッシュ配信します。SQSのようにポーリングを待つ必要が無く、メッセージを即時配信できます。ただし、サブスクライバーが常時メッセージを受け取れるようにする必要があります。

 一方のSQSは、受信クライアントが自身の都合に合わせて、ポーリングによってメッセージを受け取ります。キューにメッセージが届いたとき、受信クライアントが使用可能である必要はありません。

 SNSとSQSを組み合わせると、特定のクライアント(サブスクライバー)にはメッセージを即時配信し、他のクライアントはポーリングでメッセージを受け取る、というアーキテクチャーを作れます。その場合、SNSトピックに特定のクライアントとSQSキューをサブスクライバーとして登録しておきます。さらに、他のクライアントはSQSキューをポーリングするようにします。

 メッセージには、SNSトピックが発行した件名とメッセージに加え、JSONドキュメント内のメッセージに関するメタデータが含まれます。

SQSとSNS組み合わせコーポレートサイトを強化

 それではSQSとSNSを使用して、コーポレートサイトのシステムを疎結合化しましょう。対象とするのは、Web・APサーバーの部分です。このサーバーは、全クライアントからリクエストを受け取り処理する、というモノリシックなアプリケーション。疎結合の真逆です。

 どの機能をモノリシックなアプリケーションから分離できるか、スタンドアロンで実行できるかを検討します。

 このコーポレートサイトには株主に対してビデオメッセージを配信する機能があり、管理画面から動画をアップロードする機能があるとします。動画をアップロードすると、PCやスマートフォンに適したフォーマットに変換(エンコード)し、サムネイルを作成します。

 従来システムでは、一連の処理は密に連動しており、ユーザーが動画をアップロードすると、エンコードとサムネイル作成が終わるまで待たされます。

 そこで、フォーマット変換とサムネイル作成をWeb・APサーバーから分離させ、スタンドアロンで実行するようにしたうえで、SQSとSNSにより連携させます(図2)。

図2●SQSとSNSを使ったジョブ実行アーキテクチャー
[画像のクリックで拡大表示]

 準備としてまず、PC向けエンコード用、スマートフォン向けエンコード用、サムネイル作成用のSQSキューを作成します。次にSNSトピックを作成し、三つのキューをサブスクライバーとして登録しておきます。さらにEC2インスタンスを用意して、各キューをポーリングしメッセージを受け取ったらエンコードやサムネイル作成を行うようにします。

 Web・APサーバーはアップロードされた動画をAmazon S3に保存し、SNSトピックに動画のURLを含むメッセージを発行。ユーザーにアップロード完了のレスポンスを返して処理を終了します。

 SNSはメッセージを三つのキューに即時配信。各EC2インスタンスがキューをポーリングしてエンコードやサムネイル作成を並行処理し、出来上がった動画やサムネイルをS3にアップロードします。

 こうすることで、ユーザーは動画をアップロードするとき、後続処理の完了を待つ必要がなくなります。

 Web向け動画エンコード用、スマートフォン向け動画エンコード用、サムネイル作成用の仮想マシンはそれぞれ独立しているので、各処理の負荷に応じて個別にスケーリングができます。

■設問1

 Amazon SQS 標準キューの説明として、誤っているものはどれですか(一つを選択)。

  1. メッセージは複数のデータセンターに分散、冗長化して保存される
  2. 負荷に応じて自動でスケールする
  3. 月に10万件まで無料でリクエストを処理できる
  4. メッセージは複数回配信されることがある
  5. 標準キューで配信順序は保証されない

■設問2

 Amazon SQSとAmazon EC2を使用して、ユーザーから投稿された画像ファイルを非同期で処理するアプリケーションを開発しています。EC2インスタンスからSQSのキューへポーリング(メッセージの取り出しリクエスト)を行うと、デフォルトの設定では、有効なメッセージが無いときでも直ちにレスポンスが返り、インスタンスは次のポーリングを行います。キューが空のときの無駄なポーリングを減らしてコストを削減するには、どの設定を変更すればよいですか(一つを選択)。

  1. デッドレターキューを使用する
  2. ReceiveMessageWaitTimeSecondsの値を20秒に設定する
  3. VisibilityTimeoutの値を20秒に設定する
  4. DelaySecondsの値を20秒に設定する

■設問3

 Amazon SQSとAmazon EC2を使用して、データ集計の月次バッチ処理を行います。対象データは月末に集約し、翌月1日から処理を開始します。処理量は毎月大きく変動し、予測が難しい状況です。前月データの集計処理は当月5日までに完了すればよく、時間の制約は厳しくありません。この条件で、コストを最小限に抑える方法を検討します。EC2インスタンスの購入オプションのうち、価格を抑えられる可能性が最も高いのは次のどれですか(一つを選択)。

  1. オンデマンドインスタンスを使用する
  2. リザーブドインスタンスを使用する
  3. スポットインスタンスを使用する
  4. Dedicated Hostを使用する

解答・解説は以下を参照。

□設問1の答:C

 Amazon SQSの主な特徴を理解しておきましょう。SQSは、データ耐久性(データが消失しないこと)と拡張性を備えたサービスです。ユーザーが特別な設定をしなくても、受信したメッセージを複数のデータセンターに冗長化して保存し、負荷が急増したら性能が自動でスケールします。AとBは正しい説明です。

 標準キューでは、メッセージの削除処理のタイミングによっては、一つのメッセージが重複して取り出されることがあります。できるだけメッセージを受信した順に取り出させるように動作しますが、順序性は保証されません。よってDとEも正しい説明です。

 SQSの無料リクエスト枠は、月間100万件までです。Cの説明は間違っており、これが答えになります。

□設問2の答:B

 デッドレターキューは、指定した回数だけ正常に処理できなかったメッセージをキューから分離して格納しておくキューです。不要な処理の回数を減らせますが、無駄なポーリングの抑制にはつながりません。

 SQSのデフォルト設定では、メッセージの取り出しリクエストを受け取ったとき、キューにメッセージが無ければ直ちに空のメッセージを返します。クライアントは続けてポーリングを行うため、リクエスト件数が増えてコストがかさみます。

 キューにメッセージが無い場合、すぐには応答せずメッセージの到着を何秒かにわたって待つことができます。ReceiveMessageWaitTimeSecondsで待機時間を指定でき、0~20秒の設定が可能で、デフォルトは0秒です。秒数を長くするほど、ポーリングの無駄を減らせます。正解はBです。

 VisibilityTimeout(可視性タイムアウト)は、クライアントがメッセージを取り出したとき、他のクライアントが重複してメッセージを取り出さないように、一定時間見えなくする設定です(デフォルトは30秒)。DelaySeconds(遅延キュー)は、新しいメッセージがキューに届いてから取り出し可能にするまでの時間を指定する項目です(最長15分)。どちらも、ポーリング回数には影響しないので間違いです。

□設問3の答:C

 EC2インスタンスにはさまざまな購入オプション(契約形態)があり、システムの状況に合わせて選択すると、コストを低減できることがあります。

 オンデマンドインスタンスは、いつでも必要に応じて利用を開始し中止できる標準の契約形態です。リザーブドインスタンスは特定インスタンスタイプに対して1年または3年の契約を結ぶ代わりに、割引を受けられます(最大でオンデマンドインスタンスの75%割引)。常時稼働が必要なインスタンスに適しています。

 Dedicated Hostは指定したインスタンスを専用の物理ホストで稼働させるサービスです。ソフトライセンスの形態によってはそのコストを抑えられますが、設問のケースは当てはまりません。

 スポットインスタンスでは、購入できる価格(スポット価格)が需給状況で随時変動します。リクエストの上限料金がスポット価格を上回っているとき、余剰のインスタンスが割り当てられます。うまく使うとオンデマンドインスタンスに比べ7~9割ほどコスト削減することも可能です。

 スポット価格がリクエストの上限価格を上回ると、強制的にインスタンスを終了、停止または休止させられます(継続期間を指定することもできます)。しかし設問にある、集計処理のような分割しやすいジョブの処理に向いています。正解はCです。

堀内 康弘(ほりうち・やすひろ)
モビンギ 取締役、M&Aナビ 技術顧問
ブイキューブ、gumiを経て、2012年3月にアマゾン データ サービス ジャパン(現・アマゾン ウェブ サービス ジャパン)入社。テクニカルエバンジェリストとして活躍。2014年10月に退職し、2015年1月モビンギ 取締役に就任。2019年2月からM&Aナビ 技術顧問を兼務。トレノケートでAWS公式トレーニングの講師を務める。
三浦 美緒(みうら みお)
トレノケート ラーニングサービス本部 ラーニングサービス第1部 技術教育エンジニア
外資系ITベンダーでオープン系エンタープライズシステムの運用監視環境の設計、構築に従事した後、2002年より現職。Linux、Apache、BINDなどのトレーニング企画、提案、実施を担当。近年はAWS認定インストラクターとして研鑽中。
出典:『Amazon Web Services エンタープライズ基盤設計の基本』(日経BP社)の第4章を改編
記事は執筆時の情報に基づいており、現在では異なる場合があります。