apache2服务无响应的排查和解决办法
- 2025-05-05 13:29:00
- 丁国栋
- 原创 19
一般思路:
首先我们先观测问题的现象,例如无响应,超时;
检查系统的基础负载情况,CPU、内存、磁盘、网络;
观察apache2的访问日志,是否有大量的输出;
观察apache2的进程数量,检查mpm模型参数;
观察apache2进程发起的TCP连接数量,检查是否存在异常;
重启apache2服务并立即访问apache2服务,观察是否可以访问;
netstat中的Recv-Q Send-Q是什么意思?为什么有的值比较大?
在 netstat
命令的输出中,Recv-Q
和 Send-Q
分别表示接收队列和发送队列的当前状态,它们的含义和数值大小反映了网络连接的数据缓冲情况。以下是详细解释:
1. Recv-Q
(接收队列)
-
定义:表示当前在接收缓冲区中未被应用程序读取的数据量(字节)。
-
正常情况:通常应为
0
或较小的值。若数值持续较大,可能表示:-
应用程序读取数据的速度跟不上接收速度(如程序阻塞或性能不足)。
-
网络连接对端发送数据过快,导致本地缓冲区积压。
-
2. Send-Q
(发送队列)
-
定义:表示当前在发送缓冲区中未被对端确认接收的数据量(字节)。
-
正常情况:通常应为
0
或较小值。若数值较大,可能表示:-
对端接收速度慢(如对端应用程序处理能力不足)。
-
网络拥塞导致数据包无法及时送达对端。
-
对端已断开连接,但本地未检测到(如半开连接)。
-
为什么某个值比较大?
-
Recv-Q
大的常见原因:-
应用程序问题:进程未及时调用
read()
或阻塞(如死锁、高负载)。 -
CPU/磁盘瓶颈:系统资源不足导致无法处理数据。
-
大量突发数据:短时间内数据涌入,超过处理能力。
-
-
Send-Q
大的常见原因:-
网络问题:丢包、延迟高或拥塞,导致ACK确认延迟。
-
对端问题:对端应用程序未及时读取数据(如服务端响应慢)。
-
连接异常:对端崩溃或防火墙阻断了连接。
-
如何排查?
-
检查应用程序状态:
- 使用
top
、strace
或日志分析应用程序是否卡住。
- 使用
-
监控网络:
- 通过
ping
、traceroute
或tcpdump
检查网络延迟和丢包。
- 通过
-
调整缓冲区:
- 必要时通过
sysctl
调整内核参数(如net.core.rmem_max
、net.core.wmem_max
)。
- 必要时通过
-
连接状态:
- 结合
netstat -tunp
查看连接状态(如ESTABLISHED
、CLOSE_WAIT
),判断是否对端未正常关闭。
- 结合
示例输出分析
$ netstat -tulnp
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 1024 0 192.168.1.1:80 192.168.1.2:1234 ESTABLISHED
-
第一行(LISTEN状态):
Recv-Q
/Send-Q
通常为0
。 -
第二行(ESTABLISHED状态):
-
Recv-Q=1024
:有1KB数据未被应用程序读取。 -
Send-Q=0
:所有数据已被对端确认。
-
总结
-
Recv-Q
大:本地应用处理慢。 -
Send-Q
大:网络或对端问题。
持续的高值可能需深入排查性能或网络故障。
调整 net.core.rmem_max
(接收缓冲区最大值)和 net.core.wmem_max
(发送缓冲区最大值)是优化 TCP 性能的关键,但需根据实际场景谨慎配置。以下是调整的依据、范围及具体建议:
1. 默认值与作用
-
默认值(通常为):
net.core.rmem_max = 212992 # ~208 KB net.core.wmem_max = 212992 # ~208 KB
-
作用:
-
rmem_max
:限制每个 socket 接收缓冲区的最大大小,影响 TCP 窗口大小和吞吐量。 -
wmem_max
:限制每个 socket 发送缓冲区的最大大小,影响数据发送的积压能力。
-
2. 调整依据 (1)网络环境
-
高带宽延迟积(BDP)网络(如云服务器、跨地域通信):
需增大缓冲区以容纳更多数据(避免窗口太小限制吞吐量)。 计算公式:
BDP (Bytes) = 带宽 (bps) × 往返延迟 (RTT, 秒) / 8
例如:1Gbps 带宽、RTT=50ms → BDP = 1e9 × 0.05 / 8 ≈ 6.25MB。
-
低延迟局域网:默认值或小幅增加即可。
(2)应用场景
-
大文件传输/视频流:需更大的缓冲区(如 4MB+)。
-
高并发短连接(如 Web 服务):适中值(1~2MB),避免内存浪费。
-
数据库/实时通信:平衡低延迟与吞吐量(2~4MB)。
(3)系统资源
-
内存充足:可适当调高(如 4~16MB)。
-
内存受限:避免过度分配(如 1~2MB)。
3. 推荐调整范围
场景 | rmem_max / wmem_max 推荐值 |
---|---|
普通服务器(默认) | 256KB ~ 2MB |
高带宽高延迟(BDP 大) | 4MB ~ 16MB |
低延迟局域网 | 512KB ~ 2MB |
内存受限设备 | 256KB ~ 1MB |
示例命令(临时生效):
sysctl -w net.core.rmem_max=4194304 # 4MB
sysctl -w net.core.wmem_max=4194304 # 4MB
永久生效:
编辑 /etc/sysctl.conf
,添加:
net.core.rmem_max = 4194304
net.core.wmem_max = 4194304
执行 sysctl -p
生效。
4. 注意事项
-
与 TCP 相关参数联动:
-
net.ipv4.tcp_rmem
和net.ipv4.tcp_wmem
是 TCP 层的动态调整范围,其最大值不能超过net.core.rmem_max/wmem_max
。 -
例如:
net.ipv4.tcp_rmem = 4096 87380 4194304 # 最小值/默认值/最大值 net.ipv4.tcp_wmem = 4096 16384 4194304
-
-
避免过度分配:
-
过大的缓冲区会导致内存浪费和更高的延迟(尤其对短连接)。
-
监控内存使用情况:
free -m
或cat /proc/meminfo
。
-
-
监控效果:
-
检查当前缓冲区使用:
cat /proc/net/sockstat | grep mem
-
观察网络吞吐量:
nload
、iftop
或sar -n DEV 1
。
-
-
特殊场景:
-
NAT 网关/负载均衡器:可能需要更大值(如 8~16MB)。
-
容器/K8s 环境:需在宿主机和容器内协调配置。
-
5. 调优步骤
- 计算 BDP:通过
ping
测 RTT,结合带宽估算。 - 逐步增加:从 2MB 开始,根据吞吐量测试(如
iperf3
)逐步上调。 - 验证稳定性:长期运行后检查内存和网络指标。
- 最终固化:将最优值写入
/etc/sysctl.conf
。
总结
-
核心原则:缓冲区大小应匹配网络 BDP 和应用需求。
-
安全范围:多数场景下 2~8MB 足够,极端场景(如跨洲传输)可到 16MB。
-
动态调整:结合
tcp_rmem
/tcp_wmem
实现内核自动优化。
通过合理配置,可显著提升大流量或高延迟环境下的 TCP 性能,但需避免盲目增大导致资源浪费。
如何理解这个命令的输出?
# cat /proc/net/sockstat | grep mem
TCP: inuse 6 orphan 6 tw 78 alloc 150 mem 191
UDP: inuse 4 mem 256
FRAG: inuse 0 memory 0
这个命令 cat /proc/net/sockstat | grep mem
输出了当前系统中 TCP、UDP 和 IP 分片(FRAG) 相关的内存使用统计信息。以下是逐项解析:
1. 输出示例
TCP: inuse 6 orphan 6 tw 78 alloc 150 mem 191
UDP: inuse 4 mem 256
FRAG: inuse 0 memory 0
2. 字段解析 (1)TCP 部分
字段 | 含义 |
---|---|
inuse |
正在使用的 TCP socket 数量(ESTABLISHED 或 CLOSE_WAIT 状态)。 |
orphan |
未被任何用户进程引用的 TCP socket(如程序崩溃后残留的连接)。 |
tw |
处于 TIME_WAIT 状态的 socket 数量(等待 2MSL 超时后关闭)。 |
alloc |
内核已分配的 TCP socket 总数(包括未使用的缓存)。 |
mem |
TCP 协议栈使用的内存页数(1 页通常为 4KB,191 ≈ 764KB)。 |
(2)UDP 部分
字段 | 含义 |
---|---|
inuse |
正在使用的 UDP socket 数量。 |
mem |
UDP 协议栈使用的内存页数(256 ≈ 1MB)。 |
(3)FRAG(IP 分片)部分
字段 | 含义 |
---|---|
inuse |
正在使用的 IP 分片队列数量(通常为 0,除非有大量分片包)。 |
memory |
IP 分片缓存使用的内存页数(0 表示无分片包缓存)。 |
3. 关键点解读
-
TCP 内存使用(
mem 191
)-
表示 TCP 协议栈当前使用了约 764KB 内存(191 × 4KB)。
-
包括:socket 缓冲区、控制块、重传队列等。
-
过高可能的问题:
◦ 大量并发连接(检查
inuse
和alloc
)。◦ 内存泄漏(如
orphan
持续增长)。
-
-
UDP 内存使用(
mem 256
)-
UDP 无连接状态,内存主要用于 socket 缓冲区和报文缓存。
-
若
mem
突然增加,可能是:◦ 大量 UDP 流量(如 DNS、视频流)。
◦ 应用未及时读取数据(
Recv-Q
积压)。
-
-
TIME_WAIT 状态(
tw 78
)-
表示 78 个连接正在等待关闭(正常现象,但过多可能耗尽端口)。
-
优化建议:
sysctl -w net.ipv4.tcp_tw_reuse=1 # 允许复用 TIME_WAIT 连接 sysctl -w net.ipv4.tcp_max_tw_buckets=16384 # 增大限制
-
-
IP 分片(
FRAG
)-
正常情况下应为
0
。若memory
非零,可能遭遇 IP 分片攻击 或 MTU 配置不当。 -
检查 MTU:
ip link show eth0 | grep mtu
-
4. 监控与调优建议 (1)查看详细内存分配
cat /proc/net/sockstat # 完整统计(包括 RAW、FRAG 等)
cat /proc/slabinfo | grep sock # 内核 slab 分配器中的 socket 内存
(2)动态调整缓冲区
-
增大 TCP 内存限制(需同时调整
rmem_max/wmem_max
):sysctl -w net.ipv4.tcp_mem="379008 505344 758016" # 最小/压力/最大(页数)
(3)排查异常
-
孤儿 socket 过多:
ss -s | grep orphan # 查看具体连接
-
TIME_WAIT 堆积:
ss -tan | grep TIME-WAIT | wc -l
5. 总结
-
mem
字段:反映协议栈内存开销,单位为 内核页数(通常 4KB)。 -
正常情况:
-
TCP/UDP 内存随连接数增加,但不应无限制增长。
-
FRAG
应为 0。
-
-
异常信号:
-
orphan
持续增加 → 应用未正确关闭连接。 -
tw
过高 → 短连接频繁,需优化复用。 -
FRAG.memory
非零 → 检查 MTU 或网络攻击。
-
通过定期监控这些指标,可以及时发现网络栈的内存瓶颈或配置问题。
如何监控系统的TCP队列?
监控系统的 TCP 队列(Recv-Q
和 Send-Q
)可以帮助发现网络性能瓶颈或应用程序处理延迟问题。以下是几种常用的监控方法:
1. 使用 netstat
查看 TCP 队列
netstat -tulnp
-
关键列:
-
Recv-Q
:接收队列积压数据(未被应用读取)。 -
Send-Q
:发送队列积压数据(未被对端确认)。
-
-
示例:
Proto Recv-Q Send-Q Local Address Foreign Address State tcp 1024 0 192.168.1.1:80 192.168.1.2:1234 ESTABLISHED
-
Recv-Q=1024
:有 1KB 数据未被应用读取。 -
Send-Q=0
:所有数据已被对端确认。
-
改进版(统计所有连接的队列情况):
netstat -tn | awk '/^tcp/ {print $2, $3}' | sort | uniq -c
-
输出示例:
10 0 0 2 1024 0
- 表示有 10 个连接的
Recv-Q
和Send-Q
均为 0,2 个连接的Recv-Q
为 1024。
- 表示有 10 个连接的
2. 使用 ss
(更高效,推荐) ss
(Socket Statistics)是 netstat
的现代替代工具,性能更好,支持更多细节:
ss -tulnp
-
关键列:
-
Recv-Q
:接收队列(LISTEN 状态时表示等待accept()
的连接数)。 -
Send-Q
:发送队列(LISTEN 状态时表示最大 backlog 队列长度)。
-
-
示例:
State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 0 192.168.1.1:80 192.168.1.2:1234 LISTEN 10 128 *:80 *:*
-
LISTEN
状态的Recv-Q=10
:有 10 个连接在等待accept()
(可能backlog
不足)。 -
ESTAB
状态的Recv-Q=0
:无积压数据。
-
统计所有 TCP 连接的队列情况:
ss -tn | awk '{print $2, $3}' | sort | uniq -c
3. 使用 nstat
监控内核 TCP 统计 nstat
可以查看内核 TCP 协议栈的统计信息,包括队列溢出情况:
nstat -z -a | grep -E "TcpExtListenOverflows|TcpExtTCPBacklogDrop"
-
关键指标:
-
TcpExtListenOverflows
:accept()
队列溢出次数(Recv-Q
超过backlog
)。 -
TcpExtTCPBacklogDrop
:因队列满而丢弃的连接数。
-
-
示例:
TcpExtListenOverflows 10 TcpExtTCPBacklogDrop 5
- 表示有 10 次
accept()
队列溢出,5 次连接因队列满被丢弃。
- 表示有 10 次
4. 使用 dstat
实时监控网络缓冲
dstat -t --tcp
-
输出示例:
---tcp-sck--- ---tcp-hdr--- ESTAB LISTEN SYN TIME 100 5 0 0
-
ESTAB
:已建立连接数(可能积压数据)。 -
LISTEN
:监听队列情况。
-
5. 使用 tcpdump
抓包分析 如果 Recv-Q
或 Send-Q
持续较高,可能是网络丢包或对端问题,可以用 tcpdump
抓包:
tcpdump -i eth0 -nn "tcp port 80" -w tcp_debug.pcap
然后用 Wireshark 分析:
-
是否有大量重传(
Retransmission
)? -
是否有零窗口(
Zero Window
,表示对端接收缓冲区满)?
6. 调整内核参数优化队列 如果监控发现队列溢出或积压,可以调整内核参数:
# 增大 SYN 队列(半连接队列)
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
# 增大 accept() 队列(全连接队列)
sysctl -w net.core.somaxconn=4096
# 增大 TCP 接收/发送缓冲区
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
-
somaxconn
:影响listen()
的backlog
上限(需应用程序也设置较大的backlog
)。 -
tcp_max_syn_backlog
:SYN 半连接队列大小(防 SYN Flood)。 -
rmem_max
/wmem_max
:调整 TCP 缓冲区大小。
总结
方法 | 用途 | 适用场景 |
---|---|---|
netstat -tulnp |
查看当前连接的队列状态 | 快速检查 |
ss -tulnp |
更高效的队列监控 | 推荐替代 netstat |
nstat |
监控内核 TCP 队列溢出 | 排查 backlog 问题 |
dstat --tcp |
实时监控 TCP 连接数 | 全局趋势分析 |
tcpdump |
抓包分析网络问题 | 深入排查丢包/延迟 |
sysctl |
调整内核队列参数 | 优化性能 |
如果发现 Recv-Q
或 Send-Q
持续较高,建议结合应用程序日志、系统负载(top
/htop
)和网络状况(ping
/mtr
)综合排查。
netstat 行示例
tcp6 0 0 10.7.0.4:443 182.200.138.121:17777 ESTABLISHED 2797828/apache2 keepalive (3034.70/0/0)
字段解析
-
tcp6
- 表示这是一个 IPv6 协议 的 TCP 连接(即使地址是 IPv4,也可能通过 IPv6 协议栈处理)。
-
0
(Recv-Q)- 接收队列积压数据量(字节),
0
表示没有未被应用程序(Apache)读取的数据。
- 接收队列积压数据量(字节),
-
0
(Send-Q)- 发送队列积压数据量(字节),
0
表示所有数据已被对端确认。
- 发送队列积压数据量(字节),
-
keepalive (3034.70/0/0)
-
TCP Keepalive 信息(部分系统显示):
◦
3034.70
:Keepalive 定时器的剩余时间(秒),默认是 net.ipv4.tcp_keepalive_time 内核参数控制的。◦ 第一个
0
:Keepalive 探测已发送次数(当前未发送)。◦ 第二个
0
:Keepalive 探测未响应次数(当前无失败)。 -
表示此连接启用了 TCP Keepalive 机制,用于检测连接是否存活。
-
内核参数 net.ipv4.tcp_keepalive_time
是 Linux 系统中用于控制 TCP 长连接(Keepalive)行为的关键参数之一,其作用如下:
1. 定义与作用
-
功能:
指定 TCP 连接在空闲(无数据交互)状态下,内核发送首个 Keepalive 探测包前的等待时间(单位:秒)。 例如,默认值
7200
表示如果连接空闲超过 2 小时,内核会开始发送探测包以检测连接是否存活。 -
Keepalive 机制的目的:
-
检测对端是否崩溃或网络是否中断(避免维持“半死不活”的连接)。
-
防止 NAT/防火墙因超时断开空闲连接(如移动网络、云环境)。
-
2. 相关参数 Keepalive 行为由以下三个参数共同控制(均以秒为单位):
参数名 | 默认值 | 作用 |
---|---|---|
net.ipv4.tcp_keepalive_time |
7200 | 首次探测前的空闲时间(2小时)。 |
net.ipv4.tcp_keepalive_intvl |
75 | 两次探测的间隔时间(75秒)。 |
net.ipv4.tcp_keepalive_probes |
9 | 最大探测次数,若全部失败则判定连接死亡。 |
完整流程示例(默认值):
- 连接空闲 7200 秒(2小时)后,发送首个探测包。
- 若未收到响应,每隔 75 秒 重试一次,最多重试 9 次。
- 若全部探测失败(总耗时 ≈
7200 + 75×9 = 7875 秒
),内核强制关闭连接。
3. 如何查看当前值?
sysctl net.ipv4.tcp_keepalive_time # 查看当前配置
cat /proc/sys/net/ipv4/tcp_keepalive_time # 直接读取内核参数
4. 何时需要调整? (1)调小 tcp_keepalive_time
(更激进)
-
场景:
-
网络环境不稳定(如移动设备、跨公网通信)。
-
NAT/防火墙会话超时较短(例如 AWS NLB 默认 350 秒)。
-
需要快速释放僵死连接(如高并发服务端)。
-
-
示例(改为 5 分钟):
sysctl -w net.ipv4.tcp_keepalive_time=300
(2)调大或禁用(更宽松)
-
场景:
-
内网低延迟环境,无需频繁检测。
-
长连接业务(如数据库、消息队列)需避免误判。
-
-
注意:完全禁用需设置
tcp_keepalive_probes=0
(不推荐)。
5. 应用层 vs 内核层 Keepalive
-
内核层(本参数):
由操作系统全局控制,对所有 TCP 连接生效(除非应用显式关闭)。
-
应用层(如 HTTP Keep-Alive、gRPC):
由应用程序实现,仅作用于特定协议(优先级高于内核参数)。
验证某连接是否启用了内核 Keepalive:
ss -o state established -tnp | grep keepalive
# 输出示例:keepalive (xx.xx/0/0)
6. 注意事项
- 连接必须为
ESTABLISHED
状态: Keepalive 仅对已建立的连接有效,LISTEN
或SYN_SENT
状态无效。 - 对端需支持 TCP Keepalive: 若对端忽略探测包,连接仍会被判定为死亡。
- 性能影响:
过短的
tcp_keepalive_time
会增加网络开销(尤其在大量长连接场景)。
7. 完整配置示例
# 调整为 10 分钟空闲后探测,间隔 30 秒,最多 3 次
sysctl -w net.ipv4.tcp_keepalive_time=600
sysctl -w net.ipv4.tcp_keepalive_intvl=30
sysctl -w net.ipv4.tcp_keepalive_probes=3
# 永久生效
echo "net.ipv4.tcp_keepalive_time=600" >> /etc/sysctl.conf
sysctl -p
总结
-
tcp_keepalive_time
是控制 TCP 空闲连接检测的“第一道闸门”。 -
合理值取决于业务和网络环境:
-
公网/NAT 环境建议 300~1200 秒。
-
内网稳定环境可保持默认(7200 秒)。
-
-
需结合
intvl
和probes
参数 综合调整检测策略。