Optimizarea Linux pentru a gestiona 1.2 milioane de solicitări JSON pe secundă

A fost publicat un ghid detaliat despre reglarea mediului Linux pentru a obține performanțe maxime pentru procesarea solicitărilor HTTP. Metodele propuse au făcut posibilă creșterea performanței procesorului JSON bazat pe biblioteca libreactor în mediul Amazon EC2 (4 vCPU) de la 224 de mii de solicitări API pe secundă cu setări standard ale Amazon Linux 2 cu kernel 4.14 la 1.2 milioane de solicitări pe secundă. al doilea după optimizare (o creștere de 436%) și, de asemenea, a dus la o reducere a întârzierilor în procesarea cererilor cu 79%. Metodele propuse nu sunt specifice pentru libreactor și funcționează atunci când se folosesc alte servere http, inclusiv nginx, Actix, Netty și Node.js (libreactor a fost folosit în teste deoarece o soluție bazată pe acesta a arătat performanțe mai bune).

Optimizarea Linux pentru a gestiona 1.2 milioane de solicitări JSON pe secundă

Optimizări de bază:

  • Optimizarea codului libreactor. Ca bază a fost folosită opțiunea R18 din kit-ul Techempower, care a fost îmbunătățită prin eliminarea codului pentru a limita numărul de nuclee CPU utilizate (optimizarea a permis accelerarea lucrărilor cu 25-27%), asamblarea în GCC cu opțiunile „-O3” (o creștere de 5-10% ) și „-march-native” (5-10%), înlocuirea apelurilor de citire/scriere cu recv/send (5-10%) și reducerea supraîncărcării la utilizarea pthread-urilor (2-3%) . Creșterea generală a performanței după optimizarea codului a fost de 55%, iar debitul a crescut de la 224k req/s la 347k req/s.
  • Dezactivați protecția împotriva vulnerabilităților de execuție speculativă. Utilizarea parametrilor „nospectre_v1 nospectre_v2 pti=off mds=off tsx_async_abort=off” la încărcarea nucleului a permis creșterea performanței cu 28%, iar debitul a crescut de la 347k req/s la 446k req/s. Separat, creșterea față de parametrul „nospectre_v1” (protecție față de Spectre v1 + SWAPGS) a fost de 1-2%, „nospectre_v2” (protecție față de Spectre v2) - 15-20%, "pti=off" (Spectre v3/Meltdown) - 6 %, „mds=off tsx_async_abort=off” (MDS/Zombieload și TSX Asynchronous Abort) - 6%. Setările de protecție împotriva atacurilor L1TF/Foreshadow (l1tf=flush), iTLB multihit, Speculative Store Bypass și SRBDS au fost lăsate neschimbate, ceea ce nu a afectat performanța deoarece nu s-au intersectat cu configurația testată (de exemplu, specifice KVM, imbricate). virtualizare și alte modele CPU).
  • Dezactivarea mecanismelor de auditare și de blocare a apelurilor de sistem utilizând comanda „auditctl -a never,task” și specificând opțiunea „--security-opt seccomp=unconfined” la pornirea containerului docker. Creșterea generală a performanței a fost de 11%, iar debitul a crescut de la 446k req/s la 495k req/s.
  • Dezactivarea iptables/netfilter prin descărcarea modulelor nucleului asociate. Ideea de a dezactiva firewall-ul, care nu a fost folosit într-o soluție specifică de server, a fost determinată de rezultatele profilării, judecând după ce funcția nf_hook_slow a durat 18% din timp pentru a se executa. Se observă că nftables funcționează mai eficient decât iptables, dar Amazon Linux continuă să folosească iptables. După dezactivarea iptables, creșterea performanței a fost de 22%, iar debitul a crescut de la 495k req/s la 603k req/s.
  • Migrarea redusă a handlerelor între diferite nuclee ale procesorului pentru a îmbunătăți eficiența utilizării memoriei cache a procesorului. Optimizarea a fost realizată atât la nivel de legare a proceselor libreactor la nucleele CPU (CPU Pinning), cât și prin fixarea handlerelor de rețea kernel (Receive Side Scaling). De exemplu, irqbalance a fost dezactivat și afinitatea la coadă pentru procesor a fost setată în mod explicit în /proc/irq/$IRQ/smp_affinity_list. Pentru a utiliza același nucleu CPU pentru a procesa procesul libreactor și coada de rețea a pachetelor primite, este utilizat un handler BPF personalizat, conectat prin setarea steagului SO_ATTACH_REUSEPORT_CBPF la crearea socket-ului. Pentru a lega cozile de pachete de ieșire la CPU, setările /sys/class/net/eth0/queues/tx- au fost modificate /xps_cpus. Creșterea generală a performanței a fost de 38%, iar debitul a crescut de la 603k req/s la 834k req/s.
  • Optimizarea gestionării întreruperilor și utilizarea sondajului. Activarea modului adaptive-rx în driverul ENA și manipularea sysctl net.core.busy_read a crescut performanța cu 28% (debitul a crescut de la 834k req/s la 1.06M req/s, iar latența a scăzut de la 361μs la 292μs).
  • Dezactivarea serviciilor de sistem care duc la blocări inutile în stiva de rețea. Dezactivarea dhclient și setarea manuală a adresei IP au dus la o creștere a performanței cu 6% și a creșterii debitului de la 1.06 milioane de solicitări/s la 1.12 milioane de solicitări/s. Motivul pentru care dhclient afectează performanța este analiza traficului folosind un socket brut.
  • Luptând Spin Lock. Comutarea stivei de rețea în modul „noqueue” prin sysctl „net.core.default_qdisc=noqueue” și „tc qdisc replace dev eth0 root mq” a condus la o creștere a performanței cu 2%, iar debitul a crescut de la 1.12 M req/s la 1.15 M cerere/s.
  • Optimizări minore finale, cum ar fi dezactivarea GRO (Generic Receive Offload) cu comanda „ethtool -K eth0 gro off” și înlocuirea algoritmului de control al congestiei cubice cu reno folosind sysctl „net.ipv4.tcp_congestion_control=reno”. Creșterea globală a productivității a fost de 4%. Debitul a crescut de la 1.15 milioane de solicitări/s la 1.2 milioane de solicitări/s.

