AWS Startup ブログ

【週刊 Ask An Expert #12】チャットシステムをサーバーレスでプロトタイプ中。DB設計について見て欲しい! AWS Loft Tokyo で受けた質問まとめ #AWSLoft

こんにちは、スタートアップ ソリューションアーキテクトのザビオ(@zabbio) です。
好きなAWSサービスはありますか?僕は Amazon AuroraAmazon Managed Blockchain です!

今回は週刊 Ask An Expert 第 12 回目をお届けします。「参考になった!」「いい内容だ!」と思っていただけたら、ぜひハッシュタグ #AWSLoft を付けてシェアしてください。もちろん、改善点・ご要望もお待ちしております。

Ask An Expert ?

さて、皆さん AWS Loft Tokyo はご存知でしょうか?
目黒セントラルスクエア17Fにある、AWS を利用中のスタートアップとデベロッパーのためのコワーキングおよびイベントスペースです。その中に、AWS のエキスパート – Solutions Architect(SA)や Cloud Support Engineer(CSE)といった中の人に技術的な質問ができる、Ask An Expert カウンターがあります。そこでは毎月、来場者の方から100件以上にものぼるご相談をお受けしています。

ある日の Ask An Expert(Solutions Architect 桑野 a.k.a. 銀河

この連載では、我々 AWS のエンジニアが Ask An Expert でどのような質問を受け、どんな感じで対応しているのか、 *非常にざっくりと* ご紹介していく「週刊 Ask An Expert」をお届けしていきます。他の AWS Loft 利用者がどんな質問をしているのか、自分が知らなかった新しいトピックはないか、Ask An Expert ってどんなところなのか、一緒に見ていきましょう!
※ 似たご質問をまとめたり、ざっくりまとめにくいご質問を省いたりしているため、実際のご質問件数・内容とは異なる部分があります。

週刊 Ask An Expert #12 (2019/07/1 – 07/5)

この週の対応者は SA:市川、塚田、桑野、小泉、成田、星野、鈴木、中武、CSE:福嶋、古野、榎本 でした。

Q: Amazon QuickSight のデータソースに Amazon Athena を指定して実行したが、権限エラーとなる。

手元の環境でも確認しましたが、再現せず。また、お客様環境では Athena 単独でのクエリの実行は成功しており、他の QuickSigth->Athena では成功しているとのこと。QuickSight の権限も確認しましたが、特に問題は確認できず、再現も出来ていないため、詳細に対応させていただくためにAWSサポートへのお問い合わせをお願いしました。
また、サポート未加入とのことでビジネスサポートの無料キャンペーンをご紹介しました。

※ ご案内後、原因が確認できたとご連絡頂きました。Athena の権限設定で、指定するAmazon S3 を許可したら成功したとのことでした。

また、Amazon Athena, Amazon QuickSight を含むデータ分析基盤を構築するハンズオン、「AWS Data Lake ハンズオンセミナー」が 7/17 (木) 13:00〜17:30 に目黒で開催されます。ご興味のある方はぜひご参加ください。

前回のData Lake ハンズオンセミナーの様子。開催報告ブログはこちらです。

Q: Windows サーバーのログ収集方法を知りたい。

要件をお伺いしたところ、収集したログの検索や処理などは今回は必要なく、まずシンプルに Amazon S3 に保存したいとのことだったので、Kinesis Agent を利用した Amazon Kinesis Data Firehose を使用して S3 に保存する方法についてご説明しました

Amazon Web Services ブログ: Amazon Kinesis Agent for Microsoft Windows を使用して、Windows イベント、ログ、およびメトリックを収集、解析、変換、ストリーム配信する

Q: AWS IoT で管理しているデバイスが正しく動作していることを監視したい。

ドキュメントにあるように、Amazon SNS トピックを通じて取得できる Connect.SuccessPublishIn.Success イベントを利用して、 Amazon CloudWatch の Alarm を設定し、監視を行う方法をご案内しました。

CloudWatch を活用したアラームの設定方法や運用についてはこちらも御覧ください。

20190326 AWS Black Belt Online Seminar Amazon CloudWatch

Q: Amazon S3 で静的Webサイトホスティングを利用している。新しい HTML ファイルをアップロードしても更新が反映されない。

何らかのキャッシュを見ている可能性を考えましたが、 Amazon CloudFront は使っておらず、更新作業も行ってから2時間は経過しているとのことでした。
S3 の結果整合性についてもご説明しましたが、更新からかなり時間が空いているので結果整合性の問題ではなさそうでした。

切り分けのため Web ブラウザを変えてみたところ、正しく新しい HTML が表示されることが確認できました。ブラウザの挙動に依存する可能性がある点をお伝えしました。

Q: Amazon SageMaker から boto3 で execute-statement を実行したがエラーになってしまった。

execute-statement (HTTP 経由の SQL 実行)は現状 Amazon Aurora Serverless のみ対応
https://aws.amazon.com/jp/blogs/news/new-data-api-for-amazon-aurora-serverless/
お客様は Amazon RDS(PostgreSQL)だったので現在は対象外であることをお伝えしました。

Q: Amazon QuickSight のデータソースに Amazon RDS を指定したが接続できない。

RDS 側の Security Group に必要な設定がされておらず、QuickSight からの通信をブロックしていました。
ドキュメントを参考に QuickSightからの接続を許可していただき、接続できたことを確認しました。

Q: VPS サービスから AWS へのマイグレーションを計画中。検討中の設計をレビューしてほしい。ユーザー投稿型のサービスで、既存ユーザーデータは数千件あり、ユーザーごとに複数件の記事を投稿する。現在、記事数は全部で数万件ある。今後、数週間ほどでユーザー数が数倍になる予定。現在考えている設計は、Ruby on Rails で書かれたメインの Web アプリをAmazon ECS 上で動かし、それとは別で一台の Amazon EC2 上でスタンドアローンな Java アプリケーションを稼働。その Java アプリは ECS 上の Ruby on Rails からアクセスされる。データベースは Amazon RDS PostgreSQL を一台で利用予定。扱う画像データは、 ECS からアクセス可能な Amazon Elastic Block Store(EBS) にためていく想定。

(1) 冗長性を高めてサービスの可用性を上げたい。ユーザー数増加にも耐えられるようにしたい。

Java アプリケーションを一台の EC2 インスタンスで動かすのは SPOF になりうるので、ECS のサービスに載せて冗長化することをご提案しました。Ruby on Rails も Java アプリケーションも、 ECS および EC2 で Auto Scaling を設定することで負荷に対して柔軟になります。
また、RDS は Multi-AZ を有効にするか、Amazon Aurora PostgreSQL を利用し Writer-Reader 構成にしてDBの自動フェイルオーバーを検討いただけるようにお話しました。
画像データはできれば Amazon S3 に格納し、Amazon CloudFront を通して配信することをおすすめしました。

(2) Amazon CloudFront で、ログイン済みのユーザーのみにプライベートなコンテンツを配信するなど、アクセス制限するには?

CloudFront の署名付き Cookie/URL の機能をご紹介しました。

(3) ログ、運用監視周りはどうするのがよい?

こちらの資料をもとに説明いたしました。

運用開始周り(41ページ以降を参照)

[AWS Start-up ゼミ / DevDay 編] よくある課題を一気に解説! 御社の技術レベルがアップする 2018 秋期講習

ログ周り(38ページ以降を参照)

[AWS Start-up ゼミ] よくある課題を一気に解説! 御社の技術レベルがアップする 2019 春期講習 補講&おかわり編

Q: チャットシステムをサーバーレスでプロトタイプ中。Amazon DynamoDB を WebSockets のセッション管理、Amazon DocumentDB をチャットデータの保存に考えている。DynamoDB と DocumentDB の設計レビューをしてほしい。

お伺いしたところ、以下のような機能要件がありました。

  • サービス運営者は複数人のサービス利用者と1 on 1チャットができる。
  • サービス運営者は現在開いている1 on 1チャットをリスト表示できる。
  • サービス利用者は一度に一人のサービス運営者と1 on 1チャットができる。

Amazon DynamoDB の設計レビュー

RDB のようにテーブルを分けたり、属性を正規化したりするのではなく、二つの属性を結合した値(例えば user_id#room_id の形式で、12345#12345 のような値を持つ属性)をキーにしたり、一つの Global Scondary Index に複数の意味の値を格納する GSI 多重定義を活用したテーブル設計について、以下の資料を参考にしながら議論しました。

【旧版・説明欄参照ください】 サーバーレスアプリケーション向きの DB 設計ベストプラクティス

Amazon DocumentDB の設計レビュー

ER 図の様に設計を行うのも可能ではあるが、そこからドキュメントデータベースのモデリングを最適化していくと、ER 図だけでは端的に表せなくなる点についてお話しました。例えば、一つのコレクションのオブジェクトに対して機能追加を行うごとにオブジェクトを追加する場合や、ファイル添付されたメッセージにファイルURLやファイル名をネストさせた構造をもたせる場合など。

また、基本的な考え方としてクエリの大小や、クエリ回数の多少によって、どのコレクションを分けるのか、コレクション同士をマージするのか、もしくは同一データを別コレクションに持つのかなどを検討する考え方についてお伝えしました。

20190625 AWS Black Belt Online Seminar Amazon DocumentDB

Amazon S3 にファイルをアップロードする際に、S3 からは AWS Lambda にのみアクセスを許し、 Lambda 経由でファイルをアップロードすることで安全性を確保したい。しかし、Lambda には 6MB のペイロードサイズ制限がある点が要件に合わない。どうすればよいか?

S3 へのアクセスを制御するその他の方法として、S3 の署名付き URL 機能 やバケットポリシーAmazon Cognito によるテンポラリクレデンシャルをご提示しました。また、Lambda のペイロードサイズ制限が問題になるのであれば、 代わりに AWS Fargate を使いつつ、各コンテナから S3 へのアクセス権限には Task Role を使えることをご提案しました。

Q: Laravel で作った Web アプリケーションが重い。一画面表示完了するのに4-5秒かかることがある。Amazon EC2 と Amazon RDS を使ったシンプルな構成。もしアプリケーションの問題なのであれば、インスタンスサイズを上げれば速くなるはずと思って EC2 を t2.small から t3.medium に変えてみたが大して変わらない。RDS も、db.t2.micro から db.t3.medium に変えたら CPU 使用率が 100% に張り付いていたのは収まったが、アプリケーション全体の重さは解決していない。

EC2、RDS のメトリクスを一緒に拝見しましたが、目立ったボトルネックは発生していなそうだったので、アプリケーションレイヤーでどこにどれだけ時間がかかっているのかログを見てみたい、という流れになりました(たとえば N+1 問題が発生していないか、どの処理にどれだけ時間がかかっているのか、など)。しかし、アプリケーションログを出してはいるけれど出すぎていてすぐに確認できない、という状態だったので、調査用ログの出し方、必要なログの追い方について提案させていただきました。

Q: Amazon Pinpoint では、複数デバイスを持つ一人の人間への通知はどうなる?それぞれのデバイスが別エンドポイントになるのであれば、それぞれのエンドポイントが別のセグメントに入ったりもする?

各デバイスは Pinpoint 上でそれぞれ別の Endpoint として扱われるので、 Endpoint ごとに属性が異なれば異なるセグメントに分類されることはあり得ます。つまり、異なるタイミングで各デバイスに通知が届いたりします。それ自体はいいことでも悪いことでもないので、そこはサービスとして、またはエンドユーザーとして本来どうあるべきかをご検討いただきたいです。

もし一人が持つ全デバイスに同時に通知を届けたいという場合、何らかの方法で(例えばサーバーサイドから API を叩くなどして)各 Endpoint の Attribute を同期してあげる必要があります。また、キャンペーンによる一斉配信でなく Direct Message の場合、 Users Messages API を使うことで、任意の Username を持つ複数の Endpoint 、つまり一人の人が持つ複数デバイスに一度に通知を送信することができます。

Q: (続き)Pinpoint でのデバイストークン管理について。エンドポイントのデバイストークンはどうやって更新できる?または、無効になったエンドポイントに通知を送らないようにするには?

Amplify、SDK を利用して実装している場合、新しいデバイストークンが取得されたときにエンドポイントが更新されるようになっています。

また、キャンペーンを送信した際に無効なエンドポイントを把握するには、Pinpoint のイベントストリームを設定することで、_campaign.send イベントの attributes.campaign_send_status で 'FAILURE_PERMANENT' という値が送られます。必要に応じてそれをキャッチして無効なデバイストークンを持つエンドポイントを把握し、削除処理を行っていただけます。

Q: マルチアカウントを管理する方法について。 AWS Organizations が使えるようだと聞いたのだが、具体的にどうするのがよいか。

AWS Organizations を使ったマルチアカウント環境の構築方法、マルチアカウントの構成例(Payer アカウントには AWS リソースは持たせない、ある 1 アカウント内にIAMユーザーをもって別アカウントは Switch Role で操作する、などのパターン)について議論しました。
現在社内で G Suite をお使いとのことだったので、 G Suite アカウントで AWS に SSO する方法の解説記事をご紹介しましたが、社員数が多く設定するのが大変とのことだったので AWS Single Sign-On のご利用を検討いただくようお願いしました。

Q: Amazon S3 にファイルがアップロードされたタイミングでキックされる AWS Lambda を設定しているが、正しく稼働していないので原因の調査をしたい。

Lambda のメトリクスとログを一緒に確認したところ、Lambda に付与されている IAM Role に適切な権限が設定されていませんでした。ご相談時点では S3 Full Access を付けていたのでうまくいっていたようですが、適切な権限の種類をご案内して、調整していただくことを案内しました。また、S3 バケットに IP アドレス制限を設けているとのことでしたが、要件として問題がないのかを確認し、Boto3 でアップロードクライアントを書いているとのことでしたので、適切な権限をアサインしてお使いいただくようにご案内しました。

その他、S3 からの Lambda Invoke が行われなかった場合について対応方法をお探しだったので、一つの例として処理前バケットと処理後バケットを分けて、処理が完全に終わった場合に処理前バケットから該当オブジェクトを消すアーキテクチャパターンをご紹介しました。

Q: Amazon S3にデータをアップロードする手順がイマイチわからない。どんな設定や情報が必要なのか教えて欲しい。

オンプレミスのサーバーからデータのアップロードを行うとのことなので、AWS IAM の認証情報を CLI 等から利用し、アップロードする手順、コマンドをご説明しました。
実際に S3 からコンテンツを公開することも考慮して、S3のバケットへのアクセス制御の手法についてお伝えし、署名つきURL/Cookieといった機能についても合わせてご案内しました。

Q: AWS Batch を使ったジョブワークロードで EC2 Spot インスタンスを使っているが、ジョブ実行中に terminate が発生した場合のジョブ管理や再実行について、一般的な手法を教えて欲しい。

AWS Batch のジョブのステータス管理が行える旨を説明し、ステータスの結果をもとに、処理の再実行を行うパターンをご案内しました。処理の中で独自にステータス管理を行いたい場合は、ご自分でジョブ内に処理ステータス管理を実装することも可能です。
また Spot Fleet についてもご説明し、より効率的な Spot インスタンスの管理方法もご検討いただけることとなりました。

Q: DynamoDB Streams を使い、テーブルに追加されたデータを随時 Lambda に渡して S3 に入れたいが、うまくいかない。

一緒にログやコードを見ていったところ、少なくとも Lambda ファンクションまでデータが渡っていること、ファンクション内で変数を展開する箇所で JavaScript の Key 指定エラーが出ていることが分かりました。取り出したい値がデータ内でネストされていたので、 forEach で目的の値を取り出すことを提案しました。

Q: ライブ配信サービスを開発中。配信中に、視聴者間で競い合いリアルタイムにランキングが表示されるようなシステムをサーバーレスで作りたい。3秒に一回程度ランキングを更新したい。視聴者側から配信者に、何らかのリアクションも伝えられるようにしたい。

Amazon API Gateway の WebSockets 機能、 AWS Lambda、Amazon ElastiCache Redis の Sorted Sets を使った構成をご提案しました。
構成クライアント(配信者|視聴者) -- API Gateway -- Lambda -- Redis(ランキング情報) | DynamoDB(WebSocketsセッション情報)

  • ランキング情報の更新・配信を実現するシーケンス案
    1. 視聴者から最新のスコアを WebSockets で送る
    2. Lambda は該当視聴者のスコアを zset 上でアップデートする
    3. Lambda は最新ランキング情報を取得し視聴者に Websocket で返す
    4. これを全視聴者が3秒ごとに繰り返す
  • 視聴者から配信者へのリアクションを実現する案
    1. 配信者が接続した際、Connection ID を DynamoDB に保管
    2. 視聴者側から、リアクション情報を Websocket に乗せて送信
    3. Lambda は DynamoDB から配信者の Connection ID を取得し、視聴者から送られてきたリアクション情報を配信者に WebSockets で送る

Lambda のコールドスタート等の考慮点についてはご理解の上で許容されるとのことでした。

週刊 Ask An Expert まとめ、今回はここまで

最後までお読み頂きありがとうございます!
冒頭に書いたように、似たご質問をまとめたり、端的にまとめづらいご質問を省いているためそっくりこのままやり取りが行われているわけではありませんが、様々なご相談をいただいていることが伝わっていれば嬉しいです。実際の Ask An Expert カウンターでは、より詳細なご案内・議論が行われています。
それではまた次回をお楽しみに!


このブログの著者

中武 優樹(Yuki Nakatake)
Blockchain、Database、Zabbix が好きなスタートアップ ソリューションアーキテクトです。