服务器执行 ss 时看到大量 SYN_RECV,说明服务端已经收到客户端SYN并发出SYN-ACK,但三次握手还没有完成。短时间出现一些属于正常现象;数量持续攀升、集中在单个端口并伴随连接超时,才需要进一步判断是正常流量突发、网络回程问题,还是SYN Flood一类异常流量。
我不会一上来就调大 tcp_max_syn_backlog 或关闭防火墙。半连接队列只是症状出现的位置,应用监听队列、CPU软中断、网卡丢包、负载均衡、回程线路和来源真实性都会影响结果。先记录现场,再决定该扩容量、修网络还是启用防护。

先统计数量、端口和持续时间
先确认SYN_RECV总数以及集中在哪些监听端口:
date
ss -Hant state syn-recv | wc -l
ss -Hant state syn-recv | awk '{print $4}' | sort | uniq -c | sort -nr | head
ss -lntp
ss 输出列在不同版本上可能略有差异,先查看几行原始结果再写统计命令。每秒采样一次会产生额外开销,高连接量服务器应降低频率,优先使用已有内核和负载均衡监控。
记录至少几分钟趋势。峰值很快回落且业务无异常,可能只是发布、爬虫或客户端同时重连;持续只增不减并伴随握手失败,才支持队列或攻击方向。
同一时刻还要记录ESTABLISHED、TIME_WAIT和服务请求量。只有SYN_RECV升高而成功连接没有增加,握手失败方向更可信;各状态与请求量同步增长,则更像整体流量峰值。
按来源地址判断流量形态
查看远端地址分布:
ss -Hant state syn-recv | awk '{print $5}' | sed 's/:[^:]*$//' | sort | uniq -c | sort -nr | head -30
IPv6地址和不同 ss 版本需要调整解析方式,不能把示例直接当成审计结果。单一来源占比极高,可能是异常客户端、NAT出口或健康检查;来源高度分散且每个地址很少,则可能是伪造源地址的SYN Flood,也可能是真实热点流量。
不能仅凭IP数量判定攻击。移动网络、企业代理和CDN会让大量真实用户共享出口;反向代理架构下,源站看到的可能只有负载均衡地址。应同时查看边缘层连接率、访问日志、业务活动和地区分布。
理解半连接队列与全连接队列
SYN_RECV属于握手尚未完成的请求,主要受每个监听套接字的半连接队列影响。握手完成后,连接进入等待应用 accept() 的队列,后者与应用传入的backlog以及 net.core.somaxconn 有关。
sysctl net.ipv4.tcp_max_syn_backlog
sysctl net.core.somaxconn
ss -lnt
内核文档说明 tcp_max_syn_backlog 是每个listener记住SYN_RECV请求的上限,并提醒同时检查somaxconn。调大一个值并不能自动提高应用处理能力,监听程序传入的backlog、worker数量与accept速度仍会限制全连接队列。
把半连接和全连接混为一谈,会出现参数改了但错误不变的情况。先确认是握手未完成,还是已经完成却来不及被应用接收。
查看内核是否发生队列溢出
内核计数器能提供比当前快照更直接的证据:
nstat -az | grep -E 'ListenOverflows|ListenDrops|SyncookiesSent|SyncookiesRecv|SyncookiesFailed'
netstat -s | grep -iE 'listen|SYN|cookie'
dmesg -T | grep -i 'SYN flooding'
计数器是开机以来的累计值,应记录两次差分,不能看到非零就认定当前正在溢出。ListenOverflows 与 ListenDrops 增长提示监听队列压力;SyncookiesSent 增长说明内核在队列溢出时使用SYN cookies回退。
系统日志出现possible SYN flooding也不一定等于恶意攻击。合法流量突然上升、应用接收慢或参数过小同样可能触发,必须与业务流量和来源形态一起判断。
排除CPU软中断和网卡丢包
握手包到达速度超过CPU网络处理能力时,SYN-ACK发送或ACK处理会延迟。检查CPU、软中断和接口统计:
mpstat -P ALL 1 10
cat /proc/softirqs
ip -s link
ethtool -S eth0 2>/dev/null | grep -iE 'drop|miss|error'
接口名要替换成真实值。多队列网卡上,软中断集中在单个CPU可能与RSS、IRQ亲和性或虚拟化网络设置有关;所有CPU都被业务进程占满,则应先解决整体容量。
虚拟机还要结合云平台网卡包速率和连接跟踪上限。操作系统内部没有明显丢包,不代表上游安全组、负载均衡或宿主网络没有限速。
检查SYN-ACK有没有正常返回
来源真实但握手长期停在SYN_RECV,可能是服务端SYN-ACK没有到达客户端,或客户端ACK回程被丢弃。短时间抓取目标端口的报文头:
sudo tcpdump -ni any 'tcp port 443 and (tcp[tcpflags] & (tcp-syn|tcp-ack) != 0)' -c 200
抓包可能包含IP和端口等敏感信息,应限制时长、数量和访问权限。看到SYN到达、SYN-ACK反复重传却没有ACK,说明三次握手没有完成;原因仍可能在客户端、回程线路、防火墙或源地址伪造。
有负载均衡或CDN时,要在正确层级抓包。源站只看到代理连接,就应先检查边缘到源站链路,不要用源站结果推断终端用户的完整路径。
正确理解tcp_syncookies
Linux的 tcp_syncookies 在SYN队列溢出时提供回退保护。内核文档明确提醒,SYN cookies不应拿来帮助高负载服务器承受正常合法连接率,它不是扩容应用或队列的替代品。
sysctl net.ipv4.tcp_syncookies
sysctl net.ipv4.tcp_synack_retries
当前很多系统默认启用syncookies。不要看到SYN_RECV多就反复切换开关,也不要把重传次数随意降得很低;网络质量较差的真实用户可能因此更容易连接失败。
参数调整应先在同内核版本的测试环境验证,并记录修改前后的队列溢出、成功握手率与业务延迟。只让SYN_RECV数量下降,不代表用户体验改善。
区分正常峰值与SYN Flood
正常热点通常能在访问日志、负载均衡请求数和业务活动中找到对应,握手完成率也相对稳定。SYN Flood常表现为SYN速率异常、来源分散或伪造、完成握手比例低、syncookie计数增加,并可能挤压真实连接。
应优先在云防火墙、负载均衡、CDN或专业清洗层处理大规模异常流量。主机本地规则只能在流量已经到达网卡后生效,带宽先被占满时,单纯iptables丢包无法恢复入口容量。
需要复现合法连接突发时,可以在 萤光云 建立隔离服务端,或在按小时计费的 LightNode 上做受控并发测试。不要从公网发起类似攻击的流量,也不要对生产地址做无上限压测。
调整参数前先评估应用能力
确认是合法连接峰值且监听队列确实溢出后,才考虑提高 tcp_max_syn_backlog、somaxconn 与应用backlog。调整值要结合内存、每秒新建连接率、应用accept速度和平台限制。
Web服务还要检查worker数量、文件描述符、TLS握手CPU和上游响应。应用处理慢导致连接生命周期变长时,只扩大队列会把失败推迟,却不会提高最终吞吐。
持久化sysctl配置前先用临时值灰度验证,确认没有命名空间或容器级覆盖。容器内看到的参数是否可修改取决于运行方式,不能默认修改容器就等于修改宿主机。
修复后怎样验收
在真实高峰或受控测试中,同时观察SYN_RECV趋势、ListenDrops、SyncookiesSent、成功握手率、请求延迟和错误率:
watch -n 2 "ss -Hant state syn-recv | wc -l"
nstat -az | grep -E 'ListenOverflows|ListenDrops|Syncookies'
至少跨过一次流量峰值,并确认防护规则没有误伤正常地区、监控探针或合作方。合格的修复应能解释流量来源、队列在哪一层受限,以及调整后真实连接成功率是否恢复。
常见问题
SYN_RECV很多就一定是攻击吗?
不一定。合法流量突发、回程丢包、应用接收慢和队列过小都可能产生相似现象,要结合来源、计数器与业务指标判断。
把tcp_max_syn_backlog调得越大越好吗?
不是。它会占用更多内存,也无法修复应用吞吐或带宽问题。数值应与合法连接率和整条处理链匹配。
开启tcp_syncookies后还要处理吗?
要。syncookies是队列溢出时的回退保护,不是正常容量方案。计数持续增长仍需定位合法过载或异常流量。


