go-grpc-prometheusでgRPCのmetricsをPrometeusとGrafanaでモニタリングしてみた
gRPC Ecosystemの1つにgo-grpc-prometheus
があります。今回は「gRPC Ecosystem
のgo-grpc-prometheus
を試してみました」エントリです。
go-grpc-prometheus
go-grpc-prometheus
はgRPCのmetricsをPrometheusでモニタリングできるログ出力をサポートするインターセプターを提供します。
取得できるmetricsはレポジトリのREADMEにまとまっています。
GitHub - grpc-ecosystem/go-grpc-prometheus: Prometheus monitoring for your gRPC Go servers.
gRPC Goはインターセプターをサポートしていますので次のようにClientとServerそれぞれに設定します。
- Serverでは次のように。https://github.com/grpc-ecosystem/go-grpc-prometheus#server-side
- Clientでは次のように。https://github.com/grpc-ecosystem/go-grpc-prometheus#client-side
PrometheusでモニタリングしたmetricsをGrafanaでもモニタリングしてみる
go-grpc-prometheus
でgRPCのmetricsが取得できるようになります。Prometheusを起動すればmetricsをモニタリングできるようになります。合わせてPrometheusでモニタリングしているmetricsをGrafanaでもモニタリングしてみます。
シンプルなEchoサービスを作る
unary RPCs
を利用してシンプルなEchoサービスを作ります。
proto
syntax = "proto3"; option go_package = "protobuf"; package proto; service EchoService { rpc EchoService (Message) returns (Message) {} } message Message { string message = 1; }
Server Side
Server sideはgRPCのClientからのリクエストに応えるServer-side of gRPC
の役割とPrometeusのためのMetrics
を出力する役割の2つが必要です。
1つのPortでHTTP/2 (gRPC)
とHTTP/1.1
のリクエストを解釈する必要があるのでsoheilhy/cmux
を使います。
ほぼ素の使い方ですがServer-sideのソースは次のようになりました。(コード抜粋。詳細はnsoushi/go-grpc-prometheus-demoにあります。)
func main() { // Create the main listener. s, err := net.Listen("tcp", fmt.Sprintf(":%s", os.Getenv("GRPC_SERVER_PORT"))) if err != nil { log.Fatal(err) } // Create a cmux. m := cmux.New(s) // Match connections in order: grpcL := m.Match(cmux.HTTP2HeaderField("content-type", "application/grpc")) httpL := m.Match(cmux.HTTP1Fast()) // gRPC server grpcS := grpc.NewServer( grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor), grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor), ) pb.RegisterEchoServiceServer(grpcS, newGrpcServer()) // prometheus metrics server grpc_prometheus.Register(grpcS) httpS := &http.Server{ Handler: promhttp.Handler(), } go grpcS.Serve(grpcL) go httpS.Serve(httpL) m.Serve() }
※ unary RPCs
のみなのでgrpc.StreamInterceptor
は必要ないですがデモのため入れています。
Client Side
Client Sideはブラウザからリクエストを受け取りgRPCのServer-sideへリクエストを送ってくれるエンドポイントとPrometeusのためのmetricsを出力するエンドポイントの2つを用意します。
Client-sideのソースは次のようになりました。(コード抜粋。詳細はnsoushi/go-grpc-prometheus-demoにあります。)
func main() { //gRPC connection var err error conn, err = grpc.Dial( fmt.Sprintf("%s:%s", os.Getenv("GRPC_SERVER_HOST"), os.Getenv("GRPC_SERVER_PORT")), grpc.WithInsecure(), grpc.WithBackoffMaxDelay(time.Second), grpc.WithUnaryInterceptor(grpc_prometheus.UnaryClientInterceptor), grpc.WithStreamInterceptor(grpc_prometheus.StreamClientInterceptor), ) if err != nil { log.Error("Connection error: %v", err) } defer conn.Close() // handle http http.Handle("/metrics", promhttp.Handler()) http.HandleFunc("/echo", echoHandler) http.HandleFunc("/", indexHandler) // serve http http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("GRPC_CLIENT_PORT")), nil) }
Prometheusでmetricsを確認する
PrometheusはDockerで起動しました。Dockerで起動するとprometheus.ymlのtargetsにlocalhost
としてもgRPCのServer-sideとClient-sideのホストへはアクセスできないのでdocker-composeを使いコンテナ構成をまとめてホスト解決を行います。
version: "3" services: grpcserver: container_name: grpcserver build: ./server ports: - 8080:8080 environment: GRPC_SERVER_HOST: grpcserver GRPC_SERVER_PORT: 8080 grpcclient: container_name: grpcclient build: ./client ports: - 8081:8081 environment: GRPC_SERVER_HOST: grpcserver GRPC_SERVER_PORT: 8080 GRPC_CLIENT_HOST: grpcclient GRPC_CLIENT_PORT: 8081 prometheus: container_name: prometheus build: ./prometheus ports: - 9090:9090 depends_on: - grpcserver - grpcclient grafana: image: grafana/grafana ports: - "3000:3000" depends_on: - prometheus - grpcserver - grpcclient
Prometheusのコンテナを起動してhttp://localhost:9090/graph
へアクセスするとgRPCのmetricsが insert metric at cursor
のメニューに追加されているのが確認できます。
Grafanaでmetricsを確認する
Grafanaのコンテナもdocker-composeに入れましたのでhttp://localhost:3000/login
へアクセスするとGrafanaのダッシュボードを確認できます。Data Sourceにprometheusを追加してDashboardを作成します。
次のようなServer-sideのダッシュボードを作成しました。
gRPCのServer-sideのレスポンス送信数、クライアントからの受信数をGrafanaに設定しました。
※ nsoushi/go-grpc-prometheus-demoのgrafana
フォルダにServer-sideとClient-sideのダッシュボード設定をエクスポートしたJSONがあります。このJSONをインポートするとダッシュボードが簡単に作れます。詳細はレポジトリのREADMEを参照してください。
まとめ
go-grpc-prometheus
をつかってgRPCのmetricsをPrometheusとGrafanaでモニタリングしました。go-grpc-prometheus
の導入はインターセプターを入れるだけなので簡単ではありますが複数のClient-sideとServer-sideの条件での検証、負荷検証などサービスへの導入検証が必要。
コードを公開しています
コード全体はgitbubで確認できます。