优化 Linux 以每秒处理 1.2 万个 JSON 请求

已发布有关调整 Linux 环境以实现处理 HTTP 请求的最佳性能的详细指南。 所提出的方法可以将 Amazon EC2 环境 (4 个 vCPU) 中基于 libreactor 库的 JSON 处理器的性能从具有内核 224 的 Amazon Linux 2 标准设置下的每秒 4.14 万个 API 请求提高到每秒 1.2 万个请求优化后排名第二(增加了 436%),并且还导致处理请求的延迟减少了 79%。 所提出的方法并不特定于 libreactor,并且可以在使用其他 http 服务器时工作,包括 nginx、Actix、Netty 和 Node.js(在测试中使用 libreactor 是因为基于它的解决方案显示出更好的性能)。

优化 Linux 以每秒处理 1.2 万个 JSON 请求

基本优化:

  • 优化 libreactor 代码。 Techempower 套件中的 R18 选项被用作基础,通过删除限制所用 CPU 核心数量的代码进行了改进(优化允许将工作速度加快 25-27%),并使用“-O3”选项在 GCC 中进行组装(增加 5-10%)和“-march-native”(5-10%),用 recv/send 替换读/写调用(5-10%)并减少使用 pthread 时的开销(2-3%) 。 代码优化后整体性能提升55%,吞吐量从224k req/s提升至347k req/s。
  • 禁用针对推测执行漏洞的保护。 加载内核时使用参数“nospectre_v1 nospectre_v2 pti=off mds=off tsx_async_abort=off”使性能提高了 28%,吞吐量从 347k req/s 增加到 446k req/s。 另外,参数“nospectre_v1”(针对 Spectre v1 + SWAPGS 的保护)的增加为 1-2%,“nospectre_v2”(针对 Spectre v2 的保护)– 15-20%,“pti=off”(Spectre v3/Meltdown) – 6 %,“mds=off tsx_async_abort=off”(MDS/Zombieload 和 TSX 异步中止)- 6%。 针对 L1TF/Foreshadow (l1tf=flush)、iTLB multihit、Speculative Store Bypass 和 SRBDS 攻击的防护设置保持不变,这不会影响性能,因为它们与测试的配置没有交叉(例如,特定于 KVM、嵌套虚拟化和其他 CPU 模型)。
  • 使用“auditctl -a never,task”命令禁用审核和系统调用阻止机制,并在启动 docker 容器时指定“--security-opt seccomp=unconfined”选项。 整体性能提升了 11%,吞吐量从 446k req/s 增加到 495k req/s。
  • 通过卸载关联的内核模块来禁用 iptables/netfilter。 禁用防火墙的想法并没有在特定的服务器解决方案中使用,是由分析结果引发的,根据该结果判断,nf_hook_slow 函数的执行时间为 18%。 值得注意的是,nftables 比 iptables 工作效率更高,但 Amazon Linux 继续使用 iptables。 禁用 iptables 后,性能提升了 22%,吞吐量从 495k req/s 增加到 603k req/s。
  • 减少不同CPU核心之间处理程序的迁移,以提高处理器缓存的使用效率。 在将 libreactor 进程绑定到 CPU 核心(CPU Pinning)和通过固定内核网络处理程序(接收端扩展)的层面上进行了优化。 例如,禁用了 irqbalance,并在 /proc/irq/$IRQ/smp_affinity_list 中显式设置了与 CPU 的队列关联性。 为了使用相同的CPU核心来处理libreactor进程和传入数据包的网络队列,需要使用自定义BPF处理程序,通过在创建套接字时设置SO_ATTACH_REUSEPORT_CBPF标志来连接。 要将传出数据包队列绑定到 CPU,设置 /sys/class/net/eth0/queues/tx- 已更改/xps_cpus。 整体性能提升了 38%,吞吐量从 603k req/s 增加到 834k req/s。
  • 优化中断处理和轮询的使用。 在 ENA 驱动程序中启用自适应接收模式并操作 sysctl net.core.busy_read 将性能提高了 28%(吞吐量从 834k req/s 增加到 1.06M req/s,延迟从 361μs 减少到 292μs)。
  • 禁用导致网络堆栈中不必要的阻塞的系统服务。 禁用 dhclient 并手动设置 IP 地址导致性能提高 6%,吞吐量从 1.06M req/s 增加到 1.12M req/s。 dhclient 影响性能的原因是使用原始套接字进行流量分析。
  • 对抗自旋锁。 通过 sysctl“net.core.default_qdisc=noqueue”和“tc qdisc Replace dev eth0 root mq”将网络堆栈切换到“noqueue”模式,性能提高了 2%,吞吐量从 1.12M req/s 增加到 1.15M请求/秒。
  • 最后的小优化,例如使用命令“ethtool -K eth0 gro off”禁用 GRO(通用接收卸载),并使用 sysctl“net.ipv4.tcp_congestion_control=reno”将立方拥塞控制算法替换为 reno。 总体生产率提高了 4%。 吞吐量从 1.15M req/s 增加到 1.2M req/s。

除了有效的优化之外,本文还讨论了没有带来预期性能提升的方法。 例如,以下内容被证明是无效的:

  • 单独运行 libreactor 与在容器中运行它在性能上没有差异。 用 send 替换 writev、增加 epoll_wait 中的 maxevents 以及尝试 GCC 版本和标志都没有效果(仅对“-O3”和“-march-native”标志效果明显)。
  • 将 Linux 内核升级到版本 4.19 和 5.4,使用 SCHED_FIFO 和 SCHED_RR 调度程序,操作 sysctl kernel.sched_min_细粒度_ns、kernel.sched_wakeup_细粒度_ns、transparent_hugepages=never、skew_tick=1 和clocksource=tsc 不会影响性能。
  • 在 ENA 驱动程序中,启用卸载模式(分段、分散收集、rx/tx 校验和)、使用“-O3”标志构建以及使用 ena.rx_queue_size 和 ena.force_large_llq_header 参数没有任何效果。
  • 网络堆栈的变化并没有提高性能:
    • 禁用 IPv6: ipv6.disable=1
    • 禁用 VLAN:modprobe -rv 8021q
    • 禁用包源检查
      • net.ipv4.conf.all.rp_filter=0
      • net.ipv4.conf.eth0.rp_filter=0
      • net.ipv4.conf.all.accept_local=1(负面影响)
    • net.ipv4.tcp_sack = 0
    • net.ipv4.tcp_dsack=0
    • net.ipv4.tcp_mem/tcp_wmem/tcp_rmem
    • net.core.netdev_budget
    • net.core.dev_weight
    • net.core.netdev_max_backlog
    • net.ipv4.tcp_slow_start_after_idle=0
    • net.ipv4.tcp_moderate_rcvbuf=0
    • net.ipv4.tcp_timestamps=0
    • net.ipv4.tcp_low_latency = 1
    • SO_PRIORITY
    • TCP_NODELAY

    来源: opennet.ru

添加评论