クックパッドの動画事業での AWS AppSync 活用事例 / Practical use of AWS AppSync by Cookpad

6704ebed2f7a40a97741b69657a967d6?s=47 wata
October 31, 2018

クックパッドの動画事業での AWS AppSync 活用事例 / Practical use of AWS AppSync by Cookpad

6704ebed2f7a40a97741b69657a967d6?s=128

wata

October 31, 2018
Tweet

Transcript

  1. 6.

    AWS Cloud AWS AppSync • GraphQL + MQTT over Websockets

    ◦ Mutation ◦ Query ◦ Subscription • Amazon Cognito による認証 • Data Source ◦ Amazon Elasticsearch ◦ Amazon DynamoDB ◦ AWS Lambda Authenticate GraphQL
  2. 8.

    cookpadTV • コンセプト ◦ 「一緒につくれるクックパッド」 • 特徴 ◦ クッキング LIVE

    アプリ ◦ 有名人やプロと一緒に料理が出来る ◦ コメント機能で質問が出来る • 提供プラットフォーム ◦ iOS/Android/FireTV cookpadtv
  3. 12.

    なぜ移行したのか • データを AWS と Firebase に分散させたくなかった • AWS AppSync

    は DynamoDB、Lambda 等コントローラブルな面が多い ◦ DynamoDB に入っていれば管理画面から参照できる ◦ Lambda に繋げば後は自由
  4. 13.

    移行時の課題 • iOS/Android SDK の品質問題 ◦ 当初は React / React

    Native 利用が主だった? ◦ 複数 subscription が考慮されていなかった ◦ 5 月中旬から結局 10 月まで修正にかかった • Subscribe 時に最新のデータが取得されない ◦ 必要な場合は自ら Query する必要がある • それ以外は大きな問題もなく移行出来た ◦ Firebase -> AppSync 切替時はアプリの強制アップデートで一気に切り替え
  5. 15.
  6. 16.

    WRITE はサーバー経由、READ は直接 • コメントは NG ワードのフィルタリングや、アカウント BAN したい •

    スタンプはポイントが必要なのでポイントのチェックが必要 cookpadTV comment Filter NG comment comment NG comment NG comment
  7. 18.

    AWS AppSync 利用時のボトルネック • Amazon Cognito の制限 ◦ GetCredentialsForIdentity の同時実行数

    ◦ LIVE 配信は同時にユーザが来るので Cognito の処理で詰まる可能性がある ◦ API Key を利用すればこの制限は無い • Mutation per second 制限 ◦ かなり高いのでほとんどのケースでは問題ない • AWS AppSync からアプリへのファンアウト数 ◦ かなり高いのでほとんどのケースでは問題ない ◦ 10 万人の Subscriber がいると 10 メッセージが 100 万のファンアウトになる ◦ 細かいメッセージをたくさん飛ばすより、ある程度バッファリングした方が良い
  8. 20.

    AWS Cloud cookpadTV での AWS AppSync の使い方(詳細) cookpadTV API Point

    System cookpadTV message cookpadTV MBR check user’s points comment heart user count stamp 参考:https://speakerdeck.com/osadake212/cookpad-tech-kitchen-number-15
  9. 21.

    Service Mesh • Microservices で必須になりつつある Service Mesh ◦ 参考:クックパッド開発者ブログ Service

    Mesh and Cookpad ▪ https://techlife.cookpad.com/entry/2018/05/08/080000 ◦ クックパッドでは Microservices 対応の環境が整備されている為、積極的に分けている • Service Mesh とは ◦ SDK 実装ではなく Sidecar Proxy(Envoy) 経由で通信する ◦ Sidecar Proxy を管理、コントロール ▪ 接続先や Timeout、Retry 設定など app envoy Other Service
  10. 22.

    cookpad Service Mesh app envoy sds-register client side LB app

    server side LB app kumonos CDS/RDS updates SDS updates SDS registration hook Developers SDS 参考:https://speakerdeck.com/taiki45/observability-service-mesh-and-microservices 接続したい Service 名を渡す
  11. 23.

    cookpadTV サービス群 cookpadTV’s Service Mesh cookpadTV API Point System cookpadTV

    message cookpadTV MBR Accouting Auth cookpad API User Other services クックパッド基盤サービス群 外部サービスも Service Mesh に追加
  12. 24.

    cookpadTV message and MBR • クックパッドは Ruby だけ? ◦ 実情としては必要に応じて色々言語を使っている

    ▪ Ruby, Java, Go, Rust • メッセージ送信サービスは Go で実装 ◦ 高スループット ◦ プロトコルに gRPC を選択
  13. 25.

    cookpadTV MBW • MBW? ◦ Message Buffer Writer の略 •

    なぜ必要に? ◦ AWS AppSync への mutations per seconds を軽減させるため ◦ 某声優が出演した回では 47 分放送でハートが約 150 万回送信された ▪ 単純計算 150 万 ÷ 47 分 ÷ 60 ≒ 平均 532 rps ◦ iOS/Android アプリ側への負荷軽減 • 通信プロトコル gRPC ◦ 純粋な Go server & gRPC only は社内初
  14. 26.

    cookpadTV MBW 設計方針 • コメント反映をなるべくは遅らせない ◦ 流量によってバッファリング量、 Flush タイミングをコントロール •

    コメントの順序保証は行わない ◦ 複数台でバッファリングすると前後することもある • 最悪データのロストを許容 ◦ 永続化は別で行っている ◦ リアルタイム性が無いコメントはあまり意味がない ◦ ストレージ不要でオンメモリで処理が可能 • Subscribe で流れてくるメッセージは番組毎 ◦ 同時放送してもアプリ側でフィルタリングするのではなくサーバ側で送信し分ける
  15. 28.

    負荷試験 • 目標数値を設定し負荷試験を行うこと に ◦ 合わせて 2,150 rps 以上出す •

    gRPC の負荷試験の経験無し ◦ そもそも gRPC はどの程度パフォーマンスが 出るのかも知らない • やってみたらそれなりに速い ◦ 別サーバへの gRPC リクエストは 1ms 掛か らなかった
  16. 29.

    gRPC 負荷試験 • 負荷試験用のツールとしては ghz を採用 ◦ https://github.com/bojand/ghz • 特徴

    ◦ proto ファイルを渡して負荷を掛けられる ◦ 同時リクエスト数等、細かく負荷の掛け方が指定出来る ◦ Summary や Histogram を出してくれるので便利 • 複数の load の同時実行は未対応 ◦ スクリプトでまとめてもらった ◦ Run Multiple gRPC Load Testing using ghz ▪ http://itiskj.hatenablog.com/entry/2018/09/14/122110 実行例) ghz -proto messages.proto -call cookpad_tv_mbw.Comment -D Comment.json -M metadata.json -o Comment.log -n 10000 -q 5000 -insecure [IP Address]:[Port]
  17. 30.
  18. 31.

    average 36.16 ms fastest 6.15ms slowest 98.40ms Requests/sec 1,375.29 初計測

    (メッセージのハンドリングはしているが、AppSync 未書き込み)
  19. 33.
  20. 35.
  21. 36.

    諸々チューニング • 目標としたスループットが出せるようになったので一段落 ◦ 冗長化の為に 2 台構成にする想定なので 1,331 × 2

    = 2,662rps • 後は時間が許す限り最適化 ◦ 排他制御周りの最適化、 Go の channel と goroutine を上手く活用方法を模索する
  22. 37.
  23. 38.

    average 5.22(-30.94) fastest 0.16ms(-5.99) slowest 36.05ms(-62.35) Requests/sec 8,855.64(+7480.35) 最適化後 Response

    time histogram: 0.162 [1] | 3.751 [3638] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎ 7.340 [4344] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎ 10.930 [1532] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎ 14.519 [311] |∎∎∎ 18.108 [104] |∎ 21.697 [31] | 25.286 [17] | 28.875 [19] | 32.464 [1] | 36.053 [2] | Latency distribution: 10% in 1.86 ms 25% in 2.97 ms 50% in 4.67 ms 75% in 6.76 ms 90% in 8.99 ms 95% in 10.85 ms 99% in 17.29 ms Status code distribution: [OK] 10000 responses
  24. 41.

    Comment Worker 凡例 cookpadTV MBW 設計(コメント部分) Request Handler Interval Worker

    Write Worker Flush Worker time.AfterFunc Post has buffer? buffer over threshold? Post Worker channel goroutine Buffer store comment get buffer length get buffer length Post Post Buffered Channel Buffered Channel 数分 同時起動
  25. 42.

    凡例 cookpadTV MBW 設計(全体) Request Handler Post Post Worker channel

    goroutine Post Post Buffered Channel Buffered Channel 数分 同時起動 Comment Worker Heart Worker Stamp Worker User Count Worker AWS AppSync への同 時送信数を制御
  26. 44.
  27. 45.
  28. 47.

    AWS AppSync Schema • 複数 Subscriptions ◦ コメント、ハート、スタンプ、ユーザー数はそれぞれ別 Subscriptions ◦

    1 つの Subscription で複数のメッセージをやり取りするのではなく別々に ▪ 古いアプリのバージョンでも知らないメッセージが送られてくることはない • 受信データは配列 ◦ サーバ側でバッファリング出来る様に 2424 Hearts Comments Stamps User Count 別 Subscriptions
  29. 48.

    Schema 定義 type Comment { episodeId: Int! commentKey: String! postedAt:

    String! text: String! userId: Int! userName: String! userIconImageUrl: String! } type CommentList { episodeId: Int! comments: [Comment] } type Mutation { putComments(episodeId: Int!, comments: [CommentInput]): CommentList } type Subscription { onPutComments(episodeId: Int!): CommentList @aws_subscribe(mutations: ["putComments"]) } episodeId 毎
  30. 49.

    AWS AppSync Resolver • 当初は DynamoDB Data source を使用 ◦

    負荷試験で、DynamoDB の write がボトルネックに ◦ Batch Write Item 利用を検討 → 25 件が最大なので不採用 ▪ スタンプはこちらを採用、バッファリングも 25 件に ◦ 複数のメッセージを 1 レコードに書き込む→取り回しが不便なので不採用 ◦ 多段 Lambda で DynamoDB への書き込みを非同期に → そこまでする必要無いので不採用 • 結局 Data Source type None に ◦ 永続化は別の仕組みで行っているのでここで永続化する必要はない ▪ デメリットとして LIVE 視聴開始時に少し前のコメントを出すことが出来ない ◦ 何より速い! ◦ Kinesis Data Stream Data Source type の登場に期待
  31. 50.
  32. 51.

    Pitfalls • クライアント側 ◦ クライアントの時間がずれていると送受信出来ない ▪ シミュレータで開発しているとたまにハマる ◦ Android SDK

    は再接続を自分でやらないといけない • サーバ側 ◦ 同時接続数、リクエスト数などのメトリクスが見れない ◦ Schema 定義の更新が怖い ◦ サーバ側から書き込みが想定されていないので自前で実装する必要がある
  33. 52.
  34. 53.

    まとめ • cookpadTV で AWS AppSync の活用事例を紹介 • 高頻度 mutation

    対応の為に、Service Mesh を利用したバッファリングサービ スの導入 • Schema や Resolver 設計の実例