Linux-ի օպտիմիզացում՝ վայրկյանում 1.2 միլիոն JSON հարցումների մշակման համար

Հրապարակվել է մանրամասն ուղեցույց՝ կարգավորելու Linux միջավայրը՝ HTTP հարցումների մշակման համար առավելագույն արդյունավետության հասնելու համար: Առաջարկվող մեթոդները հնարավորություն են տվել բարձրացնել JSON պրոցեսորի աշխատանքը, որը հիմնված է Amazon EC2 միջավայրում (4 vCPU) Libreactor գրադարանի վրա՝ վայրկյանում 224 հազար API հարցումից Amazon Linux 2-ի ստանդարտ կարգավորումներով միջուկով 4.14 մինչև 1.2 միլիոն հարցում: երկրորդը օպտիմիզացումից հետո (436% աճ), ինչպես նաև հանգեցրեց հարցումների մշակման հետաձգումների կրճատմանը 79%-ով: Առաջարկվող մեթոդները հատուկ չեն libreactor-ին և աշխատում են այլ http սերվերներ օգտագործելիս, ներառյալ nginx, Actix, Netty և Node.js (libreactor-ն օգտագործվել է թեստերում, քանի որ դրա վրա հիմնված լուծումը ցույց է տվել ավելի լավ կատարում):

Linux-ի օպտիմիզացում՝ վայրկյանում 1.2 միլիոն JSON հարցումների մշակման համար

Հիմնական օպտիմալացումներ.

  • Ազատագրողի կոդի օպտիմիզացում: Որպես հիմք օգտագործվեց Techempower հավաքածուի R18 տարբերակը, որը բարելավվեց՝ հեռացնելով կոդը՝ օգտագործվող պրոցեսորի միջուկների քանակը սահմանափակելու համար (օպտիմալացումը թույլ էր տալիս արագացնել աշխատանքը 25-27%)՝ GCC-ում հավաքելով «-O3» տարբերակներով: (5-10% աճ ) և «-մարշ-հայրենի» (5-10%), կարդալու/գրելու զանգերը փոխարինելով recv/send-ով (5-10%) և կրճատելով գերավճարները pthreads օգտագործելիս (2-3%): . Կոդերի օպտիմալացումից հետո կատարողականի ընդհանուր աճը կազմել է 55%, իսկ թողունակությունը 224k req/վրկ-ից աճել է մինչև 347k req/վ:
  • Անջատել պաշտպանությունը սպեկուլյատիվ կատարման խոցելիությունից: «nospectre_v1 nospectre_v2 pti=off mds=off tsx_async_abort=off» պարամետրերի օգտագործումը միջուկը բեռնելիս թույլ է տվել բարձրացնել կատարողականը 28%-ով, իսկ թողունակությունը 347k req/վ-ից աճել է մինչև 446k req/s: Առանձին-առանձին, «nospectre_v1» (պաշտպանություն Spectre v1 + SWAPGS) պարամետրից աճը կազմել է 1-2%, «nospectre_v2» (պաշտպանություն Spectre v2-ից)՝ 15-20%, «pti=off» (Spectre v3/Meltdown) - 6 %, «mds=off tsx_async_abort=off» (MDS/Zombieload և TSX Asynchronous Abort) - 6%: L1TF/Foreshadow (l1tf=flush), iTLB multihit, Speculative Store Bypass և SRBDS հարձակումներից պաշտպանվելու կարգավորումները մնացել են անփոփոխ, ինչը չի ազդել աշխատանքի վրա, քանի որ դրանք չեն հատվում փորձարկված կազմաձևի հետ (օրինակ՝ հատուկ KVM-ին, ներկառուցված վիրտուալացում և այլ պրոցեսորի մոդելներ):
  • Անջատել աուդիտը և համակարգային զանգերի արգելափակման մեխանիզմները՝ օգտագործելով «auditctl -a never,task» հրամանը և նշելով «--security-opt seccomp=unconfined» տարբերակը՝ դոկերի կոնտեյները գործարկելիս: Ընդհանուր կատարողականի աճը կազմել է 11%, իսկ թողունակությունն աճել է 446k req/վրկ-ից մինչև 495k req/վ:
  • Անջատել iptables/netfilter-ը՝ բեռնաթափելով հարակից միջուկի մոդուլները: Firewall-ն անջատելու գաղափարը, որը չի օգտագործվել հատուկ սերվերի լուծումում, առաջացրել է պրոֆիլավորման արդյունքները, դատելով ըստ որոնց, nf_hook_slow ֆունկցիան գործարկելու համար պահանջվում է ժամանակի 18%-ը: Նշվում է, որ nftables-ն ավելի արդյունավետ է աշխատում, քան iptables-ը, սակայն Amazon Linux-ը շարունակում է օգտագործել iptable-ները։ iptables-ն անջատելուց հետո կատարողականի աճը կազմել է 22%, իսկ թողունակությունը 495k req/վրկ-ից հասել է 603k req/վ:
  • Կրճատվել է մշակողների միգրացիան տարբեր CPU միջուկների միջև՝ պրոցեսորի քեշի օգտագործման արդյունավետությունը բարելավելու համար: Օպտիմալացումն իրականացվել է ինչպես CPU-ի միջուկներին կապող ազատարար գործընթացների (CPU Pinning) և այնպես էլ միջուկի ցանցային կարգավորիչների ամրացման մակարդակով (Receive Side Scaling): Օրինակ, irqbalance-ն անջատված է, և հերթի կապը CPU-ին հստակորեն սահմանվել է /proc/irq/$IRQ/smp_affinity_list-ում: Միևնույն պրոցեսորի միջուկը ազատագրիչի պրոցեսը և մուտքային փաթեթների ցանցային հերթը մշակելու համար օգտագործվում է հատուկ BPF մշակիչ, որը միացված է վարդակից ստեղծելիս SO_ATTACH_REUSEPORT_CBPF դրոշը դնելով: Ելքային փաթեթների հերթերը CPU-ին կապելու համար փոխվել են /sys/class/net/eth0/queues/tx- կարգավորումները: /xps_cpus. Ընդհանուր կատարողականի աճը կազմել է 38%, իսկ թողունակությունն աճել է 603k req/վրկ-ից մինչև 834k req/վ:
  • Ընդհատումների կառավարման և քվեարկության օգտագործման օպտիմիզացում: ՀԷՑ-ի դրայվերում հարմարվողական-rx ռեժիմը միացնելը և sysctl net.core.busy_read-ի շահարկումը բարձրացրել են կատարողականությունը 28%-ով (գործունակությունը 834k req/վրկ-ից աճել է մինչև 1.06M req/վ, իսկ հետաձգումը նվազել է 361μs-ից մինչև 292μs):
  • Համակարգային ծառայությունների անջատում, որոնք հանգեցնում են ցանցի կույտում անհարկի արգելափակման: dhclient-ի անջատումը և IP հասցեն ձեռքով սահմանելը հանգեցրել է 6% կատարողականի բարձրացման, իսկ թողունակությունը 1.06M պահանջ/վրկ-ից մինչև 1.12M պահանջ/վրկ: Պատճառը, թե ինչու է dhclient-ը ազդում աշխատանքի վրա, երթևեկության վերլուծությունն է՝ օգտագործելով չմշակված վարդակից:
  • Fighting Spin Lock. Ցանցի կույտը «noqueue» ռեժիմի անցնելը sysctl «net.core.default_qdisc=noqueue» և «tc qdisc-ը փոխարինում է dev eth0 root mq»-ի միջոցով հանգեցրել է կատարողականի 2%-ով բարձրացման, իսկ թողունակությունը 1.12M պահանջ/վրկ-ից աճել է մինչև 1.15M: պահանջ/ներ.
  • Վերջնական փոքր օպտիմիզացումներ, ինչպիսիք են GRO-ի անջատումը (Generic Receive Offload) «ethtool -K eth0 gro off» հրամանով և փոխարինելով խորանարդ գերբեռնվածության կառավարման ալգորիթմը reno-ով, օգտագործելով sysctl «net.ipv4.tcp_congestion_control=reno»: Ընդհանուր արտադրողականության աճը կազմել է 4%: Թողունակությունն աճել է 1.15M պահանջ/վրկ-ից մինչև 1.2M պահանջ/վ:

