mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-03 16:21:14 +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 {
|
if err != nil {
|
||||||
logger.Fatalf("cannot start http server at %s: %s", addr, err)
|
logger.Fatalf("cannot start http server at %s: %s", addr, err)
|
||||||
}
|
}
|
||||||
setNetworkTimeouts(lnTmp)
|
|
||||||
ln := net.Listener(lnTmp)
|
ln := net.Listener(lnTmp)
|
||||||
|
|
||||||
if *tlsEnable {
|
if *tlsEnable {
|
||||||
@ -87,29 +86,18 @@ func Serve(addr string, rh RequestHandler) {
|
|||||||
serveWithListener(addr, ln, rh)
|
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) {
|
func serveWithListener(addr string, ln net.Listener, rh RequestHandler) {
|
||||||
s := &http.Server{
|
s := &http.Server{
|
||||||
Handler: gzipHandler(rh),
|
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)),
|
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
|
||||||
|
|
||||||
// Do not set ReadTimeout and WriteTimeout here.
|
ReadHeaderTimeout: 5 * time.Second,
|
||||||
// Network-level timeouts are set in setNetworkTimeouts.
|
IdleTimeout: time.Minute,
|
||||||
// Application-level timeouts must be set in the app.
|
|
||||||
|
|
||||||
// Do not set IdleTimeout, since it is equivalent to read timeout
|
// Do not set ReadTimeout and WriteTimeout here,
|
||||||
// set in setNetworkTimeouts.
|
// since these timeouts must be controlled by request handlers.
|
||||||
|
|
||||||
ErrorLog: logger.StdErrorLogger(),
|
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 {
|
func MustServe(ln net.Listener, insertHandler func(req *http.Request) error) *Server {
|
||||||
h := newRequestHandler(insertHandler)
|
h := newRequestHandler(insertHandler)
|
||||||
hs := &http.Server{
|
hs := &http.Server{
|
||||||
Handler: h,
|
Handler: h,
|
||||||
ReadTimeout: 30 * time.Second,
|
ReadHeaderTimeout: 5 * time.Second,
|
||||||
WriteTimeout: 10 * time.Second,
|
IdleTimeout: time.Minute,
|
||||||
|
// Do not set ReadTimeout and WriteTimeout here,
|
||||||
|
// since these timeouts must be controlled by request handler.
|
||||||
}
|
}
|
||||||
s := &Server{
|
s := &Server{
|
||||||
s: hs,
|
s: hs,
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/metrics"
|
"github.com/VictoriaMetrics/metrics"
|
||||||
)
|
)
|
||||||
@ -48,29 +47,12 @@ type statConn struct {
|
|||||||
|
|
||||||
closeCalls uint64
|
closeCalls uint64
|
||||||
|
|
||||||
readTimeout time.Duration
|
|
||||||
lastReadTime time.Time
|
|
||||||
|
|
||||||
writeTimeout time.Duration
|
|
||||||
lastWriteTime time.Time
|
|
||||||
|
|
||||||
net.Conn
|
net.Conn
|
||||||
|
|
||||||
cm *connMetrics
|
cm *connMetrics
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *statConn) Read(p []byte) (int, error) {
|
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)
|
n, err := sc.Conn.Read(p)
|
||||||
sc.cm.readCalls.Inc()
|
sc.cm.readCalls.Inc()
|
||||||
sc.cm.readBytes.Add(n)
|
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) {
|
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)
|
n, err := sc.Conn.Write(p)
|
||||||
sc.cm.writeCalls.Inc()
|
sc.cm.writeCalls.Inc()
|
||||||
sc.cm.writtenBytes.Add(n)
|
sc.cm.writtenBytes.Add(n)
|
||||||
|
@ -49,20 +49,6 @@ func getNetwork() string {
|
|||||||
//
|
//
|
||||||
// It also gathers various stats for the accepted connections.
|
// It also gathers various stats for the accepted connections.
|
||||||
type TCPListener struct {
|
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
|
net.Listener
|
||||||
|
|
||||||
accepts *metrics.Counter
|
accepts *metrics.Counter
|
||||||
@ -87,9 +73,6 @@ func (ln *TCPListener) Accept() (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
ln.conns.Inc()
|
ln.conns.Inc()
|
||||||
sc := &statConn{
|
sc := &statConn{
|
||||||
readTimeout: ln.ReadTimeout,
|
|
||||||
writeTimeout: ln.WriteTimeout,
|
|
||||||
|
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
cm: &ln.connMetrics,
|
cm: &ln.connMetrics,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user