Slide 1

Slide 1 text

クックパッドの動画事業での AWS AppSync 活用事例 ーFirebase からの移行ー 2018-10-31 wata

Slide 2

Slide 2 text

自己紹介 wata(渡辺 慎也) ● クックパッド株式会社 ○ メディアプロダクト開発部部長 ● CookpadTV株式会社 ○ 取締役 CTO @wata_dev wata-gh

Slide 3

Slide 3 text

CookpadTV 株式会社

Slide 4

Slide 4 text

CookpadTV 事業

Slide 5

Slide 5 text

AWS AppSync

Slide 6

Slide 6 text

AWS Cloud AWS AppSync ● GraphQL + MQTT over Websockets ○ Mutation ○ Query ○ Subscription ● Amazon Cognito による認証 ● Data Source ○ Amazon Elasticsearch ○ Amazon DynamoDB ○ AWS Lambda Authenticate GraphQL

Slide 7

Slide 7 text

cookpadTV

Slide 8

Slide 8 text

cookpadTV ● コンセプト ○ 「一緒につくれるクックパッド」 ● 特徴 ○ クッキング LIVE アプリ ○ 有名人やプロと一緒に料理が出来る ○ コメント機能で質問が出来る ● 提供プラットフォーム ○ iOS/Android/FireTV cookpadtv

Slide 9

Slide 9 text

cookpadTV での AWS AppSync 利用シーン 2424 Hearts Comments Stamps User Count

Slide 10

Slide 10 text

Firebase Realtime Database からの移行

Slide 11

Slide 11 text

経緯 ● 当初は Firebase Realtime Database を利用してコメント、ハートを実装 ○ 自前ではなくマネージサービスを利用したかった ● AWS AppSync はまだアジアパシフィック(東京)には来ていなかった

Slide 12

Slide 12 text

なぜ移行したのか ● データを AWS と Firebase に分散させたくなかった ● AWS AppSync は DynamoDB、Lambda 等コントローラブルな面が多い ○ DynamoDB に入っていれば管理画面から参照できる ○ Lambda に繋げば後は自由

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

cookpadTV での AWS AppSync の使い方(概要)

Slide 15

Slide 15 text

cookpadTV での AWS AppSync の使い方(概要) Mobile client cookpadTV MQTT protocol HTTP protocol subscribe READ WRITE comment comment Auth

Slide 16

Slide 16 text

WRITE はサーバー経由、READ は直接 ● コメントは NG ワードのフィルタリングや、アカウント BAN したい ● スタンプはポイントが必要なのでポイントのチェックが必要 cookpadTV comment Filter NG comment comment NG comment NG comment

Slide 17

Slide 17 text

AWS AppSync 利用時の ボトルネック

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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 名を渡す

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

cookpadTV message and MBR ● クックパッドは Ruby だけ? ○ 実情としては必要に応じて色々言語を使っている ■ Ruby, Java, Go, Rust ● メッセージ送信サービスは Go で実装 ○ 高スループット ○ プロトコルに gRPC を選択

Slide 25

Slide 25 text

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 は社内初

Slide 26

Slide 26 text

cookpadTV MBW 設計方針 ● コメント反映をなるべくは遅らせない ○ 流量によってバッファリング量、 Flush タイミングをコントロール ● コメントの順序保証は行わない ○ 複数台でバッファリングすると前後することもある ● 最悪データのロストを許容 ○ 永続化は別で行っている ○ リアルタイム性が無いコメントはあまり意味がない ○ ストレージ不要でオンメモリで処理が可能 ● Subscribe で流れてくるメッセージは番組毎 ○ 同時放送してもアプリ側でフィルタリングするのではなくサーバ側で送信し分ける

Slide 27

Slide 27 text

DesignDoc を作成

Slide 28

Slide 28 text

負荷試験 ● 目標数値を設定し負荷試験を行うこと に ○ 合わせて 2,150 rps 以上出す ● gRPC の負荷試験の経験無し ○ そもそも gRPC はどの程度パフォーマンスが 出るのかも知らない ● やってみたらそれなりに速い ○ 別サーバへの gRPC リクエストは 1ms 掛か らなかった

Slide 29

Slide 29 text

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]

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

average 36.16 ms fastest 6.15ms slowest 98.40ms Requests/sec 1,375.29 初計測 (メッセージのハンドリングはしているが、AppSync 未書き込み)

Slide 32

Slide 32 text

average 218.62ms(+182.46) fastest 0.48ms(-5.67) slowest 2451.87ms(+2353.47) Requests/sec 227.26(-1148.03) AWS AppSync 書き込み開始時

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

average 52.33(+16.17) fastest 2.37ms(-3.78) slowest 163.78ms(+65.38) Requests/sec 1,331.10(-44.19) 一通り実装完了後

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

諸々チューニング ● 目標としたスループットが出せるようになったので一段落 ○ 冗長化の為に 2 台構成にする想定なので 1,331 × 2 = 2,662rps ● 後は時間が許す限り最適化 ○ 排他制御周りの最適化、 Go の channel と goroutine を上手く活用方法を模索する

Slide 37

Slide 37 text

結果

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

MBW チューニングの軌跡 AppSync 書き込み開始 オンメモリ化 最適化後

Slide 40

Slide 40 text

MBW 最適化後設計

Slide 41

Slide 41 text

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 数分 同時起動

Slide 42

Slide 42 text

凡例 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 への同 時送信数を制御

Slide 43

Slide 43 text

cookpadTV message cookpadTV MBW AWS AppSync

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

AWS AppSync Schema, Resolver

Slide 47

Slide 47 text

AWS AppSync Schema ● 複数 Subscriptions ○ コメント、ハート、スタンプ、ユーザー数はそれぞれ別 Subscriptions ○ 1 つの Subscription で複数のメッセージをやり取りするのではなく別々に ■ 古いアプリのバージョンでも知らないメッセージが送られてくることはない ● 受信データは配列 ○ サーバ側でバッファリング出来る様に 2424 Hearts Comments Stamps User Count 別 Subscriptions

Slide 48

Slide 48 text

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 毎

Slide 49

Slide 49 text

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 の登場に期待

Slide 50

Slide 50 text

Pitfalls

Slide 51

Slide 51 text

Pitfalls ● クライアント側 ○ クライアントの時間がずれていると送受信出来ない ■ シミュレータで開発しているとたまにハマる ○ Android SDK は再接続を自分でやらないといけない ● サーバ側 ○ 同時接続数、リクエスト数などのメトリクスが見れない ○ Schema 定義の更新が怖い ○ サーバ側から書き込みが想定されていないので自前で実装する必要がある

Slide 52

Slide 52 text

まとめ

Slide 53

Slide 53 text

まとめ ● cookpadTV で AWS AppSync の活用事例を紹介 ● 高頻度 mutation 対応の為に、Service Mesh を利用したバッファリングサービ スの導入 ● Schema や Resolver 設計の実例

Slide 54

Slide 54 text

We are hiring!