はじめに
疎結合及びサーバレスの分野はWell-Architected Frameworkでは
- 信頼性……疎結合
- パフォーマンス効率……サーバレス
の領域にありベストプラクティスではそれぞれ
- コンポーネントの疎結合
- サーバーではなく、サービス
の領域になる。
疎結合とは(なぜサーバレスなのか)
疎結合とサーバレスは相互依存……というより疎結合にするためにサーバーレスを求め、サーバーレスを求めると疎結合になるという関係性にある。
じゃあなぜそうなのかを簡単に押さえてみる。
疎結合とは
ざっくりいうと、コンポーネント間は連携はしているが相互依存度は低いもしくは0であるような状態のことをいう。
つまり、コンポーネントは基本的には独立している状態に近い。
これはで1つのコンポーネントが潰れることで、他のコンポーネントも連鎖的に障害となり結果サービスが停止してしまう事態(単一障害点)を避けることにもつながる。
AWSにおける疎結合に関連する主なサービスは
- Lambda……サーバーインスタンスで直接連携するのではなく、Lambdaのトリガー処理による連携を利用する
- SQS……SQSのキューイングによる通信によってインスタンス間で連携する
- ELB……サーバー間のトラフィックの調整及びELBを基点としたコンポーネントの連携等
- SNS……アプリケーション間通信でインスタンス間連携を結ぶ
となる。
密結合であるアーキテクチャは以下のようなデメリットが生じる。
- 1インスタンスの障害やメンテナンスの影響がアーキテクチャ全体に広がりやすい
- 同様に1つの修正対応で他のインスタンスへの影響を多く考慮すればいい
- 負荷対応やスケーリングなども容易にできない
- システム構成の追加・変更が難しい
密結合であるアーキテクチャの設計パターンとしては以下のようなものが挙げられる。
- ユーザー認証・管理をバックエンドサーバーで処理する
- 通常のEC2インスタンスでアプリケーションを構成する
- アプリケーション間では直接通信する
- 静的ウェブシステムをEC2インスタンスEBSに保存する
逆に疎結合化であるアーキテクチャの設計のパターンとしては以下の通りになる。
- ユーザー認証・管理をIAMなどのマネージド型サービスを利用
- なるべくLambdaなどのサーバレスでアプリケーションを構成
- アプリケーション間ではSQSなどMQ通信で連携
- 静的ウェブシステムをVPC外部のS3に保存する
サーバレスとは
AWSにおけるサーバレスはEC2主体のアーキテクチャではなく、Lambdaを主体としたアーキテクチャを設計することを指す。
サーバレス化を求めるのは疎結合なアーキテクチャを実現したいからであり、それはサービス化へとつながっていく。
AWSにおいては利用しているインスタンスが本当に必要であるか(単純な機能や処理の実行のためだけにインスタンスを利用していないか)を検討することから始まる。
AWSにおける関連サービスは以下の通り。
- Lambda
- SNS
- SQS
- ELB
- SES
- DynamoDB
- Amazon API Gateway
- Amazon Cognito
サービス化とは
サービス指向アーキテクチャ(SOA)というアーキテクチャ設計の思想からより小さいプロセス単位のサービスをAPIで連携したマイクロサービスで設計するという設計思想。
SOAの特徴は以下の通り。
- 一通りの機能が揃った大きなサービス単位でコンポーネントを分割する設計方式である
- アプリケーションをコンポーネント化して、通信プロトコルによる連携で他のコンポーネントにサービスを提供するアーキテクチャ設計である
- 例として年金システムで喩えると、給付に関するサービス・年金徴収に関するサービス・受給者登録や検索サービス……といった個々の大きなサービスの集合が年金システムとなるという次第になる
これに
- SOAよりも小さな機能単位(1つのサービスをさらに作業ごとに細分化していくイメージ)のプロセスでサービス化した構成を求める
- 各プロセスでは1つの小さなタスクをサービスとして提供し、プロセス間の通信はAPIを用いる
- APIを利用してコンポーネント間を連携する
といったような思想を追加したものがAWSにおけるサービス化の考え方となる。
疎結合及びサーバレスを実現するAWSサービスたち
ということで前述までの思想を頭に入れたところでそれらをAWSで実現していくための中核になるサービスを確認していく。
まず通知サービスとして
- SQS
- SNS
- SES
があり、よりサーバレス化の中核をなすサービスである
- Lambda
- API Gateway
があるということを頭に入れておく。
SQS(Amazon Simple Queue Service)
プロセス間通信などのスレッド間通信に使われるコンポーネントで制御やデータを伝達するポーリング型キューサービス。
ポーリングとは複数のプログラム間通信に対して、一定のタイミングの問い合わせがあった場合に送受信処理をおこの合う通信方式を指す。
つまり、送受信の間に中継点を置くことで送信側としては送信処理を受信側の都合で完了できずに詰まってしまうということもなく、受信側としても受け取りはタスクに余裕のあるときで良くなる……という仕組み。
SQSでは
- 送信側から通信内容がSQSに送られる
- SQSは通信内容をRequestキューとして保持する
- 受信側は処理タスクに余裕がある場合、RequestキューをSQSからPullする
- Pullしたキューに基づいて処理が行われ、SQSにレスポンスを返す
- SQSはレスポンスをResponseキューとして保持する
- 送信側は処理タスクに余裕がある場合、ResponseキューをSQSから受け取る
という処理フローになる。
特徴としては以下の点が挙げられる。
- フルマネージド型サービスである
- 高可用性、高スケーラビリティ、高スループットに貢献しそれでいて低コスト化も図れるサービスである
- 複数のサーバー、データセンターにメッセージを保持する高可用性構成である
- 多数の送信者と受信者に対応可能なスケーラビリティを確保する
- メッセージが増加しても、高スループットを維持できる
- 無料枠があり、かつ従量課金制である
- メッセージサイズは最大256KBまで。ただしExtended Client Libraryというオプションを利用すると2GBまでのメッセージを送受信できる
- メッセージの保持期間はデフォルトは4日。ただし、60秒~14日まで変更は可能
- 1つのキューごとに最大120000 In Flight(受信されたメッセージ&Visibility Timeout内の)メッセージ
- メッセージの配信遅延もできる
- メッセージの受信に対して待機時間(メッセージが受信可能になるまでポーリングが待機する時間)を設定できる
またその他の機能として
- Short Poling……キューが空の場合でも即時にリターンする
- Long Poling……キューがからの場合はタイムアウトまで待つ
- デッドレターキュー……ずっと残ったメッセージを別キューに移動し、正常に処理できなかったメッセージを隔離できる
- Visibility timeout……新しいメッセージを指定時間見えなくする
というものもある。
ショートポーリングとロングポーリング
参考: Amazon SQS short and long polling
SQSにおいてはメッセージ待機時間でロングポーリングかショートポーリングかを設定できる。
ロングポーリングは
- キューからメッセージをPullする場合(1キューにつき最大10まで)すべてのサーバーにPullをかける
- Pullした結果リクエストで指定されたメッセージの最大数のうち少なくとも1つPullされた場合Responseを返す
- よって、空のResponseは設定した待機時間が終了した場合のみ送られることになる
という特徴がある。
対してショートポーリングは
- Pullは重み付け(サーバーのサブセットに対して加重ランダム分布に基づいたもの)で行われる
- Pullした結果メッセージが見つからない場合は即時に空のResponseが返される
という特徴がある。
差異としては以下の通り。
-
ショートポーリングの場合Pullは重み付けによって行われ、結果PullされないサーバーもあるのでRequestに対しすべてResponseされない場合がある
-
ロングポーリングはメッセージ受信待機時間が終了するまで、空のResponse(Requestに対し、利用可能なメッセージが無い場合のResponse)または偽の空のResponse(Requestに対して、利用可能なメッセージはあるがそのRequestに対してのResponseには含まないという場合のResponse)を返さないので結果としてSQSの利用コストを削減し、誤って空のResponseを返すことが減る
-
ただし、ロングポーリングは上述の特性上、適切に待機時間を設定しなければそれだけResponseに時間がかかってしまう
SQSキューについて
キューにはRequest・Responseという違い以外にも、キューの処理順序の違いが存在する。
デフォルトである標準キューは
- 順番通りに処理
- 1回だけのメッセージング
というルールで通信処理をなるべく実行するキューである。
わざわざなるべくと注釈がついてることから察せられるように、場合によってはキューの処理順は前後し、同じメッセージを複数回受信する可能性があることに注意。
それに対してFIFO(First in First out)キューは 必ず最初に入ってきたキューから処理をしていくというキューになる。
Visibility timeout
Visibility timeoutを設定することで、優先的に処理してほしい受信インスタンスを指定することが可能となる。
どういう理屈かというと以下の通り。
- 送信側からSQSが通信内容を受け取る
- SQSは通信内容としてRequestキューを保持する
- 受信インスタンスが複数ある場合、Visibility timeoutを指定すると指定したインスタンスはその時間RequestキューをPullできない
- よって、Visibility timeout外のインスタンスが優先的にRequestキューをPullできる状態になる
この仕組みは特にメインのインスタンスの他に、スポットインスタンスを利用しているときに効果的である。
ただし、設定した時間によっては指定外のインスタンスにキューが溜まってしまい、結果として負荷分散が失敗してしまうというデメリットもあるのに注意。
SNS(Amazon Simple Notification Service)
フルマネージド型のプッシュ型通知サービスで他のサービスとの非同期通信を可能にする。
特徴としては
- 単一発行メッセージ
- メッセージ通信の順番は保証されない
- 送信の取り消しは不可
- 配信ポリシーによる再試行が実施できる
- メッセージサイズは256KBまで
フローとしては
- 送信側がメッセージを送信
- SNSが通信内容を受け取り、Topicを作る
- あとはTopicをポリシーに基づいてHTTPS、EMAIL、SQS、Mobile pushのいずれかの通信方式で受信側にPushする
というものになる。
他サービスとの連携に関しては以下の通り。
- CloudWatch……Billing Alertの通知に利用
- SES……Bounce/Complaintのフィードバックを通知に利用
- S3……ファイルがアップロードされたときの通知に利用
- Elastic Transcoder……動画変換処理完了/失敗時の通知に利用
SNSとSQS
処理方式が違うのでユースケースによって使い分ける必要がある。
SNSに適しているのは
- メッセージが永続でなくてもよい
- プッシュ型配信方式
- Producerがメッセージを発行し、Consumerがそれをサブスクライブする形式である
という場合。
SQSの場合は
- メッセージに永続性が必要である
- ポーリング型配信方式を利用したい
- ProducerもConsumerも送受信できる必要がある(つまり、Request-Responseの関係性可にある)
SES
フルマネージド型及びサーバレス型のコスト効率に優れたEメールサービスである。
特徴としては
- スケーラブルな構成で信頼性が高いマネージド型サービスである
- メール送受信のサービスである
- Transaction Mail等が利用できる
- S3やLambdaと連携することで、メール受信をトリガーにこれらのアクションを発火できる
- メールが送れなかった場合の処理をバウンス処理として規定できる
また事前にドメインまたはメールアドレスを事前に申請する必要がある。
SESのメール送信方式
メールサーバーとしての用途だけではなく、アプリから自動でメールを送信したり連携処理できるようにするためにSESは利用できる。
HTTP REST API
以下のようなメール送信APIとしてSESを利用できる。
認証にはAWSアクセスキー及びシークレットアクセスキーを使用。
- SendEmail API……From、To、Subject、Bodyだけ用意すればSES側でメッセージを生成して送信するためのAPI
- SendRawEmail API……メッセージ全体をアプリケーション側で生成して送信するためのAPI
SMTPエンドポイント
SESにSMTPエンドポイントを設置し、生成済みのEmailメッセージを受け取ったらそこを経由してメールを送信する。
SMTPを前提としてプログラムから直接利用する場合に効果的。
利用できるポートは
- 25
- 465(SMTP over SSL)
- 587(Message Submission)
である。
利用にはTLS(Transport Layer Security)が必要で、認証には専用のIAMユーザーが必要となる。
ユースケース
SQS及びSNSとの違いはEmailサービスに特化していること。
つまり、Emailをトリガーとして以下のような連携を行うことにSESを使う目的があることになる。
- SNSと連携して、SNS Topicへのメール配信を行う
- EmailをトリガーとしてLambdaのカスタムコードを発火
- S3と連携して、S3バケットへメールを配信する
Lambda
AWSでプログラムを動作させるためのサービス。
例えば今までEC2でWebサーバーを立ててやっていたことをLambdaに置き換えたり、データのCRUD処理をLambdaで実行するなどすることでサーバレスな設計をしていく。
-
実行基盤はすべてAWSが管理
-
AWSサービスと連携させることで簡単にイベントドリブン(利用者や外部の別のプログラムなどが引き起こす出来事に対応する形で処理を記述あるいは実行する方式)なアプリケーション
-
.NET (PowerShell、C#) Go、Java、Node.js、Python、Rubyで書かれたコードを実行できる
-
100ミリ秒単位でコード実行時間に対して課金される(コスパはいいらしい)
-
オートスケールなサービスである
関数なので基本的にはイベントで発火させることになる。
例としては
- 画像アップロード
- アプリケーションの実行処理
- Webサイトのクリック
- デバイスからの出力
等々。
LambdaにはPushモデルとPullモデルとがある。
Pushモデルは
- S3。Cognito、SNSなどのAWSサービスとカスタムイベントが直接実行することにより起動するLambdaファンクションである
- サービスもしくはアプリが直接実行する
- 処理順序は順不同
- 実行に失敗した場合は3回までリトライされる
Pullモデルは
- DynamoDBとKinesisなど直接的にイベント発行をしないサービスにおいて、Lambdaがそれらへポーリングを行って自らイベントを取得する
- ストリームに入ってきた順に処理される
- イベントソースとして登録したストリームに対してLambdaが自動的にデータ取得などのファンクションを実行する
- イベントごとに複数レコードを取得可能である
- リトライはデータが期限切れになるまで行える
例えばKinesis StreamでPullモデルを使うとなると、Kinesis Streamで処理されたストリームデータをLambdaが能動的に取得して処理を実行するという形になる。
パーミッションは自動でファンクション作成時に作成される、クロスアカウントアクセスも設定できる。
- LambdaファンクションがAWSリソースにどういったアクションを実施させるかを決定させる(Execution)
- 指定されたIAMロールに沿ってAWSのリソースへのアクセスが許可される(Execution)
- Lambdaファンクションをどのリソースを実行できるかを決定する(Invocation)
主要な連携先としては
- S3
- Kinesis
- DynamoDB Streams
- Cognito(Sync)
- SNS
- Alexa Skills Kit
- SWF
フローは
- コードをアップロードする
- 関数を設定(スケジューリングかイベント駆動型か)
- 必要なメモリ容量を指定する
- タイムアウト時間を指定する
- VPCアクセス用にVPCを指定する
- 関数を起動する
という感じになる。
ブループリント
Lambdaファンクションのサンプルコード集。
ユースケースから検索して、任意のものを編集して利用できる。
スケジュール機能
Lambdaにもスケジュール機能があり、特定時刻をトリガーにしてLambdaファンクションを実行できる。
もちろん定期的なスケジューリングも可能。
バージョニング
EC2ImageBuilder他のようにバージョニングも可能、
Lambdaにおいてはファンクションの一時点に対して行う。
具体的には
- ファンクションの作成や更新時にpublishパラメータからバージョンが発行される
- PublishVersionにより明示的にバージョンを発行することが可能
- バージョンは一度発行するとそのバージョンの内容を変更することは不可
- 単純にバージョン番号が増加する
- エイリアスを設定して特定時点にマークすることが可能
- エイリアスを作成することでバージョン番号を把握していなくても指定バージョンを呼び出すことができる
という感じ。
VPCアクセス
Lambdaはインターネットを経由せずにVPC内のAWSリソースへとアクセス可能である。
- AWSのすべてのVPC内のリソースなどへインターネットを経由せずにアクセスが可能である
- Elastic Network Interface(ENI)を利用して実現
- ENIには指定したサブネットのIPHONEがDHCPで動的に割り当てられる
- VPC内リソースにアクセスさせたいLambdaファンクションに対してVPCサブネット及びセキュリティグループを指定する
- ファンクションに割り当てるIAM RoleにAWSLambdaVPCAccessExecutionRoleポリシーをアタッチしないといけない
Lambda Layer
Lambdaファンクション間で共通するコンポーネント(この場合だと共通する機能)を5つまでLayerとして定義して、ファンクションが参照できるようにする。
プログラミング言語で言うクラスのような印象を受ける。
ロードバランサー
EC2のものと同じ。
EC2とロードバランシングすることもできる。
ユースケース
デバイス経由だと
Alexa → Lambda → Alexa Skills
AWSサービスでの連携だと
CloudTrail(ログ分析で異常を確認) → S3(CloudTrailから異常ログを特定のバケットで受け取る) → Lambda(プッシュ通知) → デバイス
ということが考えられる。
モバイルアプリであれば
- デバイスからの認証はCognito
- 認証後、S3へデバイスから写真登録が行われ、それをトリガーとしてLambdaが起動
- DynamoDBへLambdaからメタデータ登録が行われ、デバイスはDynamoDBからメタデータを取得できるようになる
Lambdaエッジ
CloudFrontのエッジロケーションを利用して、そこにLambdaを連携させることでユーザーの地理的に近いロケーションでコードを実行することが可能である。
エッジロケーションとリージョナルエッジキャッシュ(またはオリジンサーバー)とのやり取りにおいてLambdaファンクションを実行し、結果をデバイスorオリジンサーバーへと返す。
API Gateway
API作成や管理をフルマネージドサービスで行ってくれる。
- 最大数十万個のAPI同時呼び出し・受付が可能
- アクセス制御の管理
- DDoS攻撃対応やスロットリングによるバックエンド保護
- EC2・Lambda・任意のウェブアプリケーションのワークロード処理を実行する
- Lambdaと密接に統合されている
- WebSocketを利用したリアルタイムかつ双方向通信のAPIも処理が可能
そもそもAPIとは
Application programing interfaceの略。
RequestとResponseで他のサービスや機能を呼び出せるようなインターフェース郡のことを指すらしい。
例えばWEB APIだとTwitterから情報を引き出すためのTwitterのAPIやAmazon アフィリエイトでアレコレするためのAPIとかがある。
APIの活用
自社アプリ・サービスをAPI化して連携を目指す方法と、API化された他社アプリやサービスを利用するの2パターンにわかれる。
どちらも自社のサービス・事業と連携してサービスを展開したり、アプリを開発するという目的のために利用されることが多い。
なお、自社サービスやデータをAPI化して社内外連携を促進して、ビジネス領域・価値を拡大させるというビジネス活動のことをAPIエコノミーという。
API利用
- APIの作成
- 利用状況の監視
- バージョン管理
- 認証・アクセス管理
この4つが利用において大切になってくる。
ユースケース
API GatewayはアプリとAWSサービス(間にLambdaを挟むことが多い)との連携口となるので以下のようなフローが考えられる。
Webアプリ → API Gateway及びAPI Gatewayキャッシュ → Lambda → AWSサービス
ハンズオン
SQS
いつものようにウィザードで作成できる。
可視性タイムアウト = Visibility timeout。
保持期間でポーリングされるまでサーバーにメッセージを溜めておく期間を設定する。
特定のインスタンスのみにキューを処理させたい場合はポリシーを設定する。
アドバンスドを選択すれば自分でポリシーを編集できる。
ポリシーの強度としてはIAMポリシーでSQSへのアクセスを制御するのと同程度の結果を得られるらしい、併用も可。
Amazon SQS での Identity Based ポリシーの使用
暗号化及びデッドレターキューについては以下の通り。
作成すると以下の通りコンソールに表示される。
動作を確認してみる。
メッセージを送信すると以下のようにポーリング処理が行われる。
完了すると以下のように確認できる。
SNS
例によってウィザードに従っていく。
講義中では言及されなかったが、おそらく仕様変更でSNSのTopicにおいてもFIFOが利用できるようになったようだ。
SQSと同じでポリシーも設定できる。
再配信ポリシーに関しても以下のように設定できる。
Cloud Watch Logsと連携してログを溜めることもできる。
次にサブスクライブ(SNSから通知を受信できるプラットフォーム)の設定をする。
サブスクライブ先にはフィルターが設定でき、サブスクライブ先が複数いる場合は条件を設定すると条件を満たす場合とそうでない場合で配信される通知に差異を出すことができる。
設定したサブスクライブのプラットフォームで認証処理を行う。
動作を確認してみる。
SQSと連動することもできる。
任意のSQSキューとSNS Topicを作り以下のようにサブスクライブさせる。
サブスクリプションができたことが確認できる。
Topicからメッセージを送信するとSQS側で以下のように確認できる。
SES
講義中では東京リージョンでは利用できないとあったが、2020年7月より利用解禁となっていた。
また、ドメインやEmailの登録は時間がかかると言及されていたが特にそんなこともなかった。
ともあれ登録しないと始まらないのでコンソールから登録。
ちなみにドメインを登録するとRoute53のHosted Zoneにも追加され、Route53でそのドメインを使ってSESと連携することも可能になる。
コンソールは以下の通り。
まずメトリクス。
ダッシュボード。
クロスアカウントでSESを使う場合の設定。
メールテンプレートの設定。
これ以外にもEmailの送受信に関する設定が一通りできる。
送信してみると以下のように送信できたがことが確認できる。
Lambda
今回はEC2インスタンスをWebサーバーとしてDynamoDBやRDSでデータをやり取りするといった今までのハンズオンからEC2をそっくりLambdaに置き換えてやってみようという話である。
まず、DynamoDBでテーブルを作成して以下のようにデータを入れておく。
なぜDynamoDBなのかというとLambdaとの連携で使うDBとして最大手になるからである。
(RDSは仕組みは整ってきたものの、それでもプロキシを設定しないといけないので向いてるかと言われると首は縦には触れない)
DBができたらさっきのデータを取り出す関数を書いてみる。
まずはLambdaに飛んでいつものようにウィザードに進んでいく。
ブループリントを使いたいならこちら。
自力で設定すらな以下の通りにやっていく。
IAMロールがLambdaの実行には必要であることがわかる。
ここからS3などと同じようにアクセス権限自体はIAMロールで設定することがわかる。
ポリシーテンプレートからロールを作る場合は、以下のように利用したいロールを選択する。
関数を作ると以下の通りコンソール画面が出来上がる。
先程選択したロールも以下のように確認できる。
Lambdaを既存のAWSサービス等から発火させたい場合はトリガーを追加することで可能。
送信先はLambdaの処理を飛ばす先があれば選択する。
このよう設定自体はかなり易しい感じ。
Lambdaの基本設定。
メモリの割り振りはLambdaはCPUメモリを振れば振るほど当然それだけ処理性能が上がる。
ただし、料金は高くなる。
特定のVPCにのみLambdaを適用したい場合はこちらから設定する。
同時実行及び非同期の設定はこちら。
非同期ではデッドレターキューの設定もできる。
RDSを利用する場合には以下の画面からプロキシを設定しないといけない。
ではコードを書いていく。
以下のようにコードを書いたら、Deployボタンを押して変更を適用。
これではエラーになるので以下のようにする。
{
'id': '1001'
}
コードの画面に戻ってTestボタンを押すとテストが始まって以下のように結果が出る。
API Gatewayに移動するとAPIができているのでメソッドを作成していく。
今回はGET処理になるのでGETを選択。
今回は欲しいデータが決まっているので、以下のように統合リクエストの画面でデータの形式をマッピングテンプレートで設定。
メソッドテストで左のようにクエリ文字列を入力すると、右のように返ってくることが確認できる。
これで処理が完成したので、デプロイする。
デプロイするとこのようにコンソールが出てくる。
エンドポイントからアクセスして先程の処理を確認してみる。
エンドポイントのURLに?id=1001と入れると
このようにデータがGETされることが確認できる。