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

gRPC in Cookpad

Yuta Iwama
November 28, 2018

gRPC in Cookpad

Cookpad Tech Kitchen #20 クックパッドのマイクロサービスプラットフォーム現状 https://cookpad.connpass.com/event/106913/

Yuta Iwama

November 28, 2018
Tweet

More Decks by Yuta Iwama

Other Decks in Technology

Transcript

  1. これまでの Cookpad • Cookpad ではマイクロサービスを推進してきた • 社内では Garage, GarageClient で

    API 共通化 • Autodoc でドキュメンテーション • 参考 ◦ https://speakerdeck.com/eagletmt/web-application-development-in-cookpad-2017 ◦ https://speakerdeck.com/adorechic/how-cookpad-shifts-to-microservices
  2. gRPC 導入理由 • IDL とスキーマがほしい ◦ 各フィールドの型を定義、参照したい • REST なエンドポイントへのマッピングが困難

    ◦ サービス間通信は REST よりも RPC のほうが適している事が多い • 多言語化 ◦ Ruby 以外の言語の使用実績の増加
  3. gRPC • オープンソースの RPC フレームワーク • IDL として Protocol Buffers

    が使える • Protocol Buffers で定義を書くとクライアント、サーバのコードを生成 • 様々な言語で実装が存在する • https://grpc.io
  4. gRPC(2) • HTTP2 上で動作 ◦ https://github.com/grpc/grpc/blob/v1.17.0-pre2/doc/PROTOCOL-HTTP2.md • 4種類の RPC ◦

    Unary RPC ◦ Server streaming RPC ◦ Client streaming RPC ◦ Bidirectional streaming RPC • Interceptor でログ、認証、エラー処理など
  5. Cookpad の gRPC アプリケーション動作環境 • 基本的に hako 上で動作 • cookpad.com

    でも使用 • cookpad/sds + Envoy を使用して Client side Loadbalancing ◦ https://blog.envoyproxy.io/service-mesh-and-cookpad-ba4d5d915dbd ◦ Envoy の load_balancing_weight を使って Slow Start をサポート • Envoy 経由でリクエストをうける • 開発環境から staging 環境へのアクセスも許可
  6. Cookpad の gRPC 動作環境(サービスイン) cookpad/sds registrator コンテナが service 起動時に front-envoy

    のエンドポイントを登録 (e.g. 10.0.0.1:77777) app Service A envoy front-envoy サービス名 エンドポイント weight Service B 10.0.0.1:6789 100 Service C 10.0.0.1:7896 100 Service A 10.0.0.1:7777 100 registrator
  7. Cookpad の gRPC 動作環境(Slow Start) cookpad/sds app Service A envoy

    front-envoy サービス名 エンドポイント weight Service B 10.0.0.1:6789 100 Service C 10.0.0.1:7896 100 Service A 10.0.0.1:7777 2 registrator コンテナが weight を徐々に大きくしていく registrator
  8. Cookpad の gRPC 動作環境(Running) cookpad/sds 1. 定期的に registrator コンテナが app

    に health check 2. health check がとおったら sds に再登録 app Service A envoy front-envoy registrator サービス名 エンドポイント weight Service B 10.0.0.1:6789 100 Service C 10.0.0.1:7896 100 Service A 10.0.0.1:7777 100
  9. app Service A envoy front-envoy Cookpad の gRPC 動作環境(通信) envoy

    が定期的に sds を見に 行って リクエスト先を見つける app Service B envoy front-envoy cookpad/sds
  10. Cookpad の gRPC 動作環境(サービスアウト) cookpad/sds registrator コンテナが service 終了時に front-envoy

    のエンドポイントを削除 app Service A envoy front-envoy サービス名 エンドポイント weight Service B 10.0.0.1:6789 100 Service C 10.0.0.1:7896 100 registrator
  11. サービス定義(Protocol Buffers) の管理 • 一つのリポジトリで管理 • サービスごとにディレクトリを切る運用 ◦ service A

    のサービス定義だったら service_a/ 以下に定義を記述 • 使用したいアプリケーションは git submodule で使用 • ckaznocha/protoc-gen-lint による Lint • pseudomuto/protoc-gen-doc を使って自動でドキュメント生成 ◦ hako-console にドキュメントへのリンクを配置 Web アプリケーションを把握するためのコンソール , https://techlife.cookpad.com/entry/2018/04/02/140846
  12. メトリクス • 前述の2つの Envoy コンテナでメトリクスをとっている ◦ Envoy Stats https://blog.envoyproxy.io/envoy-stats-b65c7f363342 ◦

    アクセスログ • メトリクス、ログ情報を Prometheus に入れており grafana でみれる • アクセスログに対して google/mtail を使用して Prometheus から読めるように している • hako-console に grafana へのリンクを配置
  13. Prometheus w/ envoy アクセスログ • サービス開発者が(ほぼ)何もしなくても動作 • front-envoy コンテナが mtail

    コンテナをマウント ◦ mtail が envoy のアクセスログ Prometheus 用に出力 ◦ https://github.com/ganmacs/prom-mtail-test • ECS 上のサービスディスカバリーサービス(sds)を作成 ◦ Prometheus が sds をもとに mtail コンテナを見つける app Service A envoy front-envoy mtail
  14. grpc gem • C と C++ で作られたものを Ruby の拡張ライブラリとして使用 ◦

    grpc/grpc は C++, Python, Ruby, Objective-C, PHP, C# をサポートしている • grpc gem はマルチスレッド (シングルプロセス) ◦ Ruby には GIL があるので並列に動かない ◦ マルチプロセス化は直近のロードマップになさそう ▪ https://github.com/grpc/grpc/issues/15334 • https://rubygems.org/gems/grpc/
  15. Ruby で gRPC in Cookpad • 公式の gRPC 実装を使用 ◦

    bigcommerce/gruf みたいなフレームワークは使ってない • アプリケーションレイヤーでアクセスログが取れないので Interceptor を自作 • シグナルを受けると死んでしまうので起動/停止を行うライブラリを自作 ◦ https://github.com/grpc/grpc/issues/14043 • その他様々な Interceptor を自作 ◦ 例外処理 ◦ New Relic などのツールもサポートされてないので interceptor として自作 ◦ Go の grpc-ecosystem/go-grpc-middleware みたいなもの
  16. Ruby on Rails で gRPC in Cookpad • app/ 以下にサービス定義を配置

    • lib/ 以下に自動生成コードを配置 • config/initializers に gRPC の設定を配置 ◦ Listen ポート、Interceptor の設定など • 起動には rails runner を使用している ◦ e.g. $ bundle exec rails runner run_grpc_server.rb ◦ 最初は rake task を作成していたが eager_load 周りでハマりどころが多い ◦ https://github.com/rails/rails/blob/v5.2.1/railties/lib/rails/application.rb#L518 • ActiveRecord の connection pool との相性
  17. grpc gem と ActiveRecord • grpc gem はマルチスレッド(シングルプロセス) • interceptor

    で AR の connection pool から pickup して終わったら返す ◦ 並行数の上限が connection pool 数になる
  18. grpc gem の問題 • CPU を使い切れない ◦ オートスケールが他のアプリに比べてうまくいかない ◦ スケールアウトするより先に

    gRPC の ResourceExhausted エラーが発生する • Graceful Shutdown がない ◦ 急にサーバが死ぬので Envoy を使ってサービスアウトしてからサービスを止めている ◦ 当然ストリーム系の Graceful shutdown もない • その他いろいろ
  19. griffin • 自作の gRPC ライブラリ • https://github.com/ganmacs/griffin ◦ nghttp2 を使用して作成

    • grpc gem との互換性を気にした ◦ Protocol Buffers から生成されるコードをそのまま使用できる ◦ grpc gem が改善されたら戻れるように • 社内のアプリで動き出している ◦ 現在移行中 • unary RPC のベンチマークでは griffin のほうが早い ◦ https://gist.github.com/ganmacs/5c7857b03ee80cf78e638f2a2a74fe01
  20. まとめ • Cookpad ではサービス間通信に gRPC を使うようになってきた • Envoy を活用して gRPC

    サービスの基盤を構成している • Rails と gRPC を組み合わせて使用している • 新しい gRPC gem (griffin) を作って検証中