TCP 协议的KeepAlive
KeepAlive 并不是 TCP 协议规范的一部分,但在几乎所有的 TCP/IP 协议栈(不管是 Linux 还是 Windows)中,都实现了 KeepAlive 功能。
参考 [RFC1122 #TCP Keep-Alives] @ref
TCP 协议栈与 KeepAlive 相关的参数有:
- tcp_keepalive_time: KeepAlive 的空闲时长,或者说每次正常发送心跳的周期,默认值为 7200 s(2 小时)@doubt
- tcp_keepalive_intvl: KeepAlive 探测包的发送间隔,默认值为 75s
- tcp_keepalive_probes: 在 tcp_keepalive_time 之后,没有接收到对方确认,继续发送保活探测包次数,默认值为 9(次)
以上参数都可以通过 sysctl 命令修改内核参数实现修改:
sysctl -w net.ipv4.tcp_keepalive_time = 7500
,
更多 sysctl 使用参考 [[../21.Operating-System/Linux.04a.Sysctl]]
KeepAlive 默认情况下是关闭的,可以被上层应用开启和关闭, 下面介绍在 Java、C 语言和 Nginx 中如何设置 KeepAlive
代码和应用程序如何设置 Keepalive
Java(Netty)设置 KeepAlive
ServerBootstrap b = new ServerBootstrap(); |
Java 程序只能做到设置 SO_KEEPALIVE
选项,其他配置项只能依赖于 sysctl 配置,系统进行读取。
C 语言 socket 编程设置 KeepAlive
setsockopt 函数原型:
int setsockopt(int socket, int level, int option_name,
const void *option_value, socklen_t option_len);
How to use:int socket(int domain, int type, int protocol)
{
int (*libc_socket)(int, int, int);
int s, optval;
char *env;
*(void **)(&libc_socket) = dlsym(RTLD_NEXT, "socket");
if(dlerror()) {
errno = EACCES;
return -1;
}
if((s = (*libc_socket)(domain, type, protocol)) != -1) {
if((domain == PF_INET) && (type == SOCK_STREAM)) {
if(!(env = getenv("KEEPALIVE")) || strcasecmp(env, "off")) {
optval = 1;
} else {
optval = 0;
}
if(!(env = getenv("KEEPALIVE")) || strcasecmp(env, "skip")) {
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
}
// ...
}
}
return s;
}
代码摘取自 libkeepalive 源码,C 语言可以设置更为详细的 TCP 内核参数
Nginx 配置 KeepAlive
Nginx 配置里有两处 KeepAlive, 含义不同:
- listen 下的
so_keepalive=30m::10
: 设置TCP_KEEPIDLE
为 30 分钟,TCP_KEEPINTVL
默认值,TCP_KEEPCNT
设为 10 probes - 注意区分 upstream 下的
keepalive N
这里不是指超时, N 指的是每个 Worker 与 upstream 服务器可缓存的最大连接数,
KeepAlive 使用场景
常见的几种使用场景:
- 检测挂掉的连接(导致连接挂掉的原因很多,如服务停止、网络波动、宕机、应用重启等)
- 防止因为网络不活动而断连(使用 NAT 代理或者防火墙的时候,经常会出现这种问题)
- TCP 层面的心跳检测
通常很多应用程序也有类似 KeepAlive 的心跳检测, 和 TCP KeepAlive 区别在于:
- TCP 的 KeepAlive 发送的数据包相比应用层心跳检测包更小,仅提供检测连接功能
- 应用层心跳包不依赖于传输层协议,无论传输层协议是 TCP 还是 UDP 都可以用
- 应用层心跳包可以定制,可以应对更复杂的情况或传输一些额外信息
- KeepAlive 仅代表 TCP 层连接仍保持着,而心跳包往往还代表客户端可正常工作
比较 Http 协议头中 Keep-Alive
在 Http Response 的 http 头可以看到下面的字段:HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 40026
Connection: keep-alive
HTTP 协议采用“请求-应答”模式,当使用普通模式,即非 KeepAlive 模式时,每个请求/应答客户和服务器都要新建一个连接,完成之后立即断开连接(HTTP 协议为无连接的协议);当使用 Keep-Alive 模式(又称持久连接、连接重用)时,Keep-Alive 功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。
http 1.0 中默认是关闭的, http 1.1 中默认启用 Keep-Alive
@ref: https://blog.biezhi.me/2017/08/talk-tcp-keepalive.html