gRPCのchannelz用のCLIツール


以前 gRPCのChannelzを使ってみた というタイトルでgRPCに導入されたchannelzというものを紹介しました。
これを使うことでアプリケーションで動いているgRPCのコネクションがどういう状態かを詳細に知ることができることがわかりました。

公式のブログでも紹介され、そこでは grpc-zpages と呼ばれるwebベースのchannelzのフロントエンドが公開されていました。自分も似たようなWebベースのものを作ろうと思っていて、社内にある複数のgRPCサービスをまとめて見られるダッシュボードのようなもの(まだない)にchannelzと連携して表示しようとしています。

今回は手元ですぐに状況を知りたいことが多くなってきたので簡単に作れるCLIとしてchannelzcliというものを作ってみました。

channelzcli

channelzcli は channelz serviceから情報を取得して表示するツールです。
まだまださっと作ったものなのでエラーハンドリングとかが雑ですが、channelz serviceから取れる情報はだいたい表示できるようになっているかなと思います。

コマンドとしては3種類で表示方法や内容が異なるだけで情報のソース(API)は同じです。

  • list: 状態を全体的にテーブル形式で見る
  • describe: 特定のものの詳細を見る
  • tree: 全体をツリー上に見る

各コマンドでは対象として channelserver を指定できます。
概念的には SocketSubchannel などもあるのでdescribeなどで詳細表示できるように都度足していきます。

  • channel: アプリケーション自体が直接生成したchannel(TopChannel)
  • server: アプリケーションのgRPCサーバ

List

雰囲気的にはkubectl getみたいなものです。
gRPCではchannelの中にchannelがあり、それぞれ毎にstateなどを持っているのでざっくりどういう状態か知るために作りました。
Subchannel毎の内訳もここに表示したかったので、APIコールがN+1になるのでどうしようかなと考え中。

$ channelzcli -k --addr localhost:8000 list channel
ID  Name                                        State   Channel SubChannel  Calls   Success Fail    LastCall
1   spanner.googleapis.com:443                  READY   0       1           6372    6362    12      9s      
2   spanner.googleapis.com:443                  READY   0       1           6442    6433    11      2m      
3   spanner.googleapis.com:443                  READY   0       1           6306    6293    17      1m      
4   spanner.googleapis.com:443                  READY   0       1           6865    6849    21      54s     
28  pubsub.googleapis.com:443                   READY   0       16          0       0       0       none    
29  pubsub.googleapis.com:443                   READY   0       16          80      80      0       12h     
$ channelzcli -k --addr localhost:8000 list server
ID  Name    LocalAddr   Calls   Success Fail    LastCall
31  <none>  <none>          2264    2262    1       410ms
35  <none>  [::]:5000       1732    1090    642     10h

Describe

describeはとりあえず取得できる情報全部表示するかという感じで作りました。
TraceのEventはchannelに発生したイベントが出てくるので問題を把握するのにも便利です。

$ channelcli -k --addr localhost:18000 describe channel 29
Name:       pubsub.googleapis.com:443
ChannelID:  29
State:      READY
Target:     pubsub.googleapis.com:443
Calls:
  Started:          80
  Succeeded:        80
  Failed:           0
  LastCallStarted:  2018-12-01 21:11:17.64129022 +0000 UTC
Socket:     <none>
Channels:       <none>
Subchannels:
  ID    Name    State   Start   Succeeded   Failed
  71        READY   5   5   0
  58        READY   5   5   0
  64        READY   5   5   0
  70        READY   5   5   0
  66        READY   5   5   0
  68        READY   5   5   0
  38        READY   5   5   0
  56        READY   5   5   0
  57        READY   5   5   0
  62        READY   5   5   0
  69        READY   5   5   0
  63        READY   5   5   0
  61        READY   5   5   0
  65        READY   5   5   0
  59        READY   5   5   0
  67        READY   5   5   0
