👻

Go言語でサーバのGraceful Shutdown

2020/10/01に公開

Go言語のサーバで Graceful Restart をするにあたり go-server-starter を使ってみようかなと思ったので、そのために必要なライブラリを調査してみました。

Graceful Restart

今回の主題とは別件ですが、Go言語の Graceful Restart のためのライブラリでは、os.StartProcessexec.Command によって自分自身の子プロセスを起動し、ファイルディスクリプタ経由でソケットを渡して、再起動時は子プロセスのみを停止・起動するものがあります。

今回はこれらのライブラリについては触れません。

Graceful Shutdown

もう一方で、Graceful Shutdown の機能だけを提供するものがあります。

これらの場合では go-server-startercircus などがソケットを保持して子プロセスを起動し、ファイルディスクリプタ経由で子プロセスにソケットを渡すことになります。

go-server-starter

go-server-starter を使って Graceful Shutdown の各ライブラリを使ったサンプルを実装してみました。ソースコード全体は github.com/najeira/grace_samples をご覧ください。

※ 前述のリポジトリ内にある facebookgo_httpdown のみ、リスナーを外部から渡せないので go-server-starter に対応したものではなく、単独でのサンプルです。今回は関係ありません。

試してみる

go get

go get github.com/lestrrat/go-server-starter/cmd/start_server
go get github.com/najeira/grace_samples/braintree_manners
go get github.com/najeira/grace_samples/shogo_gracedown
go get github.com/najeira/grace_samples/tylerb_graceful

go build

braintree_manners を試す場合。

cd $GOPATH/src/github.com/najeira/grace_samples/braintree_manners
go build

run

サーバを起動します。

$GOPATH/bin/start_server --port 8080 --pid-file app.pid -- ./braintree_manners &

HTTPリクエストを送ってみます。

curl http://localhost:8080/

going to sleep 100ms with pid 2880
slept 100ms with pid 2880

restart

サーバの再起動は HUP です。

kill -HUP `cat app.pid`
received HUP (num_old_workers=TODO)
spawning a new worker (num_old_workers=TODO)
starting new worker 2899
new worker is now running, sending TERM to old workers:2880
sleep 0 secs
killing old workers
old worker 2880 died, status:0

stop

サーバの停止は TERM です。

kill -TERM `cat app.pid`

負荷をかけてみる

シグナル HUP を送り続けて再起動させ続けます。

while true; do kill -HUP `cat app.pid`; sleep 1; done

ab

別のセッションで ab で負荷をかけてみます。

ab -r -n 100000 -c 1000 http://localhost:8080/

Results

braintree_manners

Concurrency Level:      1000
Time taken for tests:   12.580 seconds
Complete requests:      100000
Failed requests:        22
   (Connect: 0, Receive: 0, Length: 22, Exceptions: 0)
Write errors:           0
Total transferred:      15798424 bytes
HTML transferred:       6099200 bytes
Requests per second:    7949.39 [#/sec] (mean)
Time per request:       125.796 [ms] (mean)
Time per request:       0.126 [ms] (mean, across all concurrent requests)
Transfer rate:          1226.44 [Kbytes/sec] received

shogo_gracedown

Concurrency Level:      1000
Time taken for tests:   12.898 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Total transferred:      15801082 bytes
HTML transferred:       6100306 bytes
Requests per second:    7753.17 [#/sec] (mean)
Time per request:       128.980 [ms] (mean)
Time per request:       0.129 [ms] (mean, across all concurrent requests)
Transfer rate:          1196.37 [Kbytes/sec] received

tylerb_graceful

Concurrency Level:      1000
Time taken for tests:   12.472 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Total transferred:      15800474 bytes
HTML transferred:       6100183 bytes
Requests per second:    8017.95 [#/sec] (mean)
Time per request:       124.720 [ms] (mean)
Time per request:       0.125 [ms] (mean, across all concurrent requests)
Transfer rate:          1237.18 [Kbytes/sec] received

Environment

  • go version go1.6.2 linux/amd64
  • Amazon EC2 c4.large
  • Linux version 4.4.11-23.53.amzn1.x86_64

Conclusion

braintree_manners で取りこぼしがあるようです。

他、おすすめの Shutdown ライブラリがあれば、ぜひ教えてください!

参考

See: https://shogo82148.github.io/blog/2015/11/23/golang-graceful-restart-2nd/

この記事はQiitaの記事をエクスポートしたものです

Discussion