Un guide dĂ©taillĂ© sur l'optimisation de l'environnement Linux pour maximiser la performance du traitement des requĂȘtes HTTP a Ă©tĂ© publiĂ©. Les mĂ©thodes proposĂ©es ont permis d'augmenter la performance du gestionnaire JSON basĂ© sur la bibliothĂšque libreactor dans l'environnement Amazon EC2 (4 vCPU) de 224 000 requĂȘtes API par seconde avec les paramĂštres par dĂ©faut d'Amazon Linux 2 avec noyau 4.14 Ă 1,2 million de requĂȘtes par seconde aprĂšs optimisation (augmentation de 436 %), tout en rĂ©duisant les latences de traitement des requĂȘtes de 79 %. Les mĂ©thodes proposĂ©es ne sont pas spĂ©cifiques Ă libreactor et fonctionnent avec d'autres serveurs http, y compris nginx, Actix, Netty et Node.js (libreactor a Ă©tĂ© utilisĂ© dans les tests car la solution basĂ©e sur lui a montrĂ© la meilleure performance).

Optimisations principales :
- Optimisation du code libreactor. Une version R18 du set Techempower a Ă©tĂ© utilisĂ©e comme base, qui a Ă©tĂ© amĂ©liorĂ©e en supprimant le code limitant le nombre de cĆurs CPU utilisĂ©s (l'optimisation a permis d'accĂ©lĂ©rer de 25-27 %), en le compilant avec GCC avec les options « -O3 » (augmentation de 5-10 %) et « -march-native » (5-10 %), en remplaçant les appels read/write par recv/send (5-10 %) et en rĂ©duisant les frais gĂ©nĂ©raux lors de l'utilisation de pthreads (2-3 %). L'augmentation totale de la performance aprĂšs optimisation du code a Ă©tĂ© de 55 %, tandis que le dĂ©bit est passĂ© de 224k req/s Ă 347k req/s.
- DĂ©sactivation de la protection contre les vulnĂ©rabilitĂ©s causĂ©es par l'exĂ©cution spĂ©culative des instructions. L'utilisation des paramĂštres au dĂ©marrage du noyau « nospectre_v1 nospectre_v2 pti=off mds=off tsx_async_abort=off » a permis d'augmenter la performance de 28 %, tandis que le dĂ©bit est passĂ© de 347k req/s Ă 446k req/s. L'augmentation due au paramĂštre « nospectre_v1 » (protection contre Spectre v1 + SWAPGS) Ă©tait de 1-2 %, « nospectre_v2 » (protection contre Spectre v2) â 15-20 %, « pti=off » (Spectre v3/Meltdown) â 6 %, « mds=off tsx_async_abort=off » (MDS/Zombieload et TSX Asynchronous Abort) â 6 %. Les paramĂštres de protection contre les attaques L1TF/Foreshadow (l1tf=flush), iTLB multihit, Speculative Store Bypass et SRBDS ont Ă©tĂ© laissĂ©s inchangĂ©s, car ils n'influençaient pas la performance, Ă©tant donnĂ© qu'ils ne recoupaient pas avec la configuration testĂ©e (par exemple, spĂ©cifiques Ă KVM, la virtualisation imbriquĂ©e et d'autres modĂšles de CPU).
- DĂ©sactivation des mĂ©canismes d'audit et de verrouillage des appels systĂšme Ă l'aide de la commande « auditctl -a never,task » et en spĂ©cifiant l'option « âsecurity-opt seccomp=unconfined » lors du dĂ©marrage du conteneur docker. L'augmentation totale de la performance a Ă©tĂ© de 11 %, tandis que le dĂ©bit est passĂ© de 446k req/s Ă 495k req/s.
- Désactivation d'iptables/netfilter en téléchargeant les modules du noyau qui leur sont associés. L'idée de désactiver le pare-feu, qui n'était pas utilisé dans une solution serveur spécifique, a été motivée par les résultats du profilage, selon lesquels l'exécution de la fonction nf_hook_slow prenait 18 % du temps. Il est noté que nftables fonctionne plus efficacement qu'iptables, mais qu'Amazon Linux continue d'utiliser iptables. AprÚs la désactivation d'iptables, le gain de performance a été de 22 %, et le débit est passé de 495k req/s à 603k req/s.
- RĂ©duction de la migration des gestionnaires entre les diffĂ©rents cĆurs CPU pour amĂ©liorer l'efficacitĂ© de l'utilisation du cache processeur. L'optimisation a Ă©tĂ© rĂ©alisĂ©e Ă la fois au niveau du couplage des processus libreactor aux cĆurs CPU (CPU Pinning) et par le biais de l'affectation des gestionnaires rĂ©seau du noyau (Receive Side Scaling). Par exemple, irqbalance a Ă©tĂ© dĂ©sactivĂ© et des liaisons explicites des files d'attente aux CPU ont Ă©tĂ© Ă©tablies dans /proc/irq/$IRQ/smp_affinity_list. Pour utiliser un mĂȘme cĆur CPU pour le traitement du processus libreactor et de la file d'attente rĂ©seau des paquets entrants, un gestionnaire BPF dĂ©diĂ© a Ă©tĂ© utilisĂ©, connectĂ© via le drapeau SO_ATTACH_REUSEPORT_CBPF lors de la crĂ©ation du socket. Pour lier les files d'attente des paquets sortants au CPU, les paramĂštres dans /sys/class/net/eth0/queues/tx-/xps_cpus ont Ă©tĂ© modifiĂ©s. Le gain de performance total a Ă©tĂ© de 38 %, et le dĂ©bit est passĂ© de 603k req/s Ă 834k req/s.
- Optimisation du traitement des interruptions et utilisation du polling. L'activation du mode adaptive-rx dans le pilote ENA et les manipulations avec sysctl net.core.busy_read ont permis d'augmenter la performance de 28 % (le dĂ©bit est passĂ© de 834k req/s Ă 1,06M req/s, et la latence a diminuĂ© de 361ÎŒs Ă 292ÎŒs).
- Désactivation des services systÚme entraßnant des blocages inutiles dans la pile réseau. La désactivation de dhclient et la configuration adresses IP manuelle ont conduit à une augmentation de la performance de 6 %, et le débit est passé de 1,06M req/s à 1,12M req/s. La raison de l'impact de dhclient sur la performance a été analysée par un trafic à l'aide de socket brut.
- Lutte contre le Spin Lock. Passer la pile réseau en mode « noqueue » via sysctl « net.core.default_qdisc=noqueue » et « tc qdisc replace dev eth0 root mq » a entraßné un gain de performance de 2 %, et le débit est passé de 1,12M req/s à 1,15M req/s.
- Des optimisations finales mineures, telles que la désactivation de GRO (Generic Receive Offload) avec la commande « ethtool -K eth0 gro off » et le remplacement de l'algorithme de contrÎle de congestion cubic par reno via sysctl « net.ipv4.tcp_congestion_control=reno ». L'augmentation globale de performance a été de 4 %. La capacité a augmenté de 1,15 M req/s à 1,2 M req/s.
En plus des optimisations réussies, l'article examine également les méthodes qui n'ont pas conduit à l'augmentation de performance attendue. Par exemple, les suivantes se sont révélées inefficaces :
- Une exécution distincte de libreactor n'a pas présenté de différence de performance par rapport à son exécution dans un conteneur. Le remplacement de writev par send, l'augmentation de maxevents dans epoll_wait, ainsi que les expériences avec les versions et les options de GCC n'ont pas eu d'impact (l'effet n'était perceptible que pour les options « -O3 » et « -march-native »).
- La mise Ă jour du noyau Linux vers les versions 4.19 et 5.4, l'utilisation des planificateurs SCHED_FIFO et SCHED_RR, les manipulations de sysctl kernel.sched_min_granularity_ns, kernel.sched_wakeup_granularity_ns, transparent_hugepages=never, skew_tick=1 et clocksource=tsc n'ont pas eu d'effet sur la performance.
- Dans le pilote ENA, l'activation des modes Offload (segmentation, scatter-gather, rx/tx checksum), la compilation avec l'option « -O3 » et l'application des paramÚtres ena.rx_queue_size et ena.force_large_llq_header n'ont pas influencé les performances.
- Les modifications apportées à la pile réseau n'ont pas entraßné une augmentation de performance :
- Désactivation d'IPv6 : ipv6.disable=1
- Désactivation de VLAN : modprobe -rv 8021q
- Désactivation de la vérification de l'origine des paquets
- net.ipv4.conf.all.rp_filter=0
- net.ipv4.conf.eth0.rp_filter=0
- net.ipv4.conf.all.accept_local=1 (effet négatif)
- 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
Source : opennet.ru
