文档首页/ 弹性云服务器 ECS/ 常见问题/ 网络配置/ 云服务器网络优化方案
更新时间:2025-12-10 GMT+08:00
分享

云服务器网络优化方案

操作场景

为了提高程序的运行的性能,可以通过把云服务器上运行的某个进程,指定在某个CPU上工作,实现CPU性能调优。

为了获取更高的执行效率,应该保证一个CPU把一个完整的发送或者接收过程处理完,避免CPU切换。最好一个业务进程/线程固定在一个CPU、固定一个网卡发送队列,中断也使用这个CPU。对于跨NUMA的云服务器,应该尽量在一个NUMA上完成网络IO动作,避免NUMA间切换。(可以执行lscpu查看CPU相关信息判断是否跨NUMA。)

本节操作以C7.xlarge.2、CentOS 7.4操作系统的云服务器为例,介绍网络优化的方案。

其中C7.xlarge.2实例的网卡有0、1两个队列,有CPU0、CPU1、CPU2、CPU3四颗CPU。

场景一:单位CPU获取的带宽(Gbps)或者吞吐量(Mpps)最大

  1. 保证一个业务进程或线程固定在一个CPU。

    可以通过如下命令把某个进程绑定在特定CPU:

    taskset -pc cpu_id pid

    • cpu_id为希望绑定的CPU,取值范围为[0, CPU最大数-1]。
    • pid为希望绑核的业务进程。

    例如,本例中使用iperf3作为业务进程,把两个进程分别绑定到CPU2和CPU3:

    1. 执行如下命令,获取iperf3进程状态。

      ps aux | grep iperf3 | grep -v grep

       [root@localhost ~]# ps aux | grep iperf3 | grep -v grep
        root      3161  9.7  0.0   9712   896 pts/0    R    08:22   0:01 iperf3 -c 192.168.1.61 -p 10000 -t 10000 -i 0
        root      3163  9.0  0.0   9712   892 pts/0    S    08:22   0:01 iperf3 -c 192.168.1.61 -p 10001 -t 10000 -i 0
    2. 执行以下命令,指定进程运行在CPU2和CPU3上。

      taskset -pc 2 3161

      taskset -pc 3 3163
        [root@localhost ~]# taskset -pc 2 3161
        pid 3161's current affinity list: 0-3
        pid 3161's new affinity list: 2
        [root@localhost ~]# taskset -pc 3 3163
        pid 3163's current affinity list: 0-3
        pid 3163's new affinity list: 3

      如果恢复配置到原来的状态,可以使用如下命令(0-3为初始设置时返回的current affinity list):

       [root@localhost ~]# taskset -pc 0-3 3161
       pid 3161's current affinity list: 2
       pid 3161's new affinity list: 0-3
       [root@localhost ~]# taskset -pc 0-3 3163
       pid 3163's current affinity list: 3
       pid 3163's new affinity list: 0-3
  2. 保证一个CPU固定使用一个网卡队列。

    本例中让CPU2使用eth0的0号队列,CPU3使用eth0的1号队列。

    1. 修改前执行如下命令,首先查询原来的配置,便于恢复:

      cat /sys/class/net/eth0/queues/tx-0/xps_cpus

      cat /sys/class/net/eth0/queues/tx-1/xps_cpus

       [root@localhost ~]# cat /sys/class/net/eth0/queues/tx-0/xps_cpus 
        0
       [root@localhost ~]# cat /sys/class/net/eth0/queues/tx-1/xps_cpus 
        0

      xps_cpus里显示的是CPUbitmask的16进制显示,0、1、2、3四个CPU对应的值分别是1、2、4、8。

    2. 通过如下的命令让CPU2使用eth0的0号队列,CPU3使用eth0的1号队列。

      echo 4 > /sys/class/net/eth0/queues/tx-0/xps_cpus

      echo 8 > /sys/class/net/eth0/queues/tx-1/xps_cpus

      如需恢复原来的配置,使用如下命令:

      echo 0 > /sys/class/net/eth0/queues/tx-0/xps_cpus

      echo 0 > /sys/class/net/eth0/queues/tx-1/xps_cpus

  3. 保证一个网卡队列的中断固定在一个CPU。这个CPU和业务进程的CPU相同。
    1. 首先查询eth0对应的virtio设备的名字,如下查询结果为virtio0。
        [root@localhost ~]# ls /sys/class/net/eth0/device/driver/ | grep virtio
        virtio0
    2. 然后查询virtio0网卡使用的中断的名字,如下查询结果为24、25、26、27、28。
       [root@localhost ~]# cat /proc/interrupts | grep virtio0
       24:          0          0          0          0   PCI-MSI-edge      virtio0-config
       25:        105      52766        114      38738   PCI-MSI-edge      virtio0-input.0
       26:         79      49480     593063     403097   PCI-MSI-edge      virtio0-output.0
       27:         55       3594         46      36720   PCI-MSI-edge      virtio0-input.1
       28:      27277    1262879          0   12099829   PCI-MSI-edge      virtio0-output.1
    3. 编辑irqbalance配置文件。
       [root@localhost ~]# vim /etc/sysconfig/irqbalance
    4. 修改最后一行IRQBALANCE_ARGS为如下,这样irqbalance服务不再调度这几个中断。
       IRQBALANCE_ARGS=--banirq=24-28
    5. 重启irqbalance服务。
       [root@localhost ~]# service irqbalance restart
    6. 修改中断所在CPU,例如设置25、26号中断到CPU2; 27、28号中断到CPU3。
       [root@localhost ~]# echo 2 > /proc/irq/25/smp_affinity_list
       [root@localhost ~]# echo 2 > /proc/irq/26/smp_affinity_list
       [root@localhost ~]# echo 3 > /proc/irq/27/smp_affinity_list
       [root@localhost ~]# echo 3 > /proc/irq/28/smp_affinity_list

