Upgrade to Pro — share decks privately, control downloads, hide ads and more …

gRPC Streaming によるスケーラブルな常時接続型 API の構築

gRPC Streaming によるスケーラブルな常時接続型 API の構築

常時接続型 API を構築するとき、 Go + gRPC Streaming はパフォーマンスに優れる有力な選択肢となります。しかしながら常時接続ゆえ、通常通信時間が短時間で終了する Web API とは異なる注意点があります。そこで本セッションでは、gRPC Streaming の紹介にはじまり、注意点やハマりポイントをご紹介します。また、GKE 上でオートスケールするオートモーティブ移動体情報配信システムを構築した事例をご紹介します。

avvmoto

July 13, 2019
Tweet

More Decks by avvmoto

Other Decks in Programming

Transcript

  1. GoConference’19
    gRPC Streaming による
    スケーラブルな常時接続型 API の構築
    Yutaka Imoto
    DeNA

    View Slide

  2. GoConference’19
    今日のお題: gRPC Streaming
    ● サービス紹介
    ● 直面したスケーラビリティの課題
    ● 解決策
    ● gRPC Streamingの紹介
    ● インフラ構成
    2

    View Slide

  3. GoConference’19
    弊社のタクシー配車サービス MOV
    3

    View Slide

  4. GoConference’19
    4

    View Slide

  5. GoConference’19
    5
    - スマホアプリでタクシーに配車依頼
    - 電話をかけなくてOK
    - 全車輌ネット決済対応
    - 事前のクレカ登録で、車内での支払い無し
    - 対応エリア現在拡大中
    - 東京、神奈川、大阪、京都

    View Slide

  6. GoConference’19
    アプリ画面
    ● ユーザーの現在地周辺の、配車可能な
    タクシーが表示される
    ● 3秒に1度、タクシーの位置が更新される
    ○ 動きはアニメーションで補完される
    6
    注:開発中のダミー画面です
    実際の車輌の位置情報は含みません

    View Slide

  7. GoConference’19
    パフォーマンスの課題
    7

    View Slide

  8. GoConference’19
    8
    アーキテクチャ

    View Slide

  9. GoConference’19
    9
    パフォーマンスに
    課題
    - DB に負荷のかかる処理
    重い!!!

    View Slide

  10. GoConference’19
    既存アーキテクチャの課題
    - DB に負荷の高い処理
    - ユーザーの近傍車輌の取得
    - 営業圏ポリゴン上にあるかどうかの判定
    - 配車禁止エリアポリゴン上にあるかどうかの判定
    - この処理がユーザー数に比例して発生
    - ユーザーアプリは3秒に一度 API を叩く
    - DBはスケールしにくいので、システム全体のスケーラビリティに課題
    - 突発的なアクセス増加に耐えられない
    - DBのインスタンス代が高い
    10

    View Slide

  11. GoConference’19
    解決策
    11

    View Slide

  12. GoConference’19
    MQTT
    3秒に1度 publish
    位置情報、タクシーの状態等
    - 無駄な計算を抑制したい
    - 車輌の情報が更新されたタイミングで、ポリゴン上にあるかどうかの判定したい
    - ユーザー数に応じて、オートスケールしたい
    - 車輌台数に応じて、オートスケールしたい
    - 車輌台数も一定の規模ある。対応地域拡大で一気に増える
    - 車輌搭載のAndroid 端末から、タクシーの位置やステータス ( e.g. 空車かどうか )が、3秒に一度送
    られてきている
    新アーキテクチャでやりたいこと
    12
    車輌情報配信システム

    View Slide

  13. GoConference’19
    新アーキテクチャ方針
    - アプリ→API間
    - アプリはAPI のポーリングはやめる
    - アプリはAPI と常時接続する Push 型 API とする
    - アプリは配車可能な車輌のみを API から Push され受けとる
    - 車輌情報配信システム→API間
    - 必要最小限の回数のみ、ポリゴン判定したい
    - こちらも常時接続型API とし、車輌情報が送られてきたら、配車可能なもののみ配信する
    - ユーザ側と車輌側でスケールの観点が異なるので、APIのプロセスを分け、それぞ
    れ別にスケールさせたい
    13

    View Slide

  14. GoConference’19
    新アーキテクチャ 概要
    - 新システムは、gRPC Streaming とRedis PubSubを活用する
    - ユーザーに、ユーザー近辺の車輌情報を配信する Subscribe Server
    - 車輌情報を受け取り、メッシュ判定等をし、配車可能なものを配信する Publish Server
    - 地図を1km四方に細分化し(3次メッシュ)、その領域中の車輌情報を配信する Redis PubSub の
    channelを用意する
    14
    車輌情報配信システム
    gRPC Streaming
    gRPC Streaming
    Publish
    Subscribe

    View Slide

  15. GoConference’19
    Redis Pubsub
    - Redis は インメモリ KVS として有名だが、Pub/Sub 機能もある
    - メッセージのqueueing はしない。Publishする時点で、Subscribeしている クライアントにだけ伝達され
    る。
    - 今回は Redis を Pub/Sub 機能のみ利用。データの永続化はしない。
    15
    source: https://aws.amazon.com/jp/pub-sub-messaging/

    View Slide

  16. GoConference’19
    新アーキテクチャ 全体像
    16










    Cloud Load
    Balancing
    Publish
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    Cloud Load
    Balancing
    gRPC
    Publish
    Server
    Kubernetes
    Publish
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    gRPC
    gRPC
    gRPC
    Publish Server
    車輌台数に応じた
    オートスケール
    Redis Cluster
    シャード負荷に
    応じてスケール
    Subscribe Server
    ユーザーに応じた
    オートスケール
    ユーザーアプリ

    View Slide

  17. GoConference’19
    新アーキテクチャ 全体像
    17










    Cloud Load
    Balancing
    Publish
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    Cloud Load
    Balancing
    gRPC
    Publish
    Server
    Kubernetes
    Publish
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    gRPC
    gRPC
    gRPC
    Publish Server
    車輌台数に応じた
    オートスケール
    Redis Cluster
    シャード負荷に
    応じてスケール
    Subscribe Server
    ユーザーに応じた
    オートスケール
    ユーザーアプリ
    - 必要な箇所が必要なだけスケール!
    - DB がボトルネックとなることを回避できた!
    - コスト削減!

    View Slide

  18. GoConference’19
    gRPC Streaming について
    18

    View Slide

  19. GoConference’19
    gRPC とは
    - Google 製、多言語/多 Platform の RPC フレームワーク
    - クライアントは別のマシンのサーバーのメソッドをローカルオブジェクトのように直接
    呼び出す
    - シリアライザにProtocol Buffers
    - コードジェネレーター
    - 通信は HTTP/2 経由で行う
    19
    19
    source: https://grpc.io/docs/guides/

    View Slide

  20. GoConference’19
    gRPC の通信方式
    - 4分類
    - Unary RPC
    - Server streaming RPC
    - Client streaming RPC
    - Bidirectional streaming RPC
    20

    View Slide

  21. GoConference’19
    gRPC の通信方式
    - Unary RPC
    - Unary = 単項
    - Request : Response = (1, 1)
    21
    source: https://qiita.com/yuzo777/items/046910c95559cf0fff68

    View Slide

  22. GoConference’19
    gRPC の通信方式
    - Server streaming RPC
    - サーバーは1 Request に対し、複数の Response を一連の応答として返す
    - サーバーは、すべての応答を送り返した後、サーバー側のステータス等を返して完了
    - クライアントは、すべてのサーバーの応答を受信したら完了。タイムアウトも設定可
    22
    source: https://qiita.com/yuzo777/items/046910c95559cf0fff68

    View Slide

  23. GoConference’19
    gRPC の通信方式
    - Client streaming RPC
    - 今度は、クライアントが単一のリクエストではなく、複数の一連のリクエストをサーバーに送信する
    - サーバーは単一の応答を返す
    - サーバーはすべてのリクエストを受け取る前に、レスポンスを返しても良い
    23
    source: https://qiita.com/yuzo777/items/046910c95559cf0fff68

    View Slide

  24. GoConference’19
    gRPC の通信方式
    - Bidirectional streaming RPC
    - リクエストとレスポンスがそれぞれ複数
    - リクエストもレスポンスのタイミングは独立している。同期してもしなくてもよい
    24
    source: https://qiita.com/yuzo777/items/046910c95559cf0fff68

    View Slide

  25. GoConference’19
    今回用いた gRPC の通信方式
    25
    車輌情報配信システム
    gRPC Streaming
    gRPC Streaming
    Publish
    Subscribe
    Client streaming gRPC
    Server streaming gRPC

    View Slide

  26. GoConference’19
    gRPC Hello World
    26

    View Slide

  27. GoConference’19
    gRPC Hello World
    - Unary RPCのものをみてみましょう
    - proto ファイルの定義
    - proto ファイルから Go のコードを生成
    - gRPC サーバー・クライアントの実装
    - Server Streaming RPC の場合
    27

    View Slide

  28. GoConference’19
    proto の定義
    28
    source: https://grpc.io/docs/quickstart/go/

    View Slide

  29. GoConference’19
    proto ファイルから Go のコードを生成
    29
    source: https://grpc.io/docs/quickstart/go/

    View Slide

  30. GoConference’19
    source: https://grpc.io/docs/quickstart/go/
    proto ファイルから Go のコードを生成
    - request/response 用の struct
    30

    View Slide

  31. GoConference’19
    proto ファイルから Go のコードを生成
    - server用の interface
    - client 用のinterface
    31
    source: https://grpc.io/docs/quickstart/go/

    View Slide

  32. GoConference’19
    Server Streaming RPC の場合
    - Server interface
    - Client interface
    - Recv() が (nil, io.EOF) で
    サーバー側完了
    32
    source: https://grpc.io/docs/reference/go/generated-code/

    View Slide

  33. GoConference’19
    今回のサーバーの実装について
    33

    View Slide

  34. GoConference’19
    Subscribe Server
    - ユーザーアプリが接続する API
    - あるエリアの配車可能な車輌情報を 3秒に一度返す
    - Server Streaming RPC として実装
    - 今回はレスポンスに終わりはないので、サーバーに明示的に終了を告げる口を用意
    している
    -
    34

    View Slide

  35. GoConference’19
    Publish Server
    - 車輌情報が打ち上げられるAPI
    - Client Streaming RPC として実装
    -
    35

    View Slide

  36. GoConference’19
    Go で良かった点
    - 簡単にサーバーのCPU リソースを限界まで使うことが出来た
    - よしなにサーバーへの接続数を増やしても、 内部で goroutine が適切にスケジューリングされる
    - ワーカー数の調整など、特にチューニング作業することなく、限界まで CPUリソースを使うことができ

    - これにより、簡単にサーバー 1台あたりのユーザー数を増やすことができた
    - 今回のように CPU ヘビーな API であり、 CPU 使用率でオートスケールする構成に
    はありがたい
    36

    View Slide

  37. GoConference’19
    インフラ構成
    37

    View Slide

  38. GoConference’19
    インフラ構成
    - 方針
    - なるべくマネージドなクラウドサービスを使う
    - 負荷に応じたオートスケール
    - APIサーバー
    - API サーバーのバックエンドには、 GCP の Kubernetes Engine, GKE を採用
    - CPU 使用率に応じ、HPA でオートスケール
    - Redis サーバー
    - GKE 上に Redis Cluster を自前で構築・運用
    - 本当は マネージド・サービスである Google Cloud Pub/Sub を用いたかったが、レイテンシーの要
    件を満たせず断念
    38

    View Slide

  39. GoConference’19
    ロードバランサーについて
    - 課題
    - オートスケールしても負荷の偏りが持続する問題
    - gRPC Streaming に対応する クラウドの LB はどれだ問題
    39

    View Slide

  40. GoConference’19
    LB について / 負荷の偏りが持続する問題
    40
    Cloud Load
    Balancing
    Subscribe
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    オートスケールしても
    既存の接続はそのまま持続し
    新しい Pod に向き直したりしない
    Subscribe
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    Subscribe
    Server
    Kubernetes
    Cloud Load
    Balancing
    オートスケール!
    サーバーとユーザー間の接続が持続している

    View Slide

  41. GoConference’19
    - 課題
    - オートスケールしても既存 Pod の負荷が下がらない
    - 接続が持続しているため、既存ユーザの接続は新しい Pod に向かない
    - 対策
    - 長期間接続が発生する部分では、定期的に切断 &再接続処理を行う
    - 今回
    - Subscribe Server → アプリの仕様として、長いコネクションは発生しない想定
    - Publish Server → 定期的に切断&再接続
    - Redis → 定期的に切断&再接続
    LB について / 負荷の偏りが持続する問題
    41

    View Slide

  42. GoConference’19
    gRPC Streaming に対応する LB
    - GKE
    - Ingress
    - BETA
    - ReadinessProbe が httpGet でのみ動作する。gRPC 層でヘルスチェックできない 。
    httpGet での実装・検証事例はある [1]
    - LoadBalancer Service
    - BETA ではない [2]
    - `protocol: "TCP"` で、L4LBとして動かす
    - Ingress とは違い、SSL 終端は自前で行う必要がある
    - 今回はこちらを採用
    - ReadinessProbe で exec を利用し、gRPC 層でヘルスチェックできる
    42
    [1]GKE gRPC Ingress LoadBalancing https://medium.com/google-cloud/gke-grpc-ingress-loadbalancing-4b9cdbc09758
    [2]https://cloud.google.com/kubernetes-engine/docs/concepts/service

    View Slide

  43. GoConference’19
    まとめ
    43

    View Slide

  44. GoConference’19
    - gRPC Streaming + Go で スケーラブルな常時接続型 API を作った事例紹介を
    しました
    - 弊社のタクシー配車アプリにて、ポーリング型からPush型の常時接続APIに変更す
    ることで、スケール可能かつ低コスト化を達成した
    - gRPC Streaming をクラウドサービスで実現するためには、対応状況を見極める必
    要がある
    - 特に LB 周り
    まとめ
    44

    View Slide