Ի լրումն աշխատած օպտիմալացումների, հոդվածում քննարկվում են նաև մեթոդներ, որոնք չեն հանգեցրել ակնկալվող կատարողականի բարձրացմանը: Օրինակ՝ անարդյունավետ է ստացվել հետևյալը.

  • Առանձին վազող լիբրեակտորն իր կատարողականությամբ չէր տարբերվում կոնտեյներով աշխատելուց: Writv-ը send-ով փոխարինելը, epoll_wait-ում maxevents-ի ավելացումը և GCC տարբերակների ու դրոշների հետ փորձարկումները ոչ մի ազդեցություն չունեցան (էֆեկտը նկատելի էր միայն «-O3» և «-march-native» դրոշների համար):
  • Linux միջուկի արդիականացում մինչև 4.19 և 5.4 տարբերակների, օգտագործելով SCHED_FIFO և SCHED_RR ժամանակացույցերը, շահարկելով sysctl kernel.sched_min_granularity_ns, kernel.sched_wakeup_granularity_ns, transparent_hugepages=never, skew_tick=1-ը և c-ը չեն ազդել աշխատանքի վրա:
  • ՀԷՑ-ի դրայվերում Offload ռեժիմները միացնելը (segmentation, scatter-gather, rx/tx checksum), «-O3» դրոշակով կառուցելը և ena.rx_queue_size և ena.force_large_llq_header պարամետրերի օգտագործումը ոչ մի ազդեցություն չունեցավ:
  • Ցանցի կույտի փոփոխությունները չեն բարելավում կատարողականությունը.
    • Անջատել IPv6-ը՝ ipv6.disable=1
    • Անջատել VLAN-ը՝ modprobe -rv 8021q
    • Անջատել փաթեթի աղբյուրի ստուգումը
      • net.ipv4.conf.all.rp_filter=0
      • net.ipv4.conf.eth0.rp_filter=0
      • net.ipv4.conf.all.accept_local=1 (բացասական էֆեկտ)
    • 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

Добавить комментарий