Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net: default TCP Keep-Alive interval causes significant power usage #48622

Open
ValdikSS opened this issue Sep 25, 2021 · 2 comments
Open

net: default TCP Keep-Alive interval causes significant power usage #48622

ValdikSS opened this issue Sep 25, 2021 · 2 comments

Comments

@ValdikSS
Copy link

@ValdikSS ValdikSS commented Sep 25, 2021

Description

Golang's default TCP Keep-Alive is 15 seconds for both listening and connecting sockets.
Every time you use golang software, or connect to the website with long-polling/websockets running golang, your cell phone battery drains a lot quicker than it should.
The change has been originally introduced by:
https://go-review.googlesource.com/c/go/+/107196

There's a modern proxy application called V2ray, and it's available on Android as well. It's written in Go.
I noticed that my phone sends keep-alive packets every 3-5 seconds while keeping only 7 TCP sockets opened. The battery died rather quickly.

Current Golang version has two issues with TCP Keep-Alive interval:

  1. It is enabled by default on both listening and connecting sockets (dial.Dialer / net.Listener)
  2. It is very short (15 seconds), which creates unnecessary network load and makes cellphone radio module wake up much more frequently than it should
  3. dial.Dialer / net.Listener KeepAlive option changes both Keep-Alive time (TCP_KEEPIDLE) and Keep-Alive interval (TCP_KEEPINTVL) to the same value (can't be configured separately).

The latest item behavior is totally incorrect in my opinion. Linux uses 9 keep-alive probes of TCP_KEEPINTVL interval before closing the socket, so setting dial.Dialer KeepAlive to 300 seconds gives 50 minutes of actual socket hang detection.
If golang could set only TCP_KEEPIDLE and not touch TCP_KEEPINTVL, 300 second KeepAlive with the default Linux behavior (TCP_KEEPINTVL=75) would close the socket after ≈16 minutes, which is correct and expected. The latest behavior is widely used elsewhere.

Please note that golang also sets TCP_KEEPIDLE and TCP_KEEPINTVL by default for all listening and accepted sockets: not only golang clients, but also any clients connecting to golang servers are affected by short timeout.

What version of Go are you using (go version)?

$ go version
go version go1.17.1 linux/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

Reproducible on any architecture and any OS.

What did you do?

Use dial.Dialer / net.Listener with default settings.

What did you expect to see?

Sane Keep-Alive values

What did you see instead?

Very short Keep-Alive period and inability to tune TCP_KEEPIDLE and TCP_KEEPINTVL separately.

@beoran
Copy link

@beoran beoran commented Sep 26, 2021

As a workaround, it should be possible to call syscall.Setsockoptint on the FD of the socket. Example here for different socket options: https://stackoverflow.com/questions/40544096/how-to-set-socket-option-ip-tos-for-http-client-in-go-language#40549614

@mknyszek mknyszek changed the title Default TCP Keep-Alive interval is very short (15s), drains cell phone battery net: default TCP Keep-Alive interval causes significant power usage Oct 4, 2021
@mknyszek mknyszek added this to the Backlog milestone Oct 4, 2021
@mknyszek
Copy link
Contributor

@mknyszek mknyszek commented Oct 4, 2021

CC @neild

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants