mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-23 20:37:12 +01:00
lib/httpserver: reduce typical duration for http server graceful shutdown
Previously the duration for graceful shutdown for http server could take more than a minute because of imporperly set timeouts in setNetworkTimeout. Now typical duration for graceful shutdown should be reduced to less than 5 seconds.
This commit is contained in:
parent
6afb25fd08
commit
787fcfba0c
@ -71,7 +71,6 @@ func Serve(addr string, rh RequestHandler) {
|
||||
if err != nil {
|
||||
logger.Fatalf("cannot start http server at %s: %s", addr, err)
|
||||
}
|
||||
setNetworkTimeouts(lnTmp)
|
||||
ln := net.Listener(lnTmp)
|
||||
|
||||
if *tlsEnable {
|
||||
@ -87,29 +86,18 @@ func Serve(addr string, rh RequestHandler) {
|
||||
serveWithListener(addr, ln, rh)
|
||||
}
|
||||
|
||||
func setNetworkTimeouts(ln *netutil.TCPListener) {
|
||||
// Set network-level read and write timeouts to reasonable values
|
||||
// in order to protect from DoS or broken networks.
|
||||
// Application-level timeouts must be set by the authors of request handlers.
|
||||
//
|
||||
// The read timeout limits the life of idle connection
|
||||
ln.ReadTimeout = time.Minute
|
||||
ln.WriteTimeout = time.Minute
|
||||
}
|
||||
|
||||
func serveWithListener(addr string, ln net.Listener, rh RequestHandler) {
|
||||
s := &http.Server{
|
||||
Handler: gzipHandler(rh),
|
||||
|
||||
// Disable http/2
|
||||
// Disable http/2, since it doesn't give any advantages for VictoriaMetrics services.
|
||||
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
|
||||
|
||||
// Do not set ReadTimeout and WriteTimeout here.
|
||||
// Network-level timeouts are set in setNetworkTimeouts.
|
||||
// Application-level timeouts must be set in the app.
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
IdleTimeout: time.Minute,
|
||||
|
||||
// Do not set IdleTimeout, since it is equivalent to read timeout
|
||||
// set in setNetworkTimeouts.
|
||||
// Do not set ReadTimeout and WriteTimeout here,
|
||||
// since these timeouts must be controlled by request handlers.
|
||||
|
||||
ErrorLog: logger.StdErrorLogger(),
|
||||
}
|
||||
|
@ -43,9 +43,11 @@ func MustStart(addr string, insertHandler func(req *http.Request) error) *Server
|
||||
func MustServe(ln net.Listener, insertHandler func(req *http.Request) error) *Server {
|
||||
h := newRequestHandler(insertHandler)
|
||||
hs := &http.Server{
|
||||
Handler: h,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
Handler: h,
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
IdleTimeout: time.Minute,
|
||||
// Do not set ReadTimeout and WriteTimeout here,
|
||||
// since these timeouts must be controlled by request handler.
|
||||
}
|
||||
s := &Server{
|
||||
s: hs,
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
)
|
||||
@ -48,29 +47,12 @@ type statConn struct {
|
||||
|
||||
closeCalls uint64
|
||||
|
||||
readTimeout time.Duration
|
||||
lastReadTime time.Time
|
||||
|
||||
writeTimeout time.Duration
|
||||
lastWriteTime time.Time
|
||||
|
||||
net.Conn
|
||||
|
||||
cm *connMetrics
|
||||
}
|
||||
|
||||
func (sc *statConn) Read(p []byte) (int, error) {
|
||||
if sc.readTimeout > 0 {
|
||||
t := time.Now()
|
||||
if t.Sub(sc.lastReadTime) > sc.readTimeout>>4 {
|
||||
d := t.Add(sc.readTimeout)
|
||||
if err := sc.Conn.SetReadDeadline(d); err != nil {
|
||||
// This error may occur when the client closes the connection before setting the deadline
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n, err := sc.Conn.Read(p)
|
||||
sc.cm.readCalls.Inc()
|
||||
sc.cm.readBytes.Add(n)
|
||||
@ -85,17 +67,6 @@ func (sc *statConn) Read(p []byte) (int, error) {
|
||||
}
|
||||
|
||||
func (sc *statConn) Write(p []byte) (int, error) {
|
||||
if sc.writeTimeout > 0 {
|
||||
t := time.Now()
|
||||
if t.Sub(sc.lastWriteTime) > sc.writeTimeout>>4 {
|
||||
d := t.Add(sc.writeTimeout)
|
||||
if err := sc.Conn.SetWriteDeadline(d); err != nil {
|
||||
// This error may accour when the client closes the connection before setting the deadline
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n, err := sc.Conn.Write(p)
|
||||
sc.cm.writeCalls.Inc()
|
||||
sc.cm.writtenBytes.Add(n)
|
||||
|
@ -49,20 +49,6 @@ func getNetwork() string {
|
||||
//
|
||||
// It also gathers various stats for the accepted connections.
|
||||
type TCPListener struct {
|
||||
// ReadTimeout is timeout for each Read call on accepted conns.
|
||||
//
|
||||
// By default it isn't set.
|
||||
//
|
||||
// Set ReadTimeout before calling Accept the first time.
|
||||
ReadTimeout time.Duration
|
||||
|
||||
// WriteTimeout is timeout for each Write call on accepted conns.
|
||||
//
|
||||
// By default it isn't set.
|
||||
//
|
||||
// Set WriteTimeout before calling Accept the first time.
|
||||
WriteTimeout time.Duration
|
||||
|
||||
net.Listener
|
||||
|
||||
accepts *metrics.Counter
|
||||
@ -87,9 +73,6 @@ func (ln *TCPListener) Accept() (net.Conn, error) {
|
||||
}
|
||||
ln.conns.Inc()
|
||||
sc := &statConn{
|
||||
readTimeout: ln.ReadTimeout,
|
||||
writeTimeout: ln.WriteTimeout,
|
||||
|
||||
Conn: conn,
|
||||
cm: &ln.connMetrics,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user