change default value of heartbeat interval and timeout when tcpmux enabled (#4186)

This commit is contained in:
fatedier 2024-04-28 20:48:44 +08:00 committed by GitHub
parent 405969085f
commit ee3892798d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 34 additions and 25 deletions

View File

@ -1,3 +1,9 @@
### Notable Changes
We have optimized the heartbeat mechanism when tcpmux is enabled (enabled by default). The default value of `heartbeatInterval` has been adjusted to -1. This update ensures that when tcpmux is active, the client does not send additional heartbeats to the server. Since tcpmux incorporates its own heartbeat system, this change effectively reduces unnecessary data consumption, streamlining communication efficiency between client and server.
When connecting to frps versions older than v0.39.0 might encounter compatibility issues due to changes in the heartbeat mechanism. As a temporary workaround, setting the `heartbeatInterval` to 30 can help maintain stable connectivity with these older versions. We recommend updating to the latest frps version to leverage full functionality and improvements.
### Features ### Features
* Show tcpmux proxies on the frps dashboard. * Show tcpmux proxies on the frps dashboard.

View File

@ -20,8 +20,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/samber/lo"
"github.com/fatedier/frp/client/proxy" "github.com/fatedier/frp/client/proxy"
"github.com/fatedier/frp/client/visitor" "github.com/fatedier/frp/client/visitor"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
@ -236,10 +234,8 @@ func (ctl *Control) registerMsgHandlers() {
func (ctl *Control) heartbeatWorker() { func (ctl *Control) heartbeatWorker() {
xl := ctl.xl xl := ctl.xl
// TODO(fatedier): Change default value of HeartbeatInterval to -1 if tcpmux is enabled.
// Users can still enable heartbeat feature by setting HeartbeatInterval to a positive value.
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 { if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 {
// send heartbeat to server // Send heartbeat to server.
sendHeartBeat := func() (bool, error) { sendHeartBeat := func() (bool, error) {
xl.Debugf("send heartbeat to server") xl.Debugf("send heartbeat to server")
pingMsg := &msg.Ping{} pingMsg := &msg.Ping{}
@ -263,10 +259,8 @@ func (ctl *Control) heartbeatWorker() {
) )
} }
// Check heartbeat timeout only if TCPMux is not enabled and users don't disable heartbeat feature. // Check heartbeat timeout.
if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 && ctl.sessionCtx.Common.Transport.HeartbeatTimeout > 0 && if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 && ctl.sessionCtx.Common.Transport.HeartbeatTimeout > 0 {
!lo.FromPtr(ctl.sessionCtx.Common.Transport.TCPMux) {
go wait.Until(func() { go wait.Until(func() {
if time.Since(ctl.lastPong.Load().(time.Time)) > time.Duration(ctl.sessionCtx.Common.Transport.HeartbeatTimeout)*time.Second { if time.Since(ctl.lastPong.Load().(time.Time)) > time.Duration(ctl.sessionCtx.Common.Transport.HeartbeatTimeout)*time.Second {
xl.Warnf("heartbeat timeout") xl.Warnf("heartbeat timeout")

View File

@ -136,8 +136,14 @@ func (c *ClientTransportConfig) Complete() {
c.PoolCount = util.EmptyOr(c.PoolCount, 1) c.PoolCount = util.EmptyOr(c.PoolCount, 1)
c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true)) c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true))
c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 60) c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 60)
if lo.FromPtr(c.TCPMux) {
// If TCPMux is enabled, heartbeat of application layer is unnecessary because we can rely on heartbeat in tcpmux.
c.HeartbeatInterval = util.EmptyOr(c.HeartbeatInterval, -1)
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, -1)
} else {
c.HeartbeatInterval = util.EmptyOr(c.HeartbeatInterval, 30) c.HeartbeatInterval = util.EmptyOr(c.HeartbeatInterval, 30)
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90) c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90)
}
c.QUIC.Complete() c.QUIC.Complete()
c.TLS.Complete() c.TLS.Complete()
} }

View File

@ -179,7 +179,12 @@ func (c *ServerTransportConfig) Complete() {
c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 60) c.TCPMuxKeepaliveInterval = util.EmptyOr(c.TCPMuxKeepaliveInterval, 60)
c.TCPKeepAlive = util.EmptyOr(c.TCPKeepAlive, 7200) c.TCPKeepAlive = util.EmptyOr(c.TCPKeepAlive, 7200)
c.MaxPoolCount = util.EmptyOr(c.MaxPoolCount, 5) c.MaxPoolCount = util.EmptyOr(c.MaxPoolCount, 5)
if lo.FromPtr(c.TCPMux) {
// If TCPMux is enabled, heartbeat of application layer is unnecessary because we can rely on heartbeat in tcpmux.
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, -1)
} else {
c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90) c.HeartbeatTimeout = util.EmptyOr(c.HeartbeatTimeout, 90)
}
c.QUIC.Complete() c.QUIC.Complete()
if c.TLS.TrustedCaFile != "" { if c.TLS.TrustedCaFile != "" {
c.TLS.Force = true c.TLS.Force = true

View File

@ -297,12 +297,11 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
} }
func (ctl *Control) heartbeatWorker() { func (ctl *Control) heartbeatWorker() {
xl := ctl.xl if ctl.serverCfg.Transport.HeartbeatTimeout <= 0 {
return
}
// Don't need application heartbeat if TCPMux is enabled, xl := ctl.xl
// yamux will do same thing.
// TODO(fatedier): let default HeartbeatTimeout to -1 if TCPMux is enabled. Users can still set it to positive value to enable it.
if !lo.FromPtr(ctl.serverCfg.Transport.TCPMux) && ctl.serverCfg.Transport.HeartbeatTimeout > 0 {
go wait.Until(func() { go wait.Until(func() {
if time.Since(ctl.lastPing.Load().(time.Time)) > time.Duration(ctl.serverCfg.Transport.HeartbeatTimeout)*time.Second { if time.Since(ctl.lastPing.Load().(time.Time)) > time.Duration(ctl.serverCfg.Transport.HeartbeatTimeout)*time.Second {
xl.Warnf("heartbeat timeout") xl.Warnf("heartbeat timeout")
@ -311,7 +310,6 @@ func (ctl *Control) heartbeatWorker() {
} }
}, time.Second, ctl.doneCh) }, time.Second, ctl.doneCh)
} }
}
// block until Control closed // block until Control closed
func (ctl *Control) WaitClosed() { func (ctl *Control) WaitClosed() {