VictoriaMetrics/lib/netutil/tcpdialer.go
Will Jordan 2b7b3293c1
Add vmstorageUserTimeout flags to configure TCP user timeout (Linux) (#4423)
`TCP_USER_TIMEOUT` (since Linux 2.6.37) specifies the maximum amount of
time that transmitted data may remain unacknowledged before TCP will
forcibly close the connection and return `ETIMEDOUT` to the application.

Setting a low TCP user timeout allows RPC connections quickly reroute
around unavailable storage nodes during network interruptions.
2023-08-29 11:46:39 +02:00

80 lines
1.8 KiB
Go

package netutil
import (
"fmt"
"net"
"syscall"
"time"
"github.com/VictoriaMetrics/metrics"
)
// NewTCPDialer returns new dialer for dialing the given addr.
//
// The name is used in metric tags for the returned dialer.
// The name must be unique among dialers.
func NewTCPDialer(ms *metrics.Set, name, addr string, dialTimeout time.Duration, userTimeout time.Duration) *TCPDialer {
d := &TCPDialer{
d: &net.Dialer{
Timeout: dialTimeout,
// How frequently to send keep-alive packets over established TCP connections.
KeepAlive: time.Second,
},
addr: addr,
dials: ms.NewCounter(fmt.Sprintf(`vm_tcpdialer_dials_total{name=%q, addr=%q}`, name, addr)),
dialErrors: ms.NewCounter(fmt.Sprintf(`vm_tcpdialer_errors_total{name=%q, addr=%q, type="dial"}`, name, addr)),
}
d.connMetrics.init(ms, "vm_tcpdialer", name, addr)
if userTimeout > 0 {
d.d.Control = func(network, address string, c syscall.RawConn) (err error) {
controlErr := c.Control(func(fd uintptr) {
err = setTCPUserTimeout(fd, userTimeout)
})
if controlErr != nil {
return controlErr
}
return err
}
}
return d
}
// TCPDialer is used for dialing the addr passed to NewTCPDialer.
//
// It also gathers various stats for dialed connections.
type TCPDialer struct {
d *net.Dialer
addr string
dials *metrics.Counter
dialErrors *metrics.Counter
connMetrics
}
// Dial dials the addr passed to NewTCPDialer.
func (d *TCPDialer) Dial() (net.Conn, error) {
d.dials.Inc()
network := GetTCPNetwork()
c, err := d.d.Dial(network, d.addr)
if err != nil {
d.dialErrors.Inc()
return nil, err
}
d.conns.Inc()
sc := &statConn{
Conn: c,
cm: &d.connMetrics,
}
return sc, err
}
// Addr returns the address the dialer dials to.
func (d *TCPDialer) Addr() string {
return d.addr
}