UdpInOverflows非零是结果而非根因,需先检查rx_pause_cnt是否递增以确认交换机流控问题;若属实,则应禁用PAUSE帧、调大网卡Ring Buffer、关闭LRO/GRO,并合理设置net.core.rmem_max(≥24MB)及udp_mem三元组。
确认UdpInOverflows是否真在增长
netstat -su | grep "udpinoverflows" 输出非零,只是表象。它说明内核 udp 接收队列已满,新包被静默丢弃——但这个“满”可能是上游流控(rx_pause_cnt上涨)导致网卡暂停收包后,队列空转再被突发流量打满;也可能是应用读取太慢或缓冲区本身太小。别急着调大 net.core.rmem_max,先用 watch -n 1 'ethtool -s bond1 | grep rx_pause_cnt' 看 rx_pause_cnt 是否每秒递增。如果在涨,问题根源在交换机流控,不是 udp 缓冲区。
调大UDP接收缓冲区的正确姿势
Oracle RAC 的 GC 流量是短时高密度 UDP 包,net.core.rmem_max 必须足够大,否则 UdpInOverflows 会持续上升,直接关联 AWR 中的 gc cr block lost。生产环境建议值如下:
-
net.core.rmem_max = 25165824(24MB),不能低于 16MB -
net.ipv4.udp_mem = 1638400 2184533 3276800(三元组中第二个值即默认接收上限,需 ≥ rmem_max 的 80%) - 改完必须执行
sysctl -p,且确保 Oracle 进程是在该参数生效后启动的——否则新连接仍沿用旧缓冲区大小
SO_RCVBUF 应用层设置不能绕过系统限制
即使你在 Oracle 的监听器或数据库初始化参数里设了 RECV_BUF_SIZE,最终仍受 net.core.rmem_max 约束。Linux 内核不允许单个 socket 的 SO_RCVBUF 超过该上限。所以:
- 不要只改
sqlnet.ora里的DEFAULT_SDU_SIZE或RECV_BUF_SIZE - 检查当前生效值:
cat /proc/sys/net/core/rmem_max - 若发现 Oracle 进程启动后
cat /proc/<pid>/status | grep -i rmem</pid>显示的CapBnd或实际缓冲区远小于配置值,大概率是启动早于 sysctl 生效
别漏掉网卡 Ring Buffer 和 LRO/GRO
UDP 缓冲区调大只是软件栈一层。如果网卡驱动来不及把包从硬件 FIFO 搬到内核内存,rx_missed_errors 或 rx_no_buffer_count 就会涨,此时再大的 rmem_max 也无济于事:
- 用
ethtool -g bond1查当前 RX Ring Buffer 大小,万兆卡建议设为4096:ethtool -G bond1 rx 4096 -
ethtool -K bond1 lro off gro off必须执行——RAC 私网依赖精确包边界,LRO/GRO 合包会导致ksxp解析错乱、心跳延迟、甚至CRS-1611 - 这些命令需在所有节点统一执行,且加入启动脚本持久化


















