Ottimizzazione di Linux per gestire 1,2 milioni di richieste JSON al secondo

È stata pubblicata una guida dettagliata per l'ottimizzazione dell'ambiente Linux al fine di raggiungere le massime prestazioni nell'elaborazione delle richieste HTTP. I metodi proposti hanno permesso di aumentare le prestazioni del gestore JSON basato sulla libreria libreactor nell'ambiente Amazon EC2 (4 vCPU) da 224 mila richieste API al secondo con le impostazioni predefinite di Amazon Linux 2 con kernel 4.14 a 1,2 milioni di richieste al secondo dopo l'ottimizzazione (un aumento del 436%), e hanno anche portato a una riduzione dei tempi di latenza nell'elaborazione delle richieste del 79%. I metodi proposti non sono specifici per libreactor e funzionano con altri server http, inclusi nginx, Actix, Netty e Node.js (libreactor è stato utilizzato nei test poiché la soluzione basata su di esso ha mostrato le migliori prestazioni).

Ottimizzazione di Linux per gestire 1,2 milioni di richieste JSON al secondo

Ottimizzazioni principali:

  • Ottimizzazione del codice libreactor. Come base è stata utilizzata la versione R18 dal set Techempower, che è stata migliorata rimuovendo il codice per limitare il numero di core CPU utilizzati (l'ottimizzazione ha consentito di accelerare le prestazioni del 25-27%), compilando in GCC con le opzioni "-O3" (aumento del 5-10%) e "-march-native" (5-10%), sostituendo le chiamate read/write con recv/send (5-10%) e riducendo le spese generali nell'uso di pthreads (2-3%). L'aumento totale delle prestazioni dopo l'ottimizzazione del codice è stato del 55%, mentre la larghezza di banda è aumentata da 224k req/s a 347k req/s.
  • Disattivazione della protezione contro le vulnerabilità causate dall'esecuzione speculativa delle istruzioni. L'uso dei parametri al boot del kernel "nospectre_v1 nospectre_v2 pti=off mds=off tsx_async_abort=off" ha permesso di aumentare le prestazioni del 28%, e la larghezza di banda è aumentata da 347k req/s a 446k req/s. In termini separati, l'aumento dal parametro "nospectre_v1" (protezione da Spectre v1 + SWAPGS) è stato dell'1-2%, "nospectre_v2" (protezione da Spectre v2) ha portato un incremento del 15-20%, "pti=off" (Spectre v3/Meltdown) ha fornito un aumento del 6%, e "mds=off tsx_async_abort=off" (MDS/Zombieload e TSX Asynchronous Abort) ha aggiunto un 6%. Le impostazioni per la protezione contro attacchi L1TF/Foreshadow (l1tf=flush), iTLB multihit, Speculative Store Bypass e SRBDS sono state mantenute invariati, in quanto non hanno influenzato le prestazioni, non intersecandosi con la configurazione testata (ad esempio, specifiche per KVM, virtualizzazione annidata e altri modelli di CPU).
  • Disattivazione dei meccanismi di audit e blocco delle chiamate di sistema utilizzando il comando "auditctl -a never,task" e specificando l'opzione "--security-opt seccomp=unconfined" durante l'avvio del contenitore docker. L'aumento complessivo delle prestazioni è stato dell'11%, mentre la larghezza di banda è aumentata da 446k req/s a 495k req/s.
  • Disabilitare iptables/netfilter mediante il caricamento dei moduli kernel correlati. L'idea di disattivare il firewall, non utilizzato in una soluzione server specifica, è stata suggerita dai risultati del profiling, che indicano che la funzione nf_hook_slow richiedeva il 18% del tempo. Si nota che nftables funziona in modo più efficiente rispetto a iptables, ma in Amazon Linux si continua a utilizzare iptables. Dopo aver disattivato iptables, il miglioramento delle prestazioni è stato del 22%, mentre la larghezza di banda è aumentata da 495k req/s a 603k req/s.
  • Riduzione della migrazione dei gestori tra diversi core CPU per migliorare l'efficienza dell'utilizzo della cache del processore. L'ottimizzazione è stata eseguita sia a livello di binding dei processi libreactor ai core CPU (CPU Pinning), sia attraverso il legame dei gestori di rete del kernel (Receive Side Scaling). Ad esempio, è stata disattivata irqbalance e sono state impostate esplicitamente le affinità delle code con CPU in /proc/irq/$IRQ/smp_affinity_list. Per utilizzare lo stesso core CPU per elaborare i processi libreactor e la coda di rete dei pacchetti in ingresso è stato utilizzato un gestore BPF personalizzato, connesso tramite l'impostazione del flag SO_ATTACH_REUSEPORT_CBPF durante la creazione del socket. Per legare alle CPU le code dei pacchetti in uscita, sono state modificate le impostazioni in /sys/class/net/eth0/queues/tx-<n>/xps_cpus. L'incremento totale delle prestazioni è stato del 38%, con la larghezza di banda aumentata da 603k req/s a 834k req/s.
  • Ottimizzazione della gestione delle interruzioni e utilizzo del polling. L'attivazione della modalità adaptive-rx nel driver ENA e le manipolazioni con sysctl net.core.busy_read hanno consentito di aumentare le prestazioni del 28% (la larghezza di banda è aumentata da 834k req/s a 1.06M req/s, mentre i ritardi sono diminuiti da 361μs a 292μs).
  • Disabilitazione dei servizi di sistema che portano a blocchi indesiderati nello stack di rete. Disattivare dhclient e installare Indirizzi IP manualmente ha portato a un incremento delle prestazioni del 6%, con la larghezza di banda aumentata da 1.06M req/s a 1.12M req/s. La causa dell'impatto di dhclient sulle prestazioni è stata analizzata tramite il traffico utilizzando un socket raw.
  • Gestione dello Spin Lock. Portare lo stack di rete in modalità "noqueue" tramite sysctl "net.core.default_qdisc=noqueue" e "tc qdisc replace dev eth0 root mq" ha portato a un incremento delle prestazioni del 2%, con la larghezza di banda aumentata da 1.12M req/s a 1.15M req/s.
  • Ottimizzazioni finali minori, come disabilitare GRO (Generic Receive Offload) con il comando «ethtool -K eth0 gro off» e cambiare l'algoritmo di controllo della congestione da cubic a reno tramite sysctl «net.ipv4.tcp_congestion_control=reno». L'aumento complessivo delle prestazioni è stato del 4%. La capacità è passata da 1,15M req/s a 1,2M req/s.

Oltre alle ottimizzazioni implementate, l'articolo esamina anche i metodi che non hanno portato all'atteso aumento delle prestazioni. Ad esempio, sono risultati inefficaci:

  • L'esecuzione separata di libreactor non ha mostrato differenze nelle prestazioni rispetto all'esecuzione in un contenitore. Non hanno avuto effetto la sostituzione di writev con send, l'aumento di maxevents in epoll_wait, esperimenti con versioni e flag di GCC (l'effetto era visibile solo per i flag «-O3» e «-march-native»).
  • Non ha influito sulle prestazioni l'aggiornamento del kernel Linux alle versioni 4.19 e 5.4, l'uso dei pianificatori SCHED_FIFO e SCHED_RR, le manipolazioni con sysctl kernel.sched_min_granularity_ns, kernel.sched_wakeup_granularity_ns, transparent_hugepages=never, skew_tick=1 e clocksource=tsc.
  • Nel driver ENA non ha influito l'attivazione delle modalità Offload (segmentazione, scatter-gather, checksum rx/tx), la compilazione con il flag «-O3» e l'applicazione dei parametri ena.rx_queue_size e ena.force_large_llq_header.
  • Non hanno portato a un aumento delle prestazioni le modifiche nello stack di rete:
    • Disabilitare IPv6: ipv6.disable=1
    • Disabilitare VLAN: modprobe -rv 8021q
    • Disabilitare il controllo dell'origine del pacchetto
      • net.ipv4.conf.all.rp_filter=0
      • net.ipv4.conf.eth0.rp_filter=0
      • net.ipv4.conf.all.accept_local=1 (effetto negativo)
    • 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

    Fonte: opennet.ru

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster