LoginSignup
87
60

More than 5 years have passed since last update.

Go 1.8 の HTTP Server Graceful Shutdown を試す

Last updated at Posted at 2016-12-25

Go 1.8 で net/http パッケージに Server.Shutdown メソッドが追加されます。

シグネチャはこちら:

func (srv *Server) Shutdown(ctx context.Context) error

使い方

ざっくりと使い方はこんな感じ。

srv := &http.Server{Addr: ":8080"}

// サーバはブロックするので別の goroutine で実行する
go func() {
    if err := srv.ListenAndServe(); err != nil {
        log.Print(err)
    }
}()

// シグナルを待つ
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGTERM)
<-sigCh

// シグナルを受け取ったらShutdown
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
if err := srv.Shutdown(ctx); err != nil {
    log.Print(err)
}

go-server-starter で試してみる

go-server-starter でプロセスを再起動するようにし、ベンチマークをかけてみます。

go get

go get github.com/lestrrat/go-server-starter/cmd/start_server

コード

末尾に掲載しています。

run

サーバを起動します。

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

starting new worker 4043

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

> curl http://localhost:8080/

Hello, Go 1.8!

restart

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

> kill -HUP `cat app.pid`

received HUP (num_old_workers=TODO)
spawning a new worker (num_old_workers=TODO)
starting new worker 4051
new worker is now running, sending TERM to old workers:4043
sleep 0 secs
killing old workers
2016/12/13 06:23:01 http: Server closed
old worker 4043 died, status:0

stop

サーバの停止は TERM です。

> kill -TERM `cat app.pid`

ab で負荷をかけてみる

サーバが起動させた状態で、以下のようにシグナル HUP を1秒毎に送り続けて再起動させ続けます。

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

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

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

Results

Server Software:
Server Hostname:        localhost
Server Port:            8080

Document Path:          /
Document Length:        15 bytes

Concurrency Level:      1000
Time taken for tests:   10.674 seconds
Complete requests:      100000
Failed requests:        0
Total transferred:      11200000 bytes
HTML transferred:       1500000 bytes
Requests per second:    9368.48 [#/sec] (mean)
Time per request:       106.741 [ms] (mean)
Time per request:       0.107 [ms] (mean, across all concurrent requests)
Transfer rate:          1024.68 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   2.5      1      27
Processing:   100  105   5.4    103     178
Waiting:        0    2   3.4      1      48
Total:        100  106   6.9    105     194

Percentage of the requests served within a certain time (ms)
  50%    105
  66%    106
  75%    107
  80%    108
  90%    111
  95%    114
  98%    122
  99%    134
 100%    194 (longest request)

再起動を繰り返しながらでも、問題なく処理できたようです。

Environment

  • go version go1.8beta2 linux/amd64
  • Amazon EC2 c4.large
  • Linux version 4.4.23-31.54.amzn1.x86_64

コード全体

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"

    "github.com/lestrrat/go-server-starter/listener"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, ")
    w.(http.Flusher).Flush()
    time.Sleep(time.Millisecond * 100)
    fmt.Fprint(w, "Go 1.8!\n")
}

func main() {
    listeners, err := listener.ListenAll()
    if err != nil && err != listener.ErrNoListeningTarget {
        log.Fatal(err)
    }

    server := &http.Server{Handler: http.HandlerFunc(handler)}

    go func(){
        if err := server.Serve(listeners[0]); err != nil {
            log.Print(err)
        }
    }()

    sigCh := make(chan os.Signal, 1)
    signal.Notify(sigCh, syscall.SIGTERM)

    <-sigCh
    ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
    if err := server.Shutdown(ctx); err != nil {
        log.Print(err)
    }
}

License: MIT


当初の記事の公開時点では、コードの書き方に問題があり、Shutdownを待たずにプロセス終了してしまっており、Gracefulになっていませんでした。

shogo82148 さんのコメントのおかげで修正できました。ありがとうございます。

87
60
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
87
60