mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-02-09 15:27:11 +00:00
lib/httpserver: add -http.connTimeout
command-line flag for limiting the lifetime for incoming http connections
This can be useful for balancing incoming connections among multiple services.
This commit is contained in:
parent
e1c2757f70
commit
d387da142e
1 changed files with 22 additions and 0 deletions
|
@ -18,6 +18,7 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime"
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/netutil"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/netutil"
|
||||||
"github.com/VictoriaMetrics/metrics"
|
"github.com/VictoriaMetrics/metrics"
|
||||||
|
@ -43,6 +44,8 @@ var (
|
||||||
shutdownDelay = flag.Duration("http.shutdownDelay", 0, "Optional delay before http server shutdown. During this dealy the servier returns non-OK responses "+
|
shutdownDelay = flag.Duration("http.shutdownDelay", 0, "Optional delay before http server shutdown. During this dealy the servier returns non-OK responses "+
|
||||||
"from /health page, so load balancers can route new requests to other servers")
|
"from /health page, so load balancers can route new requests to other servers")
|
||||||
idleConnTimeout = flag.Duration("http.idleConnTimeout", time.Minute, "Timeout for incoming idle http connections")
|
idleConnTimeout = flag.Duration("http.idleConnTimeout", time.Minute, "Timeout for incoming idle http connections")
|
||||||
|
connTimeout = flag.Duration("http.connTimeout", 2*time.Minute, "Incoming http connections are closed after the configured timeout. This may help spreading incoming load "+
|
||||||
|
"among a cluster of services behind load balancer")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -111,6 +114,11 @@ func serveWithListener(addr string, ln net.Listener, rh RequestHandler) {
|
||||||
// since these timeouts must be controlled by request handlers.
|
// since these timeouts must be controlled by request handlers.
|
||||||
|
|
||||||
ErrorLog: logger.StdErrorLogger(),
|
ErrorLog: logger.StdErrorLogger(),
|
||||||
|
|
||||||
|
ConnContext: func(ctx context.Context, c net.Conn) context.Context {
|
||||||
|
startTime := fasttime.UnixTimestamp()
|
||||||
|
return context.WithValue(ctx, connStartTimeKey, &startTime)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
serversLock.Lock()
|
serversLock.Lock()
|
||||||
servers[addr] = &s
|
servers[addr] = &s
|
||||||
|
@ -124,6 +132,15 @@ func serveWithListener(addr string, ln net.Listener, rh RequestHandler) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func whetherToCloseConn(r *http.Request) bool {
|
||||||
|
ctx := r.Context()
|
||||||
|
v := ctx.Value(connStartTimeKey)
|
||||||
|
st, ok := v.(*uint64)
|
||||||
|
return ok && fasttime.UnixTimestamp()-*st > uint64(*connTimeout/time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
var connStartTimeKey = interface{}("startTime")
|
||||||
|
|
||||||
// Stop stops the http server on the given addr, which has been started
|
// Stop stops the http server on the given addr, which has been started
|
||||||
// via Serve func.
|
// via Serve func.
|
||||||
func Stop(addr string) error {
|
func Stop(addr string) error {
|
||||||
|
@ -168,9 +185,14 @@ func gzipHandler(s *server, rh RequestHandler) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
var metricsHandlerDuration = metrics.NewHistogram(`vm_http_request_duration_seconds{path="/metrics"}`)
|
var metricsHandlerDuration = metrics.NewHistogram(`vm_http_request_duration_seconds{path="/metrics"}`)
|
||||||
|
var connTimeoutClosedConns = metrics.NewCounter(`vm_http_conn_timeout_closed_conns_total`)
|
||||||
|
|
||||||
func handlerWrapper(s *server, w http.ResponseWriter, r *http.Request, rh RequestHandler) {
|
func handlerWrapper(s *server, w http.ResponseWriter, r *http.Request, rh RequestHandler) {
|
||||||
requestsTotal.Inc()
|
requestsTotal.Inc()
|
||||||
|
if whetherToCloseConn(r) {
|
||||||
|
connTimeoutClosedConns.Inc()
|
||||||
|
w.Header().Set("Connection", "close")
|
||||||
|
}
|
||||||
path, err := getCanonicalPath(r.URL.Path)
|
path, err := getCanonicalPath(r.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Errorf(w, r, "cannot get canonical path: %s", err)
|
Errorf(w, r, "cannot get canonical path: %s", err)
|
||||||
|
|
Loading…
Reference in a new issue