Optimizimi i Linux-it për të trajtuar 1.2 milionë kërkesa JSON në sekondë

Një udhëzues i detajuar është publikuar për akordimin e mjedisit Linux për të arritur performancën maksimale për përpunimin e kërkesave HTTP. Metodat e propozuara bënë të mundur rritjen e performancës së procesorit JSON bazuar në bibliotekën libreactor në mjedisin Amazon EC2 (4 vCPU) nga 224 mijë kërkesa API në sekondë me cilësimet standarde të Amazon Linux 2 me kernel 4.14 në 1.2 milion kërkesa për e dyta pas optimizimit (një rritje prej 436%), dhe gjithashtu çoi në një ulje të vonesave në përpunimin e kërkesave me 79%. Metodat e propozuara nuk janë specifike për libreactor dhe funksionojnë kur përdorni serverë të tjerë http, duke përfshirë nginx, Actix, Netty dhe Node.js (libreactor u përdor në teste sepse zgjidhja e bazuar në të tregoi performancë më të mirë).

Optimizimi i Linux-it për të trajtuar 1.2 milionë kërkesa JSON në sekondë

Optimizimi bazë:

  • Optimizimi i kodit libreactor. Opsioni R18 nga kompleti Techempower u përdor si bazë, i cili u përmirësua duke hequr kodin për të kufizuar numrin e bërthamave të CPU të përdorura (optimizimi lejoi përshpejtimin e punës me 25-27%), duke u montuar në GCC me opsionet "-O3". (një rritje prej 5-10%) dhe "-mars-native" (5-10%), duke zëvendësuar thirrjet leximi/shkrimi me recv/send (5-10%) dhe duke reduktuar shpenzimet e përgjithshme kur përdorni threads (2-3%) . Rritja e përgjithshme e performancës pas optimizimit të kodit ishte 55%, dhe xhiroja u rrit nga 224k req/s në 347k req/s.
  • Çaktivizoni mbrojtjen kundër dobësive spekulative të ekzekutimit. Përdorimi i parametrave "nospectre_v1 nospectre_v2 pti=off mds=off tsx_async_abort=off" gjatë ngarkimit të kernelit lejoi rritjen e performancës me 28%, dhe xhiros u rrit nga 347k req/s në 446k req/s. Më vete, rritja nga parametri "nospectre_v1" (mbrojtja nga Spectre v1 + SWAPGS) ishte 1-2%, "nospectre_v2" (mbrojtje nga Spectre v2) - 15-20%, "pti=off" (Spectre v3/Meltdown) - 6 %, "mds=off tsx_async_abort=off" (MDS/Zombieload dhe Aborti asinkron TSX) - 6%. Cilësimet për mbrojtjen kundër sulmeve L1TF/Foreshadow (l1tf=flush), iTLB multihit, Speculative Store Bypass dhe SRBDS u lanë të pandryshuara, të cilat nuk ndikuan në performancën pasi ato nuk kryqëzoheshin me konfigurimin e testuar (për shembull, specifike për KVM, të ndërlidhura virtualizimi dhe modele të tjera CPU).
  • Çaktivizimi i auditimit dhe i mekanizmave të bllokimit të thirrjeve të sistemit duke përdorur komandën "auditctl -a never,task" dhe duke specifikuar opsionin "--security-opt seccomp=unconfined" kur nis kontejnerin e dokerit. Rritja e përgjithshme e performancës ishte 11%, dhe xhiroja u rrit nga 446k req/s në 495k req/s.
  • Çaktivizimi i iptables/netfilter duke shkarkuar modulet e lidhura të kernelit. Ideja për të çaktivizuar murin e zjarrit, i cili nuk u përdor në një zgjidhje specifike të serverit, u nxit nga rezultatet e profilizimit, duke gjykuar nga të cilat funksionit nf_hook_slow iu desh 18% e kohës për t'u ekzekutuar. Vihet re se nftables funksionon në mënyrë më efikase se iptables, por Amazon Linux vazhdon të përdorë iptables. Pas çaktivizimit të iptables, rritja e performancës ishte 22%, dhe xhiroja u rrit nga 495k req/s në 603k req/s.
  • Migrimi i reduktuar i mbajtësve midis bërthamave të ndryshme të CPU-së për të përmirësuar efikasitetin e përdorimit të cache-it të procesorit. Optimizimi u krye si në nivelin e lidhjes së proceseve libreactor me bërthamat e CPU-së (CPU Pinning) ashtu edhe përmes fiksimit të mbajtësve të rrjetit të kernelit (Receive Side Scaling). Për shembull, irqbalance u çaktivizua dhe afiniteti i radhës me CPU-në u vendos në mënyrë të qartë në /proc/irq/$IRQ/smp_affinity_list. Për të përdorur të njëjtën bërthamë CPU për të përpunuar procesin libreactor dhe radhën e rrjetit të paketave hyrëse, përdoret një mbajtës i personalizuar BPF, i lidhur duke vendosur flamurin SO_ATTACH_REUSEPORT_CBPF kur krijoni folenë. Për të lidhur radhët e paketave dalëse me CPU-në, cilësimet /sys/class/net/eth0/queues/tx- janë ndryshuar /xps_cpus. Rritja e përgjithshme e performancës ishte 38%, dhe xhiroja u rrit nga 603k req/s në 834k req/s.
  • Optimizimi i trajtimit të ndërprerjeve dhe përdorimit të sondazhit. Aktivizimi i modalitetit adaptive-rx në drejtuesin ENA dhe manipulimi i sysctl net.core.busy_read rriti performancën me 28% (përdorimi u rrit nga 834k req/s në 1.06M req/s dhe vonesa u ul nga 361μs në 292μs).
  • Çaktivizimi i shërbimeve të sistemit që çojnë në bllokime të panevojshme në grupin e rrjetit. Çaktivizimi i dhclient dhe vendosja manuale e adresës IP rezultoi në një rritje prej 6% të performancës dhe xhiros u rrit nga 1.06M req/s në 1.12M req/s. Arsyeja pse dhclient ndikon në performancën është në analizën e trafikut duke përdorur një prizë të papërpunuar.
  • Fighting Spin Lock. Kalimi i grupit të rrjetit në modalitetin "noqueue" nëpërmjet sysctl "net.core.default_qdisc=noqueue" dhe "tc qdisc zëvendëson dev eth0 rrënjë mq" çoi në një rritje të performancës 2% dhe xhiros u rrit nga 1.12M req/s në 1.15M kërkesë/s.
  • Optimizimet përfundimtare të vogla, të tilla si çaktivizimi i GRO (Generic Receive Offload) me komandën "ethtool -K eth0 gro off" dhe zëvendësimi i algoritmit të kontrollit të kongjestionit kub me reno duke përdorur sysctl "net.ipv4.tcp_congestion_control=reno". Rritja e përgjithshme e produktivitetit ishte 4%. Performanca u rrit nga 1.15 milion kërkesë/s në 1.2 milion kërkesë/s.

Përveç optimizimeve që funksionuan, artikulli diskuton gjithashtu metoda që nuk çuan në rritjen e pritshme të performancës. Për shembull, sa vijon doli të ishte joefektive:

  • Drejtimi i libreactor veçmas nuk ndryshonte në performancë nga drejtimi i tij në një kontejner. Zëvendësimi i writev me send, rritja e maxeventeve në epoll_wait dhe eksperimentimi me versionet dhe flamujt e GCC nuk pati asnjë efekt (efekti ishte i dukshëm vetëm për flamujt "-O3" dhe "-marsh-native").
  • Përmirësimi i kernelit Linux në versionet 4.19 dhe 5.4, duke përdorur planifikuesit SCHED_FIFO dhe SCHED_RR, manipulimi i sysctl kernel.sched_min_granularity_ns, kernel.sched_wakeup_granularity_ns, transparent_hugepages=never, skew_tick=1 dhe c nuk ndikuan në performancën e burimit.
  • Në drejtuesin ENA, aktivizimi i modaliteteve Offload (segmentim, scatter-gather, rx/tx checksum), ndërtimi me flamurin "-O3" dhe përdorimi i parametrave ena.rx_queue_size dhe ena.force_large_llq_header nuk pati asnjë efekt.
  • Ndryshimet në grupin e rrjetit nuk e përmirësuan performancën:
    • Çaktivizo IPv6: ipv6.disable=1
    • Çaktivizo VLAN: modprobe -rv 8021q
    • Çaktivizo kontrollin e burimit të paketës
      • net.ipv4.conf.all.rp_filter=0
      • net.ipv4.conf.eth0.rp_filter=0
      • net.ipv4.conf.all.accept_local=1 (efekt negativ)
    • net.ipv4.tcp_sack = 0
    • net.ipv4.tcp_dsack=0
    • net.ipv4.tcp_mem/tcp_wmem/tcp_rmem
    • net.core.netdev_budget
    • neto.core.dev_pesha
    • 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

    Burimi: opennet.ru

Shto një koment