第25章 系统级网络调优
学习目标
- 掌握Linux网络参数调优技术
- 了解网卡中断和队列优化
- 掌握零拷贝和io_uring技术
- 能够进行网络性能调优
前置知识
25.1 网络参数调优
25.1.1 TCP参数优化
1. 缓冲区大小
# 设置TCP缓冲区大小
echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.wmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_rmem = 4096 87380 134217728' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_wmem = 4096 65536 134217728' >> /etc/sysctl.conf
# 应用配置
sysctl -p
2. 连接参数
# 设置连接参数
echo 'net.ipv4.tcp_keepalive_time = 600' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_keepalive_intvl = 60' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_keepalive_probes = 3' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_max_syn_backlog = 8192' >> /etc/sysctl.conf
echo 'net.core.somaxconn = 65535' >> /etc/sysctl.conf
# 应用配置
sysctl -p
3. 拥塞控制
# 设置拥塞控制算法
echo 'net.ipv4.tcp_congestion_control = bbr' >> /etc/sysctl.conf
# 查看可用算法
cat /proc/sys/net/ipv4/tcp_available_congestion_control
# 查看当前算法
cat /proc/sys/net/ipv4/tcp_congestion_control
25.1.2 UDP参数优化
1. UDP缓冲区
# 设置UDP缓冲区
echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.wmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.ipv4.udp_rmem_min = 8192' >> /etc/sysctl.conf
echo 'net.ipv4.udp_wmem_min = 8192' >> /etc/sysctl.conf
# 应用配置
sysctl -p
2. UDP队列
# 设置UDP队列大小
echo 'net.core.netdev_max_backlog = 5000' >> /etc/sysctl.conf
echo 'net.core.netdev_budget = 600' >> /etc/sysctl.conf
# 应用配置
sysctl -p
25.1.3 网络接口参数
1. 接口队列
# 设置接口队列
echo 'net.core.netdev_max_backlog = 5000' >> /etc/sysctl.conf
echo 'net.core.netdev_budget = 600' >> /etc/sysctl.conf
echo 'net.core.netdev_budget_usecs = 5000' >> /etc/sysctl.conf
# 应用配置
sysctl -p
2. 接口缓冲区
# 设置接口缓冲区
echo 'net.core.rmem_default = 262144' >> /etc/sysctl.conf
echo 'net.core.wmem_default = 262144' >> /etc/sysctl.conf
echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.wmem_max = 134217728' >> /etc/sysctl.conf
# 应用配置
sysctl -p
25.2 网卡优化
25.2.1 网卡队列配置
1. 多队列配置
# 查看网卡队列数
ethtool -l eth0
# 设置网卡队列数
ethtool -L eth0 combined 8
# 查看队列配置
ethtool -l eth0
2. 队列权重
# 设置队列权重
echo 1 > /sys/class/net/eth0/queues/rx-0/rps_cpus
echo 2 > /sys/class/net/eth0/queues/rx-1/rps_cpus
echo 4 > /sys/class/net/eth0/queues/rx-2/rps_cpus
echo 8 > /sys/class/net/eth0/queues/rx-3/rps_cpus
25.2.2 网卡中断优化
1. 中断绑定
# 查看中断分布
cat /proc/interrupts | grep eth0
# 绑定中断到特定CPU
echo 2 > /proc/irq/24/smp_affinity
echo 4 > /proc/irq/25/smp_affinity
echo 8 > /proc/irq/26/smp_affinity
echo 16 > /proc/irq/27/smp_affinity
2. 中断合并
# 启用中断合并
ethtool -C eth0 rx-usecs 100
ethtool -C eth0 tx-usecs 100
ethtool -C eth0 rx-frames 32
ethtool -C eth0 tx-frames 32
# 查看中断合并配置
ethtool -c eth0
25.2.3 网卡特性优化
1. 硬件卸载
# 启用硬件卸载
ethtool -K eth0 gro on
ethtool -K eth0 gso on
ethtool -K eth0 tso on
ethtool -K eth0 ufo on
# 查看网卡特性
ethtool -k eth0
2. 网卡缓冲区
# 设置网卡缓冲区
ethtool -G eth0 rx 4096
ethtool -G eth0 tx 4096
# 查看网卡缓冲区
ethtool -g eth0
25.3 零拷贝技术
25.3.1 零拷贝原理
传统数据拷贝:
用户空间 ←→ 内核空间 ←→ 网卡
↓ ↓
应用缓冲区 内核缓冲区
零拷贝:
用户空间 ←→ 网卡
↓
应用缓冲区
25.3.2 零拷贝实现
1. sendfile系统调用
#include <sys/sendfile.h>
// 使用sendfile实现零拷贝
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
// 示例代码
int in_fd = open("input.txt", O_RDONLY);
int out_fd = socket(AF_INET, SOCK_STREAM, 0);
sendfile(out_fd, in_fd, NULL, file_size);
2. splice系统调用
#include <fcntl.h>
// 使用splice实现零拷贝
ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);
// 示例代码
int pipefd[2];
pipe(pipefd);
splice(in_fd, NULL, pipefd[1], NULL, len, SPLICE_F_MOVE);
splice(pipefd[0], NULL, out_fd, NULL, len, SPLICE_F_MOVE);
3. mmap系统调用
#include <sys/mman.h>
// 使用mmap实现零拷贝
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
// 示例代码
void *mapped = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, in_fd, 0);
send(out_fd, mapped, file_size, 0);
munmap(mapped, file_size);
25.3.3 零拷贝应用
1. Nginx零拷贝
# 启用sendfile
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 启用sendfile
location / {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
}
2. Apache零拷贝
# 启用sendfile
EnableSendfile On
# 启用mmap
EnableMMAP On
25.4 io_uring技术
25.4.1 io_uring概述
io_uring是Linux 5.1引入的异步I/O接口,提供高性能的异步I/O操作。
特点:
- 异步I/O操作
- 零拷贝支持
- 批量操作
- 高性能
25.4.2 io_uring实现
1. 基本使用
#include <liburing.h>
// 创建io_uring实例
struct io_uring ring;
io_uring_queue_init(32, &ring, 0);
// 准备异步操作
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fd, buffer, size, offset);
// 提交操作
io_uring_submit(&ring);
// 等待完成
struct io_uring_cqe *cqe;
io_uring_wait_cqe(&ring, &cqe);
io_uring_cqe_seen(&ring, cqe);
2. 网络I/O
// 异步网络I/O
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_send(sqe, sockfd, buffer, size, 0);
io_uring_submit(&ring);
3. 批量操作
// 批量提交多个操作
for (int i = 0; i < 10; i++) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fd, buffer[i], size, offset[i]);
}
io_uring_submit(&ring);
25.4.3 io_uring应用
1. 高性能Web服务器
// 使用io_uring实现高性能Web服务器
#include <liburing.h>
int main() {
struct io_uring ring;
io_uring_queue_init(1024, &ring, 0);
// 处理连接
while (1) {
struct io_uring_cqe *cqe;
io_uring_wait_cqe(&ring, &cqe);
// 处理完成的事件
handle_completion(cqe);
io_uring_cqe_seen(&ring, cqe);
}
}
2. 高性能文件传输
// 使用io_uring实现高性能文件传输
#include <liburing.h>
int transfer_file(int in_fd, int out_fd, size_t size) {
struct io_uring ring;
io_uring_queue_init(32, &ring, 0);
char buffer[4096];
size_t transferred = 0;
while (transferred < size) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, in_fd, buffer, sizeof(buffer), transferred);
io_uring_submit(&ring);
struct io_uring_cqe *cqe;
io_uring_wait_cqe(&ring, &cqe);
if (cqe->res > 0) {
transferred += cqe->res;
// 写入输出文件
write(out_fd, buffer, cqe->res);
}
io_uring_cqe_seen(&ring, cqe);
}
return transferred;
}
25.5 实验:网络性能调优
25.5.1 实验环境
环境要求:
- 两台Linux主机
- 网络互通
- 支持iperf3
网络拓扑:
┌─────────────────────────────────────────────────────────────┐
│ Performance Lab │
├─────────────────────────────────────────────────────────────┤
│ Client │
│ │ │
│ ┌──────┐ │
│ │ Server │ │
│ └───────┘ │
└─────────────────────────────────────────────────────────────┘
25.5.2 实验步骤
步骤1:基线测试
# 在服务器上启动iperf3
iperf3 -s
# 在客户端上测试
iperf3 -c server-ip -t 60 -i 10
步骤2:TCP参数优化
# 在服务器上优化TCP参数
echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.wmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_rmem = 4096 87380 134217728' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_wmem = 4096 65536 134217728' >> /etc/sysctl.conf
sysctl -p
# 重新测试
iperf3 -c server-ip -t 60 -i 10
步骤3:网卡优化
# 优化网卡队列
ethtool -L eth0 combined 8
# 优化网卡中断
echo 2 > /proc/irq/24/smp_affinity
echo 4 > /proc/irq/25/smp_affinity
# 重新测试
iperf3 -c server-ip -t 60 -i 10
步骤4:零拷贝测试
# 使用零拷贝传输文件
# 创建大文件
dd if=/dev/zero of=testfile bs=1M count=1000
# 使用scp传输
time scp testfile user@client-ip:/tmp/
# 使用rsync传输
time rsync -av testfile user@client-ip:/tmp/
25.6 性能监控
25.6.1 系统监控
1. 网络统计
# 查看网络统计
cat /proc/net/dev
# 查看TCP统计
cat /proc/net/tcp
# 查看UDP统计
cat /proc/net/udp
2. 中断统计
# 查看中断统计
cat /proc/interrupts
# 查看软中断统计
cat /proc/softirqs
3. 内存统计
# 查看内存统计
cat /proc/meminfo
# 查看网络内存使用
cat /proc/slabinfo | grep skb
25.6.2 性能分析
1. 使用perf分析
# 安装perf
apt-get install linux-tools-common linux-tools-generic
# 分析网络性能
perf record -e net:net_dev_xmit,net:net_dev_receive -a sleep 10
perf report
2. 使用bcc分析
# 安装bcc
apt-get install bpfcc-tools
# 分析网络延迟
tcpaccept -p $(pgrep nginx)
# 分析网络吞吐量
tcptop
25.7 故障排查
25.7.1 常见问题诊断
问题1:网络延迟高
# 检查网络延迟
ping -c 100 8.8.8.8
# 检查网络队列
tc -s qdisc show dev eth0
# 检查网络缓冲区
cat /proc/sys/net/core/rmem_max
cat /proc/sys/net/core/wmem_max
问题2:网络吞吐量低
# 检查网卡状态
ethtool eth0
# 检查网卡队列
ethtool -l eth0
# 检查中断分布
cat /proc/interrupts | grep eth0
问题3:CPU使用率高
# 检查CPU使用率
top
htop
# 检查软中断
cat /proc/softirqs
# 检查网络处理
perf top
25.7.2 排错工具
# 使用iftop监控网络
iftop -i eth0
# 使用nload监控网络
nload eth0
# 使用tcpdump抓包
tcpdump -i eth0 -n
# 使用netstat查看连接
netstat -tuln
25.8 排错清单
25.8.1 性能调优检查
- [ ] TCP参数是否优化
- [ ] 网卡队列是否配置
- [ ] 中断是否绑定
- [ ] 零拷贝是否启用
- [ ] 监控是否正常
25.8.2 性能问题检查
- [ ] 网络延迟是否正常
- [ ] 吞吐量是否满足要求
- [ ] CPU使用率是否正常
- [ ] 内存使用是否正常
- [ ] 错误率是否正常
25.9 延伸阅读
下一章:第26章 故障排查方法论
返回目录:README