Trace:
  NumEvents:    22
  CreationTimestamp:    2018-11-30 11:16:06.335742037 +0000 UTC
  Events
    Severity    Description                                                                         Timestamp
    INFO    Channel Created                                                                     2018-11-30 11:16:06.335743742 +0000 UTC
    INFO    Resolver returns a non-empty address list (previous one was empty) "pubsub.googleapis.com:443"  2018-11-30 11:16:06.427269951 +0000 UTC
    INFO    Subchannel(id:38) created                                                           2018-11-30 11:16:06.525993125 +0000 UTC
    INFO    Subchannel(id:56) created                                                           2018-11-30 11:16:06.526069714 +0000 UTC
    INFO    Channel Connectivity change to CONNECTING                                           2018-11-30 11:16:06.526084142 +0000 UTC
    INFO    Subchannel(id:57) created                                                           2018-11-30 11:16:06.526261462 +0000 UTC
    INFO    Subchannel(id:58) created                                                           2018-11-30 11:16:06.526275698 +0000 UTC
    INFO    Subchannel(id:59) created                                                           2018-11-30 11:16:06.526310408 +0000 UTC
    INFO    Subchannel(id:61) created                                                           2018-11-30 11:16:06.526424564 +0000 UTC
    INFO    Subchannel(id:62) created                                                           2018-11-30 11:16:06.526442884 +0000 UTC
    INFO    Subchannel(id:63) created                                                           2018-11-30 11:16:06.526450184 +0000 UTC
    INFO    Subchannel(id:64) created                                                           2018-11-30 11:16:06.52646022 +0000 UTC
    INFO    Subchannel(id:65) created                                                           2018-11-30 11:16:06.52647477 +0000 UTC
    INFO    Subchannel(id:66) created                                                           2018-11-30 11:16:06.526482334 +0000 UTC
    INFO    Subchannel(id:67) created                                                           2018-11-30 11:16:06.526566127 +0000 UTC
    INFO    Subchannel(id:68) created                                                           2018-11-30 11:16:06.526575083 +0000 UTC
    INFO    Subchannel(id:69) created                                                           2018-11-30 11:16:06.526583642 +0000 UTC
    INFO    Subchannel(id:70) created                                                           2018-11-30 11:16:06.526597817 +0000 UTC
    INFO    Subchannel(id:71) created                                                           2018-11-30 11:16:06.526631882 +0000 UTC
    INFO    Channel Connectivity change to READY                                                2018-11-30 11:16:07.438772142 +0000 UTC
    INFO    Channel Connectivity change to CONNECTING                                           2018-11-30 12:40:09.169893863 +0000 UTC
    INFO    Channel Connectivity change to READY                                                2018-11-30 12:40:12.967264812 +0000 UTC

Tree

treeコマンドはchannelなどの情報をツリー上に視覚的にわかりやすく表示するために作りました。
channelはchannelの中にsubchannelがあって更にその中にsubchannelがあるとかもありえるので、describeなどでは表示が厳しそうだからです。

pubsub.googleapis.com:443 (ID:28) [READY]
  [Calls] Started:0, Succeeded:0, Failed:0, Last:none
  [Subchannels]
    |-- pubsub.googleapis.com:443 (ID:52) [READY]
          [Calls]: Started:0, Succeeded:0, Failed:0, Last:none
          [Socket] ID:22840, Name:, RemoteName:, Local:[10.0.0.xx]:39306 Remote:[172.217.27.xx]:443
    |-- pubsub.googleapis.com:443 (ID:45) [READY]
          [Calls]: Started:0, Succeeded:0, Failed:0, Last:none
          [Socket] ID:22844, Name:, RemoteName:, Local:[10.0.0.xx]:42054 Remote:[216.58.197.xx]:443
    |-- pubsub.googleapis.com:443 (ID:53) [READY]
          [Calls]: Started:0, Succeeded:0, Failed:0, Last:none
          [Socket] ID:22837, Name:, RemoteName:, Local:[10.0.0.xx]:49570 Remote:[172.217.31.xx]:443
    |-- pubsub.googleapis.com:443 (ID:55) [READY]
          [Calls]: Started:0, Succeeded:0, Failed:0, Last:none
          [Socket] ID:22841, Name:, RemoteName:, Local:[10.0.0.xx]:45626 Remote:[216.58.197.xx]:443
    |-- pubsub.googleapis.com:443 (ID:46) [READY]
          [Calls]: Started:0, Succeeded:0, Failed:0, Last:none
          [Socket] ID:22850, Name:, RemoteName:, Local:[10.0.0.xx]:54362 Remote:[216.58.197.xx]:443
    ....

pubsub.googleapis.com:443 (ID:29) [READY]
  [Calls] Started:80, Succeeded:80, Failed:0, Last:12h
  [Subchannels]
    |-- pubsub.googleapis.com:443 (ID:56) [READY]
          [Calls]: Started:5, Succeeded:5, Failed:0, Last:12h
          [Socket] ID:22862, Name:, RemoteName:, Local:[10.0.0.xx]51096 Remote:[172.217.31.xx]:443
    |-- pubsub.googleapis.com:443 (ID:63) [READY]
          [Calls]: Started:5, Succeeded:5, Failed:0, Last:12h
          [Socket] ID:22856, Name:, RemoteName:, Local:[10.0.0.xx]:57712 Remote:[172.217.161.xx]:443
    |-- pubsub.googleapis.com:443 (ID:57) [READY]
          [Calls]: Started:5, Succeeded:5, Failed:0, Last:12h
          [Socket] ID:22865, Name:, RemoteName:, Local:[10.0.0.xx]:47202 Remote:[172.217.25.xx]:443
    |-- pubsub.googleapis.com:443 (ID:65) [READY]
          [Calls]: Started:5, Succeeded:5, Failed:0, Last:12h
          [Socket] ID:22863, Name:, RemoteName:, Local:[10.0.0.xx]:47198 Remote:[172.217.25.xx]:443
  ....

その他

機能的にほしいのは top コマンドみたいに定期的に更新して変化を見られるものとか作りたいなとか考えてます。
あとはリクエスト数と成功数からreq/sとか成功率とかも計算できるはずなのでそのあたりも表示できると嬉しそうです。