AWSでジョブWorkerを構成するベストプラクティス 〜 SQSの巻

AWSでジョブWorkerを構成するベストプラクティス 〜 SQSの巻

Clock Icon2014.05.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

よく訓練されたアップル信者、都元です。AWSでシステム構築をする場合は、Design for failureという考えに基いて、複数AZにまたがる形の冗長構成を組むのがベストプラクティスです。さらに、このように分散させた各インスタンスには、出来る限りマスターを作らない、つまりSPOFとなるインスタンスを避ける構成であるのが理想です。

という話題については以前AWSにおける可用性の考え方というエントリーでも書きました。

可用性 (availability) と拡張性 (scalability)

本題はジョブWorkerですが、WebサーバやDBサーバの可用性と拡張性を先におさらいしておきましょう。

Webサーバ

この考えで構築する最も基本的な構成が、Webシステムにおける ELB + Webサーバ の構成です。この構成マルチAZと呼び、片方のAZが丸ごとダウンしたとしても、サービス自体はダウンさせずに継続できる *1、という特徴があります。Webサーバ内に特別な「マスター」はありませんので、どちらのAZがダウンしても同じです。所謂 HA (high-availability) な構成です。

elb

また、Webサーバを4台、6台、8台と増やしていくことによって、スケーラビリティが確保できます。

ちなみに、ELBについては、サービス自体がマルチAZで構成されていますので、この冗長性は特に意識せずとも確保されています。

DBサーバ

次にDBについて考えます。RDSを利用する場合、複数のAZにまたがってレプリケーションを行えます。

rds

この場合、片方がマスター(稼動系)となり、もう片方がスレーブ(待機系)となります。従って、残念ながらこの場合は「マスターを作らない」という条件を満たすことができません。稼動系の方のAZが丸ごとダウンした場合、待機系のマスター昇格が発生し、フェイルオーバーによって一定の可用性を確保します。フェイルオーバーには数分の時間がかかりますので、完全なHA構成ではありません。

また、RDSは複数のマスターを作れませんので、処理能力の拡大は基本的にスケールアップによって行うことが多いです。読み込み負荷が大きいケースであれば、リードレプリカによってスケールアウトが可能ですが、その数にも一定の制限があります。というわけで、RDSはスケーラビリティについても限定的であるのが実情です。

DBに可用性と拡張性を確保したい場合は、リレーショナル・データベースを諦めて、DynamoDB等を使うことも検討します。DynamoDBは、マルチAZの仕組みで可用性と拡張性を確保しています。

ジョブWorker

さて、だいぶ前置きが長くなってしましました。ここから本題。

Webサーバは多くの場合、HTTPリクエストを受け取り、何らかの処理を行い、処理完了後にHTTPレスポンスを返す、という所謂「同期」処理を担います。一方、ジョブWorkerは、処理依頼(ジョブ)を受け付けて待ち行列(キュー)に追加し、ジョブの完了に関係なく制御が依頼元に戻る、という所謂「非同期」処理を担います。Workerは主にバッチ処理等に使われるアーキテクチャです。

例えば、大きめな集計処理や動画のエンコーディング処理等を行うWebサービスを考えます。これらの処理は、1件につき数十分〜数時間掛かるものだとイメージしてみてください。このような処理のリクエストを同期処理として実行してしまうと、実行ボタンをクリックした後に何らかのネットワーク切断が発生したら、全てを最初からやり直す羽目になるでしょう。まぁ、それ以前にHTTPのタイムアウトが発生しますよね。

こういう処理は非同期処理として実装するのが常套です。HTTPとしては「処理を受け付けました。進捗はこちらで確認できます。」的なレスポンスを即座に返し、進捗確認ページでは、現在のジョブのステータスを確認できる、といった形です。

このような仕組みは、前述の「ELB + Webサーバ」ではなく「SQS + Workerサーバ」という構成で実現します。

sqs

クライアント *2はSQSキューにジョブを登録します。Workerはキューに対してポーリングを行い、ジョブを認識し次第処理を行います。

SQS自体はELBと同様、可用性と拡張性はサービスとして確保されていますので、我々は気にする必要はありません。キューの出口で待つWorkerはマルチAZ分散していますので、AZダウンにも対応できます。また、特にマスターもないので可用性には問題ありません。キューに貯まるメッセージが多くなった場合は台数を増やして行けばいいので、スケーラビリティも充分に確保できています。

まとめ

全部組み合わせてみるとこんなかんじです。

all

Workerは、処理結果をDBに書き戻しても良いですし、S3に書き込んでもOK。EMRやElastic Transcoderをキックしたり、SESでメールを送っても構いません。それは実行する処理次第ですね。

最後に注意点を2つ。SQSが分散キューであることに起因する制限事項があります。

1つ目。キュー内のジョブの順序は保証されません。まぁ大抵、おおむね、enqueue(投入)した順にdequeue(出力)されます。が、これは保証されたものではありません。ジョブ同士の前後関係を制御したい場合は、「順序は保証されない」ということを意識して、ワーカー側に別途独自に何らかの実装が必要です。

2つ目。メッセージは「at least once delivery」です。何のことかと言うと、「1つのメッセージをenqueueしたら、最低1回はそのメッセージをdequeueします」ってことです。いいじゃん、普通じゃん、と思うわけですが。よく考えれば「1つのenqueueに対して、同じメッセージが2回dequeueされてしまうことがある」と言っているのです。まぁ大抵、おおむね、1つのenqueueメッセージは、1回だけdequeueされます。が、これは保証されたものではありません。ジョブ自体を冪等に実装する *3か、もしくは重複処理を防止する処理をワーカー側に仕込む必要があります。

という2点には、是非お気をつけて。

脚注

  1. もちろん、処理能力的には半分になってしまいますが。
  2. 図中にはEC2インスタンスとして書きましたが、そうでなくても良いです。
  3. つまり、同じ処理が二回以上実行されても困らないように実装する。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy