最近,有小伙伴在群里提问:Linux系统怎么设置tcp_nodelay参数?也有小伙伴说问我。那今天,咱们就来根据这个问题来聊聊在高并发场景下如何优化服务器的性能这个话题。node
其实,tcp_nodelay参数并非在操做系统级别进行配置的,而是在TCP套接字上添加tcp_nodelay参数来关闭粘包算法,以便使数据包可以当即投递出去。tcp_nodelay参数主要是对TCP套接字来讲的,那对于服务器硬件,若是要使其可以支撑上百万甚至上千万的并发,咱们该如何对其进行优化呢?git
文章已收录到:github
https://github.com/sunshinelyz/technology-binghe算法
https://gitee.com/binghe001/technology-binghe数据库
这里,我使用的操做系统为CentOS 8,咱们能够输入以下命令来查看操做系统的版本。bash
CentOS Linux release 8.0.1905 (Core)
对于高并发的场景,咱们主要仍是优化操做系统的网络性能,而操做系统中,有不少关于网络协议的参数,咱们对于服务器网络性能的优化,主要是对这些系统参数进行调优,以达到提高咱们应用访问性能的目的。服务器
在CentOS 操做系统中,咱们能够经过以下命令来查看全部的系统参数。微信
/sbin/sysctl -a
部分输出结果以下所示。cookie
这里的参数太多了,大概有一千多个,在高并发场景下,咱们不可能对操做系统的全部参数进行调优。咱们更多的是关注与网络相关的参数。若是想得到与网络相关的参数,那么,咱们首先须要获取操做系统参数的类型,以下命令能够获取操做系统参数的类型。网络
/sbin/sysctl -a|awk -F "." '{print $1}'|sort -k1|uniq
运行命令输出的结果信息以下所示。
abi crypto debug dev fs kernel net sunrpc user vm
其中的net类型就是咱们要关注的与网络相关的操做系统参数。咱们能够获取net类型下的子类型,以下所示。
/sbin/sysctl -a|grep "^net."|awk -F "[.| ]" '{print $2}'|sort -k1|uniq
输出的结果信息以下所示。
bridge core ipv4 ipv6 netfilter nf_conntrack_max unix
在Linux操做系统中,这些与网络相关的参数均可以在/etc/sysctl.conf 文件里修改,若是/etc/sysctl.conf 文件中不存在这些参数,咱们能够自行在/etc/sysctl.conf 文件中添加这些参数。
在net类型的子类型中,咱们须要重点关注的子类型有:core和ipv4。
若是服务器的网络套接字缓冲区过小,就会致使应用程序读写屡次才能将数据处理完,这会大大影响咱们程序的性能。若是网络套接字缓冲区设置的足够大,从必定程度上可以提高咱们程序的性能。
咱们能够在服务器的命令行输入以下命令,来获取有关服务器套接字缓冲区的信息。
/sbin/sysctl -a|grep "^net."|grep "[r|w|_]mem[_| ]"
输出的结果信息以下所示。
net.core.rmem_default = 212992 net.core.rmem_max = 212992 net.core.wmem_default = 212992 net.core.wmem_max = 212992 net.ipv4.tcp_mem = 43545 58062 87090 net.ipv4.tcp_rmem = 4096 87380 6291456 net.ipv4.tcp_wmem = 4096 16384 4194304 net.ipv4.udp_mem = 87093 116125 174186 net.ipv4.udp_rmem_min = 4096 net.ipv4.udp_wmem_min = 4096
其中,带有max、default、min关键字的为分别表明:最大值、默认值和最小值;带有mem、rmem、wmem关键字的分别为:总内存、接收缓冲区内存、发送缓冲区内存。
这里须要注意的是:带有rmem 和 wmem关键字的单位都是“字节”,而带有mem关键字的单位是“页”。“页”是操做系统管理内存的最小单位,在 Linux 系统里,默认一页是 4KB 大小。
若是在高并发场景下,须要频繁的收发大文件,咱们该如何优化服务器的性能呢?
这里,咱们能够修改的系统参数以下所示。
net.core.rmem_default net.core.rmem_max net.core.wmem_default net.core.wmem_max net.ipv4.tcp_mem net.ipv4.tcp_rmem net.ipv4.tcp_wmem
这里,咱们作个假设,假设系统最大能够给TCP分配 2GB 内存,最小值为 256MB,压力值为 1.5GB。按照一页为 4KB 来计算, tcp_mem 的最小值、压力值、最大值分别是 6553六、39321六、524288,单位是“页” 。
假如平均每一个文件数据包为 512KB,每一个套接字读写缓冲区最小能够各容纳 2 个数据包,默承认以各容纳 4 个数据包,最大能够各容纳 10 个数据包,那咱们能够算出 tcp_rmem 和 tcp_wmem 的最小值、默认值、最大值分别是 104857六、209715二、5242880,单位是“字节”。而 rmem_default 和 wmem_default 是 2097152,rmem_max 和 wmem_max 是 5242880。
注:后面详细介绍这些数值是如何计算的~~
这里,还须要注意的是:缓冲区超过了 65535,还须要将 net.ipv4.tcp_window_scaling 参数设置为 1。
通过上面的分析后,咱们最终得出的系统调优参数以下所示。
net.core.rmem_default = 2097152 net.core.rmem_max = 5242880 net.core.wmem_default = 2097152 net.core.wmem_max = 5242880 net.ipv4.tcp_mem = 65536 393216 524288 net.ipv4.tcp_rmem = 1048576 2097152 5242880 net.ipv4.tcp_wmem = 1048576 2097152 5242880
对计算机网络有必定了解的小伙伴都知道,TCP的链接须要通过“三次握手”和“四次挥手”的,还要通过慢启动、滑动窗口、粘包算法等支持可靠性传输的一系列技术支持。虽然,这些可以保证TCP协议的可靠性,但有时这会影响咱们程序的性能。
那么,在高并发场景下,咱们该如何优化TCP链接呢?
(1)关闭粘包算法
若是用户对于请求的耗时很敏感,咱们就须要在TCP套接字上添加tcp_nodelay参数来关闭粘包算法,以便数据包可以马上发送出去。此时,咱们也能够设置net.ipv4.tcp_syncookies的参数值为1。
(2)避免频繁的建立和回收链接资源
网络链接的建立和回收是很是消耗性能的,咱们能够经过关闭空闲的链接、重复利用已经分配的链接资源来优化服务器的性能。重复利用已经分配的链接资源你们其实并不陌生,像:线程池、数据库链接池就是复用了线程和数据库链接。
咱们能够经过以下参数来关闭服务器的空闲链接和复用已分配的链接资源。
net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_keepalive_time=1800
(3)避免重复发送数据包
TCP支持超时重传机制。若是发送方将数据包已经发送给接收方,但发送方并未收到反馈,此时,若是达到设置的时间间隔,就会触发TCP的超时重传机制。为了不发送成功的数据包再次发送,咱们须要将服务器的net.ipv4.tcp_sack参数设置为1。
(4)增大服务器文件描述符数量
在Linux操做系统中,一个网络链接也会占用一个文件描述符,链接越多,占用的文件描述符也就越多。若是文件描述符设置的比较小,也会影响咱们服务器的性能。此时,咱们就须要增大服务器文件描述符的数量。
例如:fs.file-max = 10240000,表示服务器最多能够打开10240000个文件。
好了,本文结合群内读者的提问进行的一些总结,但愿可以给小伙伴们带来实质性的帮助。今天就到这儿吧,我是冰河,你们有啥问题能够在下方留言,也能够加我微信:sun_shine_lyz,一块儿交流技术,一块儿进阶,一块儿牛逼~~