SREチームの那須です。
3/7に開催されたピクスタさんの 大規模プラットフォームを支えるエンジニアの技術と工夫〜Web現場Meetup #3〜 で登壇させていただきました。そのときにお話ししたgrpc-gatewayを使った管理画面の構築について改めてまとめてみます
CrowdWorksのマイクロサービス化の試み
CrowdWorksでは現在マイクロサービス化を進めています。
CrowdWorksはモノリシックなアプリケーションです。様々な機能が一つのアプリケーションに同居し、サービスを提供しています。
モノリシックなアプリケーションの問題点としては一つの問題が全体に波及してしまうということがあります。メッセージの機能を改修したところ問題が発生しアプリケーション全体が不安定になるということもありえます。
そこでCrowdWorksでは最初の試みとして、新しく作るサービスをCrowdWorks本体に実装せず別サービスとしてリリースするという取り組みを行っています。もし障害が起きたとしてもCrowdWorks本体には大きな影響を及ぼさないように実装していくのが最近の方針です。
マイクロサービス化の知見がまだあまりないので新しいサービスをマイクロサービスで実装し、知見を溜めてゆくゆくは本体の機能を切り出すなどしていければと考えています。
異なるサービス間をつなぐgRPC
マイクロサービス化を進めていくとサービス間の連携をどうしていくかが課題になってきます。
よく使われる手としてはREST APIを実装することですが、REST APIだとAPIのURLを考えたりとAPIの仕様をどうするか考えたりと手数が多いのが難点です。マイクロサービスとしてサービスを切り出していくたびにAPIを考えるのはかなりのコストになります。
そこでCrowdWorksではgRPCを用いたサービス間の連携に取り組みはじめました。
gRPCはGoogleが公開しているRPCのライブラリ・フレームワークでprotocol buffersをコンパイルするprotocというコマンドのプラグインとして提供されています。protocで.protoファイルをコンパイルし、吐き出されたコードをサーバーとクライアントに実装することでサービス間の通信をRPCで行うことが出来るようになります。
gRPCを使うことでサービス間の連携にかかるコストを削減することができ、マイクロサービスをより作りやすくなることを期待しています。
マイクロサービス化による課題
gRPCを使うことでマイクロサービス化が促進されるのは良いのですが、問題点も勿論出てきます。
小さなサービスが生まれることで管理画面がその分増えることになります。管理画面増加の問題です。サービスを提供していて管理画面が存在しないというのはりえないです。モノリシックなアプリケーションだと一つの管理画面ですんでいたのですが、サービスが増えることにより管理画面の管理 が大変になります。
サービス間の連携にgRPCを使うことによって新たな問題が発生します。それはgRPCでしかお話しできないことです。よくあるREST APIの場合は curl
などでAPIを叩くことは可能でしたが、gRPCだとそのやり方では駄目です。protocで出力したコードを実装した専用のクライアントなどを使わなければ確認できないので気軽さはだいぶ減ってしまいます。
grpc-gatewayを使った管理画面の構築
管理画面の散逸を防ぐために一つの管理画面に集約することをまずは考えました。管理画面からgRPCで各サービスに接続し全てのサービスの管理を行います。管理画面側のサーバーで一度リクエストを受け付けてgRPCを使って各サービスにリクエストを投げます。
そうなると一度管理画面側のサーバーでリクエストを受け付けないといけないためサーバー側でルーティングをちゃんと実装する必要が出てきます。ビューを表示しformから入力させ、POSTで送られたデータをパースして各サービスに渡すなどの実装を行うのは割とコストのかかることです。
そこで我々はgrpc-gateway
を使ってAPIを自動生成し、それを実装してJSON APIを作るようにしコストがかかるのを軽減することにしました。
grpc-gateway
はgRPCをラップしてJSON APIを作成してくれるprotoc
のpluginです。普通の用途としてはこれを使って吐き出されたコードを利用してJSON APIとgRPCを仲介するリバースプロキシを作成し利用します。
grpc-gateway
で吐き出されたコードを使ってJSON APIの作成を行うと、APIの作成やデータをパースする処理を自前で書かないですむためコストがかなり安くなります。
JSON APIなのでJavaScriptでそのまま直にAjaxでPOST出来るのも魅力で、ビュー側を全てJavaScriptで作成するSPAにすればビューのロジックをすべてJavaScript側に寄せられるので保守性も向上します。
grpc-gateway
で作成したAPIに認証の機能を追加し、ビューをJavaScript側に寄せたSPAで配信する管理画面を作ることにより、我々が感じていた課題を良い具合に解決することが出来るようになりました。
.protoを集めてくるprotodep
ここで一つ問題となるのが .proto
の管理です。普通に考えると呼び出すための仕組みは呼び出される側で仕様策定し実装するのが良いと考えます。するとマイクロサービス側のリポジトリに.proto
が存在することになるので、管理画面側はそれをとりに行く仕組みが必要になります。
Cyber Agentのかたがこれをうまく解決するツールをOSSで公開していました。 protodep
というツールです。
https://github.com/stormcat24/protodep
Protocol BuffersのIDL(.protoファイル)をvendoringするツールを書いた
このツールは golang
の dep
というライブラリのバージョン管理を行うコマンドに似た使用感で、dep
と同じようにtomlで依存関係を書けます。
proto_outdir = "./proto" [[dependencies]] target = "github.com/crowdworksjp/hogehoge_app/protocol" branch = "master"
依存関係をコードで管理できるのでとても便利です。
課題は結構ある
ここまで書いてきたのですが、実はまだこれらは実装中でまだ本番稼働してません。なのでこれで運用できるかはまだ未知です。
そもそも grpc-gateway
をリバプロのみの実装ではなく、認証機能を追加したりJavaScriptを配信したりする機能をつけたりして良いのかがちょっと自信が無いです。
既知の課題としては、grpc-gateway
と gRPCサーバーの接続が切れることがありました。
そのうち grpc-gateway
と gPRCサーバーの接続はAWSのnlbならではの問題で以下の記事の現象にまさに当てはまっていました。
GRPC WITH NLB は IDLE TIMEOUT に気をつけないと死ぬ
TCP_ELB_Reset_Count が計測されていることからも分かる通り、 350s 以上 idle している connection は NLB 側から RST Packet ( RESET 用の packet )を送出して接続を切るようです。
クライアントとサーバーにKeepaliveの設定を追加することで解決出来るようです。
他にもログ周りでgrpc-gateway
でも使われている grpc-log
を使うのですが、ログの整形をうまく制御できないなど課題があり実運用に耐えられるかまだ不安なところが出てきています。
正式リリースまでには解決したいところです。
まとめ
grpc-gateway
を中心とした管理画面について書いていきました。この記事では触れてませんが、ビューの構築に Vue.js
を使ったり、 Docker
のマルチステージビルドを利用したCI中でのコンテナの作り方などチャレンジングなことをしているプロジェクトになっています。
困難を一つずつ倒しながらCrowdWorksのマイクロサービス化を進めていきます。
クラウドソーシングのCrowdWorksではそんなマイクロサービス化を進めていくメンバーを募集中です。まずは気軽にお話をしてみませんか?マイクロサービスについての意見交換などしていければと思っております。