Pe lângă optimizările care au funcționat, articolul discută și metode care nu au condus la creșterea așteptată a performanței. De exemplu, următoarele s-au dovedit a fi ineficiente:

  • Rularea libreactor separat nu diferă ca performanță de rularea acestuia într-un container. Înlocuirea writev cu send, creșterea numărului maxim de evenimente în epoll_wait și experimentarea cu versiuni și steaguri GCC nu au avut niciun efect (efectul a fost vizibil doar pentru steaguri „-O3” și „-march-native”).
  • Actualizarea nucleului Linux la versiunile 4.19 și 5.4, folosind programatoarele SCHED_FIFO și SCHED_RR, manipularea sysctl kernel.sched_min_granularity_ns, kernel.sched_wakeup_granularity_ns, transparent_hugepages=never, skew_source.=ts1 și clocktick nu au afectat performanța.
  • În driverul ENA, activarea modurilor de descărcare (segmentare, scatter-gather, suma de control rx/tx), construirea cu indicatorul „-O3” și utilizarea parametrilor ena.rx_queue_size și ena.force_large_llq_header nu au avut niciun efect.
  • Modificările în stiva de rețea nu au îmbunătățit performanța:
    • Dezactivați IPv6: ipv6.disable=1
    • Dezactivați VLAN: modprobe -rv 8021q
    • Dezactivați verificarea sursei pachetului
      • net.ipv4.conf.all.rp_filter=0
      • net.ipv4.conf.eth0.rp_filter=0
      • net.ipv4.conf.all.accept_local=1 (efect negativ)
    • 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_PRIORITATE
    • TCP_NODELAY

    Sursa: opennet.ru

Adauga un comentariu