Help us understand the problem. What is going on with this article?

golang Echoでhttpの最大接続数を設定する

golang + Echoで実装されたWebサーバの最大接続数を制限する方法です。

前提条件

Custom Listenerを利用する

https://echo.labstack.com/guide/customization

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を作成する

https://godoc.org/golang.org/x/net/netutil

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)
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away