EMQX 性能调优:TCP SYN 队列与 Accept 队列

本文探讨了MQTT连接过程中SYN队列和Accept队列溢出的问题,分析了TCP三次握手的机制,介绍了SYNCookie和相关内核参数如何影响连接处理。作者建议监控相关计数并根据RTT调整队列大小以提升服务稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇博客(EMQX 性能调优:最大连接与文件描述符),我们深入研究了 MQTT 连接与文件描述符之间的关系,介绍了如何修改文件描述符相关的内核参数来突破默认的最大连接数量限制。

但你可能会发现,在某些情况下,即便当前服务端的 MQTT 连接总数并未达到文件描述符限制,客户端的连接请求仍然失败。当你运行以下命令,你将看到以下 Overflowed 和 SYN Dropped 计数在不断增加:

$ watch -d 'netstat -s | grep -i "listen"'
    2091 times the listen queue of a socket overflowed
    3418 SYNs to LISTEN sockets dropped

本文将介绍导致这一现象的原因以及如何通过内核参数调优来解决此问题。

SYN 队列与 Accept 队列

前文提到的这两个计数,通常意味着 SYN 队列和 Accept 队列发生了溢出,一旦溢出,客户端的正常连接就会受到影响。

所以首先,我们需要了解 SYN 队列和 Accept 队列分别是什么?

MQTT 作为构建在 TCP 之上的应用层协议,我们总是必须先建立 TCP 连接,然后才能发送 MQTT 协议的 CONNECT 报文。建立 TCP 连接,需要经过三次握手:

tcp 3 way handshake

  1. 客户端向服务器发送 SYN(同步)报文,表示要建立连接。
  2. 服务器用 SYN-ACK(同步确认)报文进行响应,表示愿意建立连接。
  3. 客户端回复 ACK(Acknowledge)报文,表示已收到 SYN-ACK 报文,连接已建立。

由于网络延迟的存在,从服务端发出 SYN-ACK 报文到收到客户端回复的 ACK 报文总是需要一段时间。在这段时间内,服务端需要暂存本次连接的关键信息,例如 TCP 四元组、MSS(Maximum Segment Size,最大分段大小)和窗口缩放因子(Window Scale)。所以,Linux 内核维护了一个 SYN 队列来存放这些连接信息。

当服务端收到客户端回复的 ACK 报文,连接建立完成,就会将连接从 SYN 队列取出,然后放入同样由内核维护的 Accept 队列,直到上层应用调用 accept() 将连接从 Accept 队列中取出。Accept 队列在这里的主要作用是解耦了网络层和应用层,使 TCP 三次握手和实际的数据传输可以并行进行,有效提高连接请求的处理效率。

syn queue and accept queue

但服务端的资源是有限的,不管是 SYN 队列还是 Accept 队列,它们都有着最大长度限制。如果客户端一直只发送 SYN 报文而不回复最后的 ACK 报文,或者服务端的应用程序没有及时地调用 accept(),那么这两个队列就会有溢出的风险。

SYN 队列溢出时将发生什么?

服务端在 SYN 队列溢出时的行为,主要由 net.ipv4.tcp_syncookies 选项决定。

由于 SYN 队列的长度总是有限的,所以一些攻击者会尝试采用发送大量 SYN 报文的方式来对服务端发起攻击,企图耗尽服务端的 SYN 队列来阻止合法连接的建立,这也就是我们常说的 SYN 泛洪攻击 (SYN Flood Attack)。

SYN Cookie 机制被设计用于解决这一问题。简单来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值