golang + Echoで実装されたWebサーバの最大接続数を制限する方法です。
前提条件
- golang
- 1.12
- WebFramework
- https://github.com/labstack/echo
- v4.1.10
Custom Listenerを利用する
Echoはnet.Listenerを設定できるようになっているので同時接続数を制限したListenerを設定してやる。
cf. https://github.com/labstack/echo/blob/master/echo.go#L79
Echo struct {
common
StdLogger *stdLog.Logger
colorer *color.Color
premiddleware []MiddlewareFunc
middleware []MiddlewareFunc
maxParam *int
router *Router
routers map[string]*Router
notFoundHandler HandlerFunc
pool sync.Pool
Server *http.Server
TLSServer *http.Server
Listener net.Listener
TLSListener net.Listener
AutoTLSManager autocert.Manager
DisableHTTP2 bool
Debug bool
HideBanner bool
HidePort bool
HTTPErrorHandler HTTPErrorHandler
Binder Binder
Validator Validator
Renderer Renderer
Logger Logger
}
netutilを使ってListenerを作成する
ln, err := net.Listen("tcp", ポート番号)
if err != nil {
log.Fatal(err)
}
// LimitListenerの作成
listener := netutil.LimitListener(ln, 同時接続数)
実装例
package main
import (
"log"
"net"
"net/http"
"time"
"golang.org/x/net/netutil"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
e.HideBanner = true
e.HidePort = true
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.GET("/", func(c echo.Context) error {
time.Sleep(995 * time.Millisecond)
return c.String(http.StatusOK, "Hello, World!\n")
})
ln, err := net.Listen("tcp", ":1323")
if err != nil {
log.Fatal(err)
}
// LimitListenerの作成
listener := netutil.LimitListener(ln, 2)
e.Listener = listener
e.Logger.Fatal(e.Start(""))
}
ざっくりと検証
vegetaでリクエストした結果、多少の誤差はありますがほぼ期待した動作をしているようです。
$ echo "GET http://localhost:1323/" | vegeta attack -rate=3 -duration=10s | vegeta report
Requests [total, rate] 30, 3.10
Duration [total, attack, wait] 39.337579882s, 9.663924965s, 29.673654917s
Latencies [mean, 50, 95, 99, max] 12.601428969s, 1.000919979s, 30.005719753s, 30.005729277s, 30.005729277s
Bytes In [total, mean] 252, 8.40
Bytes Out [total, mean] 0, 0.00
Success [ratio] 60.00%
Status Codes [code:count] 0:12 200:18
Error Set:
Get http://localhost:1323/: net/http: request canceled (Client.Timeout exceeded while awaiting headers)