Linux性能优化实战 47-48 服务器丢包的检测思路

时间:2024-04-06 21:24:59

1. 执行 wrk 命令,来测试 Nginx 的性能

Linux性能优化实战 47-48 服务器丢包的检测思路

可以看到吞吐量(也就是每秒请求数)只有 189,并且所有 1910 个请求收到的都是异常响应(非 2xx 或 3xx)。

数据显然表明,吞吐量太低了,并且请求处理都失败。

以下开始查找原因。

2. 使用ss查看 TCP 连接数的汇总情况

Linux性能优化实战 47-48 服务器丢包的检测思路

成功建立连接数太少了,是 timewait 状态太多了。

3. 查看系统系统日志

Linux性能优化实战 47-48 服务器丢包的检测思路

4. 查看连接跟踪数

Linux性能优化实战 47-48 服务器丢包的检测思路

发现最大值太小了,改大:

Linux性能优化实战 47-48 服务器丢包的检测思路

wrk 命令,重新测试 Nginx 的性能:

Linux性能优化实战 47-48 服务器丢包的检测思路

真正成功的只有 8000 多个(54221-45577=8644)。大部分请求的响应都是异常的

5. 查询 Nginx 容器日志

Linux性能优化实战 47-48 服务器丢包的检测思路

499表示服务器端还没来得及响应时,客户端就已经关闭连接了。

问题在于服务器端处理太慢,客户端因为超时(wrk 超时时间为 2s),主动断开了连接。

6. 查询 PHP 容器日志

Linux性能优化实战 47-48 服务器丢包的检测思路

两条警告信息,server reached max_children setting (5),并建议增大 max_children。

max_children 表示 php-fpm 子进程的最大数量,每个 php-fpm 子进程可能会占用 20 MB 左右的内存。

把它设置成了 20。重新测试 Nginx 的性能:

Linux性能优化实战 47-48 服务器丢包的检测思路

4000 多的吞吐量显然还是比较差的,并且大部分请求的响应依然还是异常。

7. 观察有没有发生套接字的丢包现象

Linux性能优化实战 47-48 服务器丢包的检测思路

有大量的套接字丢包,并且丢包都是套接字队列溢出导致的。

8. 查看套接字的队列大小  ss -ltnp

Linux性能优化实战 47-48 服务器丢包的检测思路

php-fpm 也已经接近了最大值。很明显,套接字监听队列的长度太小了,需要增大。

Linux性能优化实战 47-48 服务器丢包的检测思路

把 Nginx 和 php-fpm 的队列长度增大到8192,而把 somaxconn 增大到 65536。

重新测试 Nginx 的性能:

Linux性能优化实战 47-48 服务器丢包的检测思路

同时,在另一终端重新执行 netstat -s | grep socket

已经没有套接字丢包问题了。但是,Nginx 的响应,再一次全部失败了

9. 再次查看 Nginx 日志

Linux性能优化实战 47-48 服务器丢包的检测思路

这个错误消息对应的错误代码为 EADDRNOTAVAIL,表示 IP 地址或者端口号不可用。

10. 端口号优化

查询系统配置的临时端口号范围:

Linux性能优化实战 47-48 服务器丢包的检测思路

端口的范围只有 50 个,显然太小了 。把端口号范围扩展为 “10000 65535”:

Linux性能优化实战 47-48 服务器丢包的检测思路

再次测试性能:

Linux性能优化实战 47-48 服务器丢包的检测思路

异常的响应少了,但 出现了很多 Socket read errors。

11. 执行top,观察CPU和内存的变化

Linux性能优化实战 47-48 服务器丢包的检测思路

两个 CPU 的系统 CPU 使用率都接近 50%,Nginx 进程和两个 docker 相关的进程占用,使用率都是 30% 左右。

瓶颈在CPU。

12. 火焰图,寻找热点函数

Linux性能优化实战 47-48 服务器丢包的检测思路

Linux性能优化实战 47-48 服务器丢包的检测思路

do_syscall_64、tcp_v4_connect、inet_hash_connect 这个堆栈,很明显就是最需要关注的地方。

inet_hash_connect() 是Linux 内核中负责分配临时端口号的函数。

瓶颈应该还在临时端口的分配上。

再顺着 inet_hash_connect 往堆栈上面查看,下一个热点是 __init_check_establishe函数。

这个函数的目的,是检查端口号是否可用。

说明有大量连接占用着端口,查端口号可用的函数,消耗更多的 CPU。

13. ss 命令, 查看连接状态统计

Linux性能优化实战 47-48 服务器丢包的检测思路

有大量连接(这儿是 32768)处于 timewait 状态,而 timewait 状态的连接,本身会继续占用端口号。

如果这些端口号可以重用,那么自然就可以缩短 __init_check_established 的过程。

14. 设置端口重用

查询状态:

Linux性能优化实战 47-48 服务器丢包的检测思路

把它设置成 1 就可以开启。

输入: net.ipv4.tcp_tw_reuse = 1

再次测试优化后的效果:

Linux性能优化实战 47-48 服务器丢包的检测思路

吞吐量已经达到了 5000 多,并且只有少量的 Socket errors,也不再有 Non-2xx or 3xx 的响应了。

说明一切终于正常了。