愛と勇気と缶ビール

ふしぎとぼくらはなにをしたらよいか

CベースのgRPCサーバをgraceful restartする、たった一つの冴えたやり方

たった一つかどうかは知らんけど、「まあとりあえずこれでいいや」みたいな方法。

「CベースのgRPCサーバ」とは何ぞやっていうと、gRPCの実装はC言語ベースの実装・golang実装・Java実装に分かれているっぽくて、いわゆるRubyとかPythonとかのLLにおけるgRPC Serverは「各言語のライブラリ => 各言語のC言語バインディング => Cで書かれたコア」という構成になっているっぽい。早い話が、goとJava以外ではCベースの実装を使っていることになる。

で、ある程度真面目にRuby / gRPCで書かれたAPIサーバを運用しようとするにあたって「これどうやってgraceful restartしようかな」と思ったわけですね。

今まで僕がgraceful restartをやる方法といえば、

  1. UnicornとかNginxとか、サーバアプリケーション自体がgraceful restartを実装しているのでそれに乗っかる
  2. H2OとかRhebokとか、server-starter経由でgraceful restartできるサーバアプリケーションを使う

のどっちかしかやってこなかったわけですが、gRPC Serverは少なくとも1ではなさそうであり、2のためにコードに手を入れるのもなんだかな、という感じだったので「どうしたもんかな〜」と思いながらgRPCのCのソースを眺めいていたわけです。

そしたら、アレですよアレ。なんとCベースのgRPCサーバはデフォルトでSO_REUSEPORTが有効になってるんですね。やった!これや!ということで超手抜きなgraceful restartの実現方法がこちら

  1. 新サーバを立ち上げる (同じportをlistenしても死なない、なぜならREUSEPORTが効いてるからな!)
  2. 暫し待つ
  3. 旧サーバを殺す

Great.

ただしこの方法には明らかな問題があって、もし新サーバを立ち上げるのに失敗した場合は爆死してしまう。そこは新サーバの立ち上がりをちゃんと確認してから旧サーバを殺すようにすればいいだろう。

イマドキはgraceful restartなんてやらずにBlue / Greenなdeployを行うのが主流だったりするのかもだけど、まあやりたい人はいるだろうということで。