Linux下Http高并发参数优化之keepalive

 2017-06-06 22:19:32     TCP/IP  HTTP  Linux   3241


导读: Linux 系统参数设置后,应用服务的并发量并不会出现显著的提升。这是因为应用服务一般都是采用 HTTP 协议,而 HTTP 是一种无状态的、基于请求+响应的协议。也就是俗称的 “短连接”,对应的解决方案是 “长连接”。长连接用到 `keepalive` ,它又分 TCP keepalive 和 HTTP keepalive 。

TCP 的 keepalive 是检查当前TCP连接是否活着。

HTTP的 keepalive 是要让一个 TCP 连接活久点。

TCP keepalive


因为 TCP 的上层调用是 Socket,客户端和服务端都会启动 Socket。如果客户端关闭了 Socket,而服务端不知道,一直会为客户端保持着连接,这样是很浪费资源的。为了解决这个问题,TCP协议规定,当超过一段时间之后,TCP自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,连接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为连接丢失,应该关闭连接。

Linux 内核包含了对 keepalive 的支持,使用下面三个参数(默认单位为秒)。

# 表示TCP链接在多少秒之后没有数据报文传输时启动探测报文(发送空的报文)
cat /proc/sys/net/ipv4/tcp_keepalive_time 
7200

# 表示前一个探测报文和后一个探测报文之间的时间间隔
cat /proc/sys/net/ipv4/tcp_keepalive_intvl
75

# 表示探测的次数
cat /proc/sys/net/ipv4/tcp_keepalive_probes
9

这些参数是在 /etc/sysctl.conf 文件中定义的,默认文件中没有定义这三个参数,但系统提供的有默认值。可以根据需要进行修改,修改后,执行sysctl -p命令让其生效。

net.ipv4.tcp_keepalive_time = 900
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3

在socket编程时候,可以通过以下参数设置。


TCP_KEEPIDLE: tcp_keepalive_time

TCP_KEEPCNT: tcp_keepalive_probes

TCP_KEEPINTVL: tcp_keepalive_intvl

HTPP keepalive


在说 HTTP keepalive 之前,先理解 HTTP 与 TCP/IP 的关系。我们知道 HTTP 是应用层,是建立在 TCP/IP 协议基础之上的,客户端和服务端通过 TCP/IP 协议建立连接后,就可以进行数据传输,而 HTTP 协议使用了TCP传输HTTP协议的请求(Request)和响应(Response)数据。

HTTP事务图

这里简化了HTTP(Req)和HTTP(Resp),实际上的请求和响应需要多个TCP报文。

HTTP 连接的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为 "一次连接"。

HTTP 的一次连接相当于调用了 TCP/IP 协议的三次握手建立连接,TCP 协议的多次数据传,TCP/IP 协议 断开连接的四次握手。

可想而知,上面这种原始的方式是多么的低效。为了减少频繁的建立连接和关闭连接,从 HTTP1.1 版本,开始支持了 keepalive 。目前,绝大部分服务框架和浏览器的 HTTP 协议版本默认都是1.1。

设置了 keepalive 。客户端与服务端一旦建立 TCP/IP 连接后,会保持连接一段时间,在这段时间内,HTTP 就可以直接进行数据传输。如果 HTTP 主动告知关闭,或者达到 TCP 关闭的条件,那么 TCP/IP 就会关闭。这也就是 HTTP keepalive 能让 TCP 连接活久点的原因。

如果没有,可以通过设置使其支持。

客户端设置: 在 HTTP 请求头需要增加 Connection: keep-alive 字段。

服务端设置: 要先识别客户端的 Connection: keep-alive 字段,且在 http 的 response 里设置 Connection: keep-alive 字段。

是不是这样设置后,keep-alive 就起到作用呢? 答案是并不一定。这是需要综合考虑服务架构的。我们的应用服务通常会涉及到负载均衡、转发、反向代理等。简化一下架构,就是 Nginx + 应用服务。通常的使用方式如下。

Nginx代理

Nginx


keepalive_timeout

Nginx 默认是支持 keepalive的,是通过 keepalive_timeout 设置的,默认值是75s。它表示在长连接开启的情况下,在75s内如果没有 http 请求,则关闭长连接(其实就是关闭 tcp)。

此值可以根据情况进行调整,如果设置过大,则服务器需要长时间保持客户端的连接信息,会存在浪费资源的问题;太小的话,又起不到长连接的优势。

例如:如果客户端平均触发请求的间隔时间在2分钟,那么此值可以设置为3~5分钟;如果间隔时间在30秒,此值可以设置为1~2分钟。

如果客户端的请求间隔时间在10分钟以上,那么此值没有必要调大,设置为2分钟就可以了。客户端一次触发请求,例如点击连接,会发送N个 Http 请求,而这些请求在1分钟内就会完成。所以,将 keepalive_timeout 设置为2分钟,即可以起到N个 Http 请求利用长连接,又可以减少服务器的资源浪费。

keepalive_requests

此值容易被忽略,它是值在 keepalive_timeout 的时间范围内,一个长连接最大允许的请求次数,如果超过此值,也会关闭此长连接。默认值为100。

例如:keepalive_timeout 为2分钟,在2分钟时间内,A长连接发送了101个 Http 请求,那么第101个请求就会重新建立连接,即使长连接时间没有超过2分钟。

此值也应该根据业务情况来定,一般默认值100就够用。

upstream keepalive

Nginx 一般用在反向代理,将请求代理到业务服务上。在设置上也需要注意。

upstream http_backend {
    server 127.0.0.1:8080;
    keepalive 1000;
}

keepalive 是指 Nginx 每个 worker 连接后端的最大长连接数,而不是整个 Nginx 的。 而且这里的后端指的是「所有的后端」,而不是每一个后端。

…

location /http/ {
    proxy_pass http://http_backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    …
}

proxy_http_version 指定 HTTP 版本,防止 1.0 版本导致 keepalive 无效。

proxy_set_header 清空将客户端的一些设置,防止导致 keepalive 无效。

Nginx 代理的服务如果是 Tomcat 等容器,也需要 Tomcat 进行长连接的相关设置。

worker_cpu_affinity

Nginx默认没有开启利用多核cpu,我们可以通过增加worker_cpu_affinity配置参数来充分利用多核cpu的性能。cpu是任务处理,计算最关键的资源,cpu核越多,性能就越好。

两核cpu,开启两个进程。

worker_processes  2;  
worker_cpu_affinity 01 10;

两核cpu,开启八个进程。

worker_processes  8;  
worker_cpu_affinity 01 10 01 10 01 10 01 10;

8核cpu,开启8个进程。

worker_processes  8;  
worker_cpu_affinity 10000000 01000000 00100000 00010000 00001000 00000100 00000010 00000001;

也可以配置成自动分配的。

worker_processes  auto;  
worker_cpu_affinity auto;

参考: