Objavljen je detaljan vodič o podešavanju okruženja Linuxa za postizanje maksimalnih performansi za obradu HTTP zahtjeva. Predložene metode omogućile su povećanje performansi JSON procesora temeljenog na biblioteci libreactor u okruženju Amazon EC2 (4 vCPU) s 224 tisuće API zahtjeva u sekundi sa standardnim postavkama Amazon Linux 2 s kernelom 4.14 na 1.2 milijuna zahtjeva po drugi nakon optimizacije (porast od 436%), a također je doveo do smanjenja kašnjenja u obradi zahtjeva za 79%. Predložene metode nisu specifične za libreactor i rade kada se koriste drugi http poslužitelji, uključujući nginx, Actix, Netty i Node.js (libreactor je korišten u testovima jer je rješenje temeljeno na njemu pokazalo bolje performanse).
Osnovne optimizacije:
- Optimiziranje libreactor koda. Kao osnova korištena je opcija R18 iz Techempower kita, koja je poboljšana uklanjanjem koda za ograničavanje broja korištenih CPU jezgri (optimizacija je omogućila ubrzanje rada za 25-27%), sklapanje u GCC s opcijama “-O3” (povećanje od 5-10% ) i "-march-native" (5-10%), zamjena poziva za čitanje/pisanje s recv/send (5-10%) i smanjenje opterećenja pri korištenju pnit (2-3%) . Ukupno povećanje performansi nakon optimizacije koda iznosilo je 55%, a propusnost se povećala s 224k req/s na 347k req/s.
- Onemogući zaštitu od spekulativnih ranjivosti izvršenja. Korištenje parametara “nospectre_v1 nospectre_v2 pti=off mds=off tsx_async_abort=off” prilikom učitavanja kernela omogućilo je povećanje performansi za 28%, a propusnost je povećana sa 347k req/s na 446k req/s. Zasebno, povećanje od parametra “nospectre_v1” (zaštita od Spectre v1 + SWAPGS) bilo je 1-2%, “nospectre_v2” (zaštita od Spectre v2) - 15-20%, "pti=off" (Spectre v3/Meltdown) - 6 %, "mds=off tsx_async_abort=off" (MDS/Zombieload i TSX asinkroni prekid) - 6%. Postavke za zaštitu od L1TF/Foreshadow (l1tf=flush), iTLB multihit, Speculative Store Bypass i SRBDS napada ostavljene su nepromijenjene, što nije utjecalo na izvedbu jer se nisu presijecale s testiranom konfiguracijom (na primjer, specifične za KVM, ugniježđene virtualizacija i drugi CPU modeli).
- Onemogućavanje revizije i mehanizama za blokiranje poziva sustava korištenjem naredbe "auditctl -a never,task" i navođenjem opcije "--security-opt seccomp=unconfined" prilikom pokretanja docker spremnika. Ukupno povećanje performansi iznosilo je 11%, a propusnost se povećala sa 446k req/s na 495k req/s.
- Onemogućavanje iptables/netfilter istovarom povezanih modula kernela. Ideja da se onemogući vatrozid, koji nije korišten u određenom poslužiteljskom rješenju, potaknuta je rezultatima profiliranja, sudeći prema kojima je funkciji nf_hook_slow trebalo 18% vremena da se izvrši. Primijećeno je da nftables radi učinkovitije od iptables, ali Amazon Linux nastavlja koristiti iptables. Nakon onemogućavanja iptables, povećanje performansi bilo je 22%, a propusnost se povećala sa 495k req/s na 603k req/s.
- Smanjena migracija rukovatelja između različitih CPU jezgri radi poboljšanja učinkovitosti korištenja predmemorije procesora. Optimizacija je provedena i na razini vezanja libreactor procesa na CPU jezgre (CPU Pinning) i putem pinning kernel mrežnih rukovatelja (Receive Side Scaling). Na primjer, irqbalance je onemogućen, a afinitet reda čekanja prema CPU-u izričito je postavljen u /proc/irq/$IRQ/smp_affinity_list. Za korištenje iste CPU jezgre za obradu libreactor procesa i mrežnog reda dolaznih paketa, koristi se prilagođeni BPF rukovatelj, povezan postavljanjem zastavice SO_ATTACH_REUSEPORT_CBPF prilikom kreiranja utičnice. Za vezanje redova odlaznih paketa na CPU, postavke /sys/class/net/eth0/queues/tx- su promijenjene /xps_cpus. Ukupno povećanje performansi bilo je 38%, a propusnost je povećana sa 603k req/s na 834k req/s.
- Optimizacija rukovanja prekidima i korištenje prozivanja. Omogućavanje adaptive-rx načina rada u ENA upravljačkom programu i manipuliranje sysctl net.core.busy_read povećalo je performanse za 28% (propusnost je povećana s 834k req/s na 1.06M req/s, a latencija smanjena s 361μs na 292μs).
- Onemogućavanje usluga sustava koje dovode do nepotrebnog blokiranja u mrežnom stogu. Onemogućavanje dhclienta i ručno postavljanje IP adrese rezultiralo je povećanjem performansi od 6%, a propusnost je povećana s 1.06M req/s na 1.12M req/s. Razlog zašto dhclient utječe na izvedbu je analiza prometa korištenjem sirove utičnice.
- Borba protiv Spin Locka. Prebacivanje mrežnog stoga u način rada "noqueue" putem sysctl "net.core.default_qdisc=noqueue" i "tc qdisc replace dev eth0 root mq" dovelo je do povećanja performansi od 2%, a propusnost se povećala s 1.12M req/s na 1.15M zahtjev/s.
- Završne manje optimizacije, kao što je onemogućavanje GRO (Generic Receive Offload) naredbom “ethtool -K eth0 gro off” i zamjena kubičnog algoritma za kontrolu zagušenja s reno koristeći sysctl “net.ipv4.tcp_congestion_control=reno”. Ukupno povećanje produktivnosti iznosilo je 4%. Protok je povećan s 1.15M req/s na 1.2M req/s.
Osim optimizacija koje su uspjele, u članku se govori i o metodama koje nisu dovele do očekivanog povećanja performansi. Na primjer, sljedeće se pokazalo neučinkovitim:
- Odvojeno pokretanje libreactora nije se razlikovalo u izvedbi od pokretanja u spremniku. Zamjena writev s send, povećanje maxevents u epoll_wait i eksperimentiranje s GCC verzijama i zastavicama nije imalo učinka (učinak je bio primjetan samo za zastavice "-O3" i "-march-native").
- Nadogradnja Linux kernela na verzije 4.19 i 5.4, korištenje planera SCHED_FIFO i SCHED_RR, manipuliranje sysctl kernel.sched_min_granularity_ns, kernel.sched_wakeup_granularity_ns, transparent_hugepages=never, skew_tick=1 i clocksource=tsc nije utjecalo na performanse.
- U ENA drajveru, omogućavanje Offload modova (segmentacija, scatter-gather, rx/tx checksum), izgradnja sa zastavom “-O3” i korištenje parametara ena.rx_queue_size i ena.force_large_llq_header nije imalo učinka.
- Promjene u mrežnom stogu nisu poboljšale performanse:
- Onemogući IPv6: ipv6.disable=1
- Onemogući VLAN: modprobe -rv 8021q
- Onemogući provjeru izvora paketa
- net.ipv4.conf.all.rp_filter=0
- net.ipv4.conf.eth0.rp_filter=0
- net.ipv4.conf.all.accept_local=1 (negativan učinak)
- 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_PRIORITET
- TCP_NODELAY
Izvor: opennet.ru