场景二:获取的带宽(Gbps)或者吞吐量(Mpps)最高

场景二仅提供优化方案,需要具备相关网络知识,且根据云服务器实际情况和业务场景综合考虑具体操作。

建议首先尝试使用最优效率配置,即场景一:单位CPU获取的带宽(Gbps)或者吞吐量(Mpps)最大的操作方法。确认是否可以满足性能要求。当场景一的方法不满足需求的情况下,推荐使用本场景的方法。

  • 对于即收又发的业务,可以把接收和发送中断分别绑定一个CPU,例如把3的25、26、27、28分别绑定到CPU0、1、2、3。
  • 对于接收繁忙的业务,可以打开RPS(Receive Packet Steering),让一个中断的软中断分散到多个CPU。

场景三:获取最优的不丢包TCP带宽

场景三仅提供优化方案,需要具备相关网络知识,且根据云服务器实际情况和业务场景综合考虑具体操作。

为了获取稳定的TCP不丢包带宽,推荐从小到大修改,设置一个满足业务带宽要求的发送socket缓冲区大小。业务带宽要求应该小于云服务器规格的带宽大小,否则请更换更大规格的实例。

例如推荐从64K缓冲区开始,尝试64K、128K...socket缓冲区大小。

socket缓冲区大小设置示例:

        int opt = 64 * 1024;
        if (setsockopt(sk, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0
            || setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
            log_err("socket buffer size set failed.");
            close(sk);
            return -1;
        }

使用小的发送缓冲区大小,可以避免由于瞬时发送速率太高,超过flavor带宽限速而引起的丢包,从而获得更稳定的带宽。

  • 对于iperf3程序,可以使用-w参数指定缓冲区大小。
  • 对于4.9及以上内核版本,推荐把操作系统的TCP拥塞控制算法修改为BBR算法,这样可以在不修改socket缓冲区大小的情况下,获得一个稳定的TCP不丢包带宽。

    BBR(Bottleneck Bandwidth and Round-trip propagation time)是一种拥塞控制算法,能够在传输最大带宽的同时保证最小的时延。Linux 4.9及以上内核版本自带了该算法,关于把操作系统内核协议栈拥塞控制算法修改为BBR的具体方法可以查询相关网站。

场景四:处理UDP接收丢包场景

场景四仅提供优化方案,需要具备相关网络知识,且根据云服务器实际情况和业务场景综合考虑具体操作。

  1. 执行以下命令,检查是否触发软中断丢包。

    cat /proc/net/softnet_stat

    如果第二列计数值在增长时,则会判断为“软中断丢包”。当您的实例触发了软中断丢包时,可通过以下步骤进行排查及处理:

    1. 执行以下命令,查看是否开启 RPS。

      cat /sys/class/net/eth0/queues/rx-*/rps_cpus

      eth0需改为对应网卡名。如果回显为非全0,则是开启了RPS。

    2. 在开启场景下,内核参数net.core.netdev_max_backlog偏小时会引发软中断丢包,需执行以下命令,调大该值。

      sysctl -w net.core.netdev_max_backlog=65535

      此处为示例数值,具体数值与业务场景相关,可逐步增大尝试。

  2. 检查是否UDP接受缓冲区满导致丢包。

    若您的实例因UDP接收缓冲区不足而导致丢包时,可通过以下步骤进行排查处理:

    1. 执行以下命令,检查UDP中receive buffer errors字段。

      nstat -su

      该字段表示由于接收缓冲区满而不能接收的UDP数据包数量。如果该值较高或者持续增加,可能是因为UDP接收缓冲区满而导致的丢包。

      您可以尝试通过调大内核参数net.core.rmem_max和net.core.rmem_default来增加接收缓冲区的大小,并重启UDP程序以生效。

    2. 执行以下命令,临时调整内核参数。

      查看原始值:

      sysctl -a | grep net.core.rmem_max

      sysctl -a | grep net.core.rmem_default

      修改:

      sysctl -w net.core.rmem_max=2129920

      sysctl -w net.core.rmem_default=2129920

      具体数值与业务场景有关,可逐步增大尝试后再观测缓冲区丢包计数是否增长。

  3. 检查是否为CPU单核软中断高导致丢包。

    通过执行top命令后按1查看每个CPU核的si列占比,确认是否为CPU单核软中断高导致未能及时接收数据。若是,您可以通过以下步骤进行排查处理:

    1. 选择开启RPS,使软中断分配更为均衡。

      RPS采用软件模拟的方式,实现了多队列网卡所提供的功能,分散了在多CPU系统上数据接收时的负载,把软中断分到各个CPU处理,而不需要硬件支持,一般与RFS配合使用。RFS则是尽力保证同一会话仍然由“上次”的CPU处理,这样可以保证cache的热度,提高cache的命中率。

      1. 获取RPS/RFS默认设置。

        执行以下命令,获取接收队列0所设置的CPU掩码,表示将接收队列0散列到指定CPU上,数值是按照16进制表示,如0、1、2、3四个CPU对应的值分别是1、2、4、8。

        cat /sys/class/net/eth0/queues/rx-0/rps_cpus

        执行以下命令命令获取接收队列0的最大栈/流程数。

        cat /sys/class/net/eth0/queues/rx-0/rps_flow_cnt

        执行以下命令,获取内核可以操控的任意指定CPU可控制的最大栈/流程数,是一个系统参数。

        cat /proc/sys/net/core/rps_sock_flow_entries

        以上三个参数共同构成RPS/RFS功能。

      1. 开启RPS。

        以下示例是将eth0网卡接收队列0散列到CPU2核,CPU3核使用eth0的1号接收队列,设置每个接收队列最大栈数为4096,CPU可控制的最大栈为65536:

        echo 4 > /sys/class/net/eth0/queues/rx-0/rps_cpus

        echo 8 > /sys/class/net/eth0/queues/rx-1/rps_cpus

        echo 4096 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt

        echo 4096 > /sys/class/net/eth0/queues/rx-1/rps_flow_cnt

        echo 65536 > /proc/sys/net/core/rps_sock_flow_entries

        一般单网卡队列多CPU场景建议开启RPS以获得更优性能。

    2. 检查业务程序是否会引发软中断分配不均匀。

      如果是业务程序引发的软中断分配不均匀,可通过场景一:单位CPU获取的带宽(Gbps)或者吞吐量(Mpps)最大中保证一个业务进程或线程固定在一个CPU的操作方法进行业务绑核以缓解。

相关文档