2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
gRPC at OA Dev team(全1記事)
提供:LINE株式会社
リンクをコピー
記事をブックマーク
奥山裕也氏(以下、奥山):LINEの開発4センター、 Official Account開発室の奥山が、「OA DevにおけるgRPC」についてお話しします。
まず簡単に自己紹介しますと、私は2019年の4月に新卒で入社しました。Official Account開発室というチームで、LINE公式アカウント関連の新規サービスを主に開発しています。コードは、サーバサイドで主にKotlinを書いています。また、line-bot-sdk-pythonというMessaging API SDKのメンテナーもしています。
今日は、最初に「gRPCって何だったっけ?」という話をして、そのあとOA Devチームにおいて、gRPCをどう使っているかという話をしていきます。
それではまずgRPCについてですが、たぶんこの中でも、実際にgRPCを使ったことがあるという人や実際のサービスで使ったことがある人もいるかもしれません。gRPCというのはGoogleが開発したRPCフレームワークで、現在はCloud Native Computing FoundationというCNCFのプロジェクトになっています。
gRPCと言ったときに一番初めに思い浮かべることは、Protocol Buffersを使っていることかなと思います。このIDLを使うことによって、スキーマファーストな開発ができます。protoファイルを見れば、仕様があるという状態になっていて、また、特定の言語に依存しないメッセージ、サービスを定義できます。
これによって、JavaやGo、Python、JavaScriptといった他の言語のクライアントを簡単に生成でき、他の言語を使っているチームとのやり取りが簡単にできるといったメリットがあります。
あとは、JSONとの相互互換がちゃんと定義されている点や、前方互換性/後方互換性を保つ変更の仕方が明確に決まっているので、メッセージの型を変えるとかメッセージのフィールドを増やすときに、ちゃんと互換性を保ちながら変更することができます。
JSONやXML、MessagePackなど、いろいろあると思いますが、そういったものよりもコンパクトで効率的なコーディングができます。また、HTTP/2でデータを送受信していたり双方向通信をしていたりなどもありますが、たぶんおそらく多くの人にとって一番特徴的なのがProtocol Buffersを使うことだと思います。
それでは、実際にLINEではgRPCをどう使っているかというと、私たちが今新規開発しているサービスや、既にLINE公式アカウントのバックエンドでも使われています。
あとは、去年のLINE DEVELOPER DAYで発表があったLINE LIVE Commerce、LINE MUSICやLINE Financialなどサーバ間の通信で使われることが増えてきました。
また言語としては、Javaの会社なので、Java、Kotlin、Scalaでの使用が多いです。GoやPythonを使っている事例もあります。JavaScriptでgRPC-Webを使っている事例もあります。
Thriftは聞きなれない方も多いかもしれませんが、これはFacebook製のRPCフレームワークで、ほぼgRPCのようなものです。実際に、既に社内の多くの箇所で利用されており、そういう意味では、LINEというのはRPCをよく使う会社です。
実際にgRPCのアプリケーションをデプロイするにあたって、どういうことが必要かなと考えてみると、たぶんこの辺のことが最低限必要かと思います。ログやメトリクスや分散トレーシングはマイクロサービスでは必要になってきますし、サービス間通信でのサーキットブレーカーやリトライ、ロードバランシングも必要です。
gRPCでは、「ロードバランシングはどうするの?」がよく話題になります。また、gRPCだとcurlが使えません。そうなると「デバッグツールはどうするの?」となります。他にも「gRPCで他のサービスとのエラーの伝播、エラーハンドリングはどうするの?」「ドキュメントをどうやって作って他のチームと共有するの?」といったことは気になると思います。そういうわけで今回は、この辺の話をしていこうと思います。
私のチームで、gRPCをどう使っているのかを紹介します。これが、私たちのシステムの本当にざっくりとしたオーバービューです。私たちが今作っているこの新規サービスのアーキテクチャで、BtoBサービスということだけしか言えないんですけど、BtoBなので、パートナーのサーバからリクエストが来たりとか、普通にブラウザからリクエストが来ることもあります。
あとは社内の他のチームからリクエストが来ることもあり、しかもRESTに限らず他のチームや外部のサーバからgRPCで来ることもあるので、RESTとgRPCの両方をちゃんと受けられるようになっています。
最初にRESTとgRPCに関係なく、L4LBで受け取って、それをNginxに流して、Nginxの部分でリクエストのパスを見て、gRPCかRESTかを流すような感じになっています。そのあとに、それぞれにプロキシが2つあるんですけど、こちらがgRPCを受けてgRPCを流すというプロキシで、こっちはRESTを受けてgRPCに変換するプロキシです。それぞれのプロキシでロードバランシングをしています。最後に、このアップストリームのgRPCサーバに流していると。
1つ特徴的と思えるかもしれないのが、ここのREST-gRPCのプロキシの部分は、私たちはEnvoyとかgrpc-gatewayは使わずに実装することにしました。
というのも、社外から呼ばれるということで、やっぱりEnvoyやGoはまだ運用に不慣れなところがあり、それでかつ柔軟な要望に応えるようにしたいので、今回はSpringというJavaのフレームワークを使って実装することになりました。システム全体のオーバービューでした。
それではgRPCサーバをどう実装しているのかという話をしたいと思います。今回、私たちはgRPCのフレームワークとしてLINE製のマイクロサービスフレームワークであるArmeriaを使いました。Armeriaは社内のコアな部分で既に実績があり、信頼できるフレームワークです。
とくにgRPCとJavaやSpringの界隈でよく使われているライブラリとしては、LogNet/grpc-spring-boot-starterやyidongnan/grpc-spring-boot-starterがありますが、それらに比べてArmeriaのほうが開発が活発でした。
あとは社内製ということで、フィーチャーリクエストのしやすさや、コミュニケーションの取りやさがありました。決定的な理由としては、ArmeriaのgRPC実装というのは、公式のgrpc-javaのインターフェースを使って実装されており、gRPCのエコシステムから逸脱せずにgRPCサーバーを実装できるのがすごく魅力的でした。
実際にバリデーションのライブラリなど、grpc-javaを前提としたライブラリはけっこう多いんです。そういうときに困ることがないので、私たちはArmeriaを使いました。
Armeriaではクライアントサイドロードバランシング、サーキットブレーカー、リトライ、分散トレーシングといった定番の機能が簡単に使えます。またDocServiceというSwaggerのような機能もあります。これらの便利な機能が簡単に使えるので、私たちはArmeriaを使ってgRPCサーバを作ることにしました。
実際にどんな感じでgRPCのサーバが実装できるの? という話なんですけど、この例のコードは少し省略しているのですが、基本的には自分のbindableServices(gRPCのprotoのコンパイラが出したgRPCサービスのインターフェースの実装)をBuilderに渡すだけです。
あとはここの部分でシリアライゼーション、Content-typeに応じてJSONで返すとか、そういうおもしろい特徴があったり、アクセスログをちゃんと取りたかったらここで設定をしたり、分散トレーシングの設定も本当に1行でできてしまいます。こんなふうに、本当に簡単にログやメトリクス、分散トレーシングの設定ができます。
gRPC クライアントも簡単に実装できます。今回私たちはクライアントサイドでロードバランシングをしたのですが、ロードバランスするときのサービスディスカバリーについては、DNSで行いました。builderの引数にDNSレコードを与えるだけで設定できます。
さらにロギングやZipkin、メトリクスの設定も1行で書けてしまいます。またサービスディスカバリーについては、ZooKeeperやEurekaでも行えるようになっています。
もう1点、ArmeriaにはDocServiceという、Swagger UIのような機能があると話したと思うのですが、これを使うことによってProtocol Buffersで定義したサービスやメッセージを一覧できます。
例えばHelloServiceというサービスがあって、それのHello()やBidiHello()、こういうメソッドが見られるとか、そのメソッドのリクエストの型とかを簡単にチェックできます。
さらにDocServiceにはデバッグ機能もあります。これは実際にgRPCのリクエストをサーバに投げてそのレスポンスが返ってきているという例なんですけど、ブラウザからgRPCのデバッグができるというのが本当に魅力的でした。このようにしてロギングからメトリクス、分散トレーシングとかリトライ、ロードバランシング、デバッグはArmeriaで簡単に解決することができました。
では残りのエラーハンドリングやドキュメンテーションはどうやっているかというと、もしかしたらgRPCをちょっと使っただけだと気付かない話かもしれないのですが、gRPCはRESTみたいにエラーのペイロードをHTTPボディに含めて返すことができません。なので、これら4つの方法のどれをとるかで悩みました。
エラーを返したいとき、一番基本的なのは1個目のgrpc-statusとgrpc-messageだけで返す方法があります。これでもいいんですけど、当然他のチームとのやり取りが出てくると、ちゃんとエラーメッセージを返してあげないといけないですよね。そうなってくると1個目の方法は却下となります。
次は2個目の方法で、すべてのレスポンスのフィールドにエラーのフィールドを追加する。これはすごくシンプルでわかりやすいのですが、すべてのレスポンスにエラーのフィールドを追加しないといけなくて、ちょっと煩わしかったり、あとは0から15まであるgRPCのステータスを常に0で返さないといけなくなってしまうので、あまりよくないですね。
そういうことで、私たちは下の、とくに一番下の自分で定義したメッセージをメタデータに含めて返すという方針を取りました。これはどうやるかというと、最初に自分で返したいエラーの定義を作ります。
今回はこのErrorであって、そこにErrorDetailのリストを返すかたちなんですけど、こんな感じで好きなエラーを定義して、サーバでエラーが起こった場合は、メタデータを作ってメタデータに自分が返したいエラーのペイロードをputして返す。このときはProtoBufでバイナリエンコーディングしたものをメタデータに含めて送り返しています。
ただ、この方法の1点面倒くさいところは、クライアントで受け取るときは自分でデシリアライズしてあげないといけなくて、これは仕方がないのかなと思います。この辺はたぶんあまり言語によらず、Goで出てきても同じような方法になるかと思います。エラーハンドリングについてはこんな感じです。
最後に、私たちが実際にドキュメンテーションをどうしているか。protoc-gen-docsというツールがあったので、これを使って社内の他のチームとかに共有するドキュメントを生成していました。こんな感じで、gRPCのコメントだったり、オプションとコメントを読み取って。ここの部分がコメントで、ここがオプションですかね。
ここがRPCのリクエストとレスポンスの型を表示したり、という感じで、protoから簡単にドキュメントを生成できました。
こんなふうに私たちのチームでは、ロギングだったりデバッグするこの辺の一連のArmeriaを使うことで解決させました。エラーハンドリングについてはメタデータにエラーペイロードを含めるという手法をとったり、ドキュメンテーションについてはprotoc-gen-docsというツールを使ってやっていきました。
実際にgRPCを使ってどうだったかという、ざっくりとした感想なんですけど、最初に実装ではなくてスキーマを定義してからやっていくので、やっぱりコードレビューがしやすかったです。ただ1点不満があるとしたら、protoファイルで関数名やフィールド名を変更したとき、それがIDが自動で変更を反映してくれなくて、ソースコードのほうも名前を変えるのは面倒くさかったりしました。
HTTP/2を使っているということで、社内ではまだ新しい技術だと思うのですが、その分社内LBとかの設定がちょっと面倒くさかったりしました。あとはエコシステムとしましては、CLIからリクエストしたいときは、gRPCurlというツールがあったり、ドキュメント生成ツールがあったりとか、最低限なものは揃っているかなという感じはありました。
ただGUI Clientがまだまだリッチなものがないねとか、まだまだなところもありました。
最後に覚えておいてほしいのは、LINEでも少しずつgRPCがプロダクションで使われだしています。とくにJavaユーザーの方であれば、Armeriaを使えばプロダクションレディなgRPCサーバが簡単に作れます。あとはgRPCを使っていくにあたって、エラーハンドリングはどうするかなとなったとき、RESTより少し面倒くさいということは覚えておいてください。
スキーマを定義するというのは、レビューも楽だし、ドキュメントの生成もすごく楽だという話でした。以上です。
司会者:どうもありがとうございます。ここからは質疑応答のセッションです。1つ目ですね。「gRPCのツールにいろいろな機能をもたせると便利だけど、それぞれの機能が密結合してしまって、後で変更しにくくなりませんか?」ということですが、いかがですか?
奥山:ツールというのはたぶんフレームワークのことかと思うのですが、それは確かに一理あるというか、ArmeriaというgRPCサーバを作っているのですが、実際はgRPCサーバだけじゃなくて、RESTのサーバとかも別に作っていたりして、それぞれでいちいちロギングだったり諸々の設定をしないといけないのが、三度手間だったりするのはありますね。
たぶんこれは、「Envoyとか、そういうプロキシを置いて、それにいろいろ任せちゃえばいいじゃん」みたいな話かと思いますが、それは確かにそうなのですが、Envoyを運用するコストと、やりやすい方法どちらを取るかという話なのかなと思います。
司会者:はい、ありがとうございます。次に「サーバープッシュなどのstreamingのRPCは利用していますか?」。
奥山:今は使っていないし、将来的にも使う要求は出ないと思っています。
司会者:なるほど。はい、ありがとうございました。
LINE株式会社
2024.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05