apache2服务无响应的排查和解决办法

2025-05-05 13:29:00
丁国栋
原创 19
摘要:本文记录如何排查apache2 web服务无响应或超时的问题。

一般思路:

首先我们先观测问题的现象,例如无响应,超时;

检查系统的基础负载情况,CPU、内存、磁盘、网络;

观察apache2的访问日志,是否有大量的输出;

观察apache2的进程数量,检查mpm模型参数;

观察apache2进程发起的TCP连接数量,检查是否存在异常;

重启apache2服务并立即访问apache2服务,观察是否可以访问;


netstat中的Recv-Q Send-Q是什么意思?为什么有的值比较大?

netstat 命令的输出中,Recv-QSend-Q 分别表示接收队列和发送队列的当前状态,它们的含义和数值大小反映了网络连接的数据缓冲情况。以下是详细解释:


1. Recv-Q(接收队列)

  • 定义:表示当前在接收缓冲区中未被应用程序读取的数据量(字节)。

  • 正常情况:通常应为 0 或较小的值。若数值持续较大,可能表示:

    • 应用程序读取数据的速度跟不上接收速度(如程序阻塞或性能不足)。

    • 网络连接对端发送数据过快,导致本地缓冲区积压。


2. Send-Q(发送队列)

  • 定义:表示当前在发送缓冲区中未被对端确认接收的数据量(字节)。

  • 正常情况:通常应为 0 或较小值。若数值较大,可能表示:

    • 对端接收速度慢(如对端应用程序处理能力不足)。

    • 网络拥塞导致数据包无法及时送达对端。

    • 对端已断开连接,但本地未检测到(如半开连接)。


为什么某个值比较大?

  • Recv-Q 大的常见原因:

    • 应用程序问题:进程未及时调用 read() 或阻塞(如死锁、高负载)。

    • CPU/磁盘瓶颈:系统资源不足导致无法处理数据。

    • 大量突发数据:短时间内数据涌入,超过处理能力。

  • Send-Q 大的常见原因:

    • 网络问题:丢包、延迟高或拥塞,导致ACK确认延迟。

    • 对端问题:对端应用程序未及时读取数据(如服务端响应慢)。

    • 连接异常:对端崩溃或防火墙阻断了连接。


如何排查?

  1. 检查应用程序状态:

    • 使用 topstrace 或日志分析应用程序是否卡住。
  2. 监控网络:

    • 通过 pingtraceroutetcpdump 检查网络延迟和丢包。
  3. 调整缓冲区:

    • 必要时通过 sysctl 调整内核参数(如 net.core.rmem_maxnet.core.wmem_max)。
  4. 连接状态:

    • 结合 netstat -tunp 查看连接状态(如 ESTABLISHEDCLOSE_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. 注意事项

  1. 与 TCP 相关参数联动:

    • net.ipv4.tcp_rmemnet.ipv4.tcp_wmem 是 TCP 层的动态调整范围,其最大值不能超过 net.core.rmem_max/wmem_max

    • 例如:

      net.ipv4.tcp_rmem = 4096 87380 4194304  # 最小值/默认值/最大值
      net.ipv4.tcp_wmem = 4096 16384 4194304
  2. 避免过度分配:

    • 过大的缓冲区会导致内存浪费和更高的延迟(尤其对短连接)。

    • 监控内存使用情况:free -mcat /proc/meminfo

  3. 监控效果:

    • 检查当前缓冲区使用:

      cat /proc/net/sockstat | grep mem
    • 观察网络吞吐量:nloadiftopsar -n DEV 1

  4. 特殊场景:

    • NAT 网关/负载均衡器:可能需要更大值(如 8~16MB)。

    • 容器/K8s 环境:需在宿主机和容器内协调配置。


5. 调优步骤

  1. 计算 BDP:通过 ping 测 RTT,结合带宽估算。
  2. 逐步增加:从 2MB 开始,根据吞吐量测试(如 iperf3)逐步上调。
  3. 验证稳定性:长期运行后检查内存和网络指标。
  4. 最终固化:将最优值写入 /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. 关键点解读

  1. TCP 内存使用(mem 191

    • 表示 TCP 协议栈当前使用了约 764KB 内存(191 × 4KB)。

    • 包括:socket 缓冲区、控制块、重传队列等。

    • 过高可能的问题:

      ◦ 大量并发连接(检查 inusealloc)。

      ◦ 内存泄漏(如 orphan 持续增长)。

  2. UDP 内存使用(mem 256

    • UDP 无连接状态,内存主要用于 socket 缓冲区和报文缓存。

    • mem 突然增加,可能是:

      ◦ 大量 UDP 流量(如 DNS、视频流)。

      ◦ 应用未及时读取数据(Recv-Q 积压)。

  3. TIME_WAIT 状态(tw 78

    • 表示 78 个连接正在等待关闭(正常现象,但过多可能耗尽端口)。

    • 优化建议:

      sysctl -w net.ipv4.tcp_tw_reuse=1    # 允许复用 TIME_WAIT 连接
      sysctl -w net.ipv4.tcp_max_tw_buckets=16384  # 增大限制
  4. 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-QSend-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-QSend-Q 均为 0,2 个连接的 Recv-Q 为 1024。

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"
  • 关键指标:

    • TcpExtListenOverflowsaccept() 队列溢出次数(Recv-Q 超过 backlog)。

    • TcpExtTCPBacklogDrop:因队列满而丢弃的连接数。

  • 示例:

    TcpExtListenOverflows    10
    TcpExtTCPBacklogDrop     5
    • 表示有 10 次 accept() 队列溢出,5 次连接因队列满被丢弃。

4. 使用 dstat 实时监控网络缓冲

dstat -t --tcp
  • 输出示例:

    ---tcp-sck--- ---tcp-hdr---
    ESTAB  LISTEN  SYN    TIME
    100    5      0      0
    • ESTAB:已建立连接数(可能积压数据)。

    • LISTEN:监听队列情况。


5. 使用 tcpdump 抓包分析 如果 Recv-QSend-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-QSend-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 最大探测次数,若全部失败则判定连接死亡。

完整流程示例(默认值):

  1. 连接空闲 7200 秒(2小时)后,发送首个探测包。
  2. 若未收到响应,每隔 75 秒 重试一次,最多重试 9 次。
  3. 若全部探测失败(总耗时 ≈ 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. 注意事项

  1. 连接必须为 ESTABLISHED 状态: Keepalive 仅对已建立的连接有效,LISTENSYN_SENT 状态无效。
  2. 对端需支持 TCP Keepalive: 若对端忽略探测包,连接仍会被判定为死亡。
  3. 性能影响: 过短的 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 秒)。

  • 需结合 intvlprobes 参数 综合调整检测策略。

发表评论
博客分类