بهینه سازی لینوکس برای رسیدگی به 1.2 میلیون درخواست JSON در ثانیه

راهنمای دقیقی در مورد تنظیم محیط لینوکس برای دستیابی به حداکثر کارایی برای پردازش درخواست های HTTP منتشر شده است. روش های پیشنهادی افزایش عملکرد پردازنده JSON بر اساس کتابخانه libreactor در محیط Amazon EC2 (4 vCPU) را از 224 هزار درخواست API در ثانیه با تنظیمات استاندارد لینوکس آمازون 2 با هسته 4.14 به 1.2 میلیون درخواست در هر ثانیه ممکن کرد. دوم پس از بهینه سازی (افزایش 436٪)، و همچنین منجر به کاهش تاخیر در پردازش درخواست ها تا 79٪ شد. روش‌های پیشنهادی مختص libreactor نیستند و هنگام استفاده از سرورهای http دیگر، از جمله nginx، Actix، Netty و Node.js کار می‌کنند (libreactor در آزمایش‌ها استفاده شد، زیرا راه‌حل مبتنی بر آن عملکرد بهتری را نشان داد).

بهینه سازی لینوکس برای رسیدگی به 1.2 میلیون درخواست JSON در ثانیه

بهینه سازی های اساسی:

  • بهینه سازی کد لیبراکتور گزینه R18 از کیت Techempower به عنوان پایه مورد استفاده قرار گرفت، که با حذف کد برای محدود کردن تعداد هسته‌های CPU استفاده شده بهبود یافت (بهینه‌سازی اجازه می‌دهد سرعت کار را 25-27٪ افزایش دهد)، مونتاژ در GCC با گزینه‌های "-O3" (افزایش 5-10٪ ) و "-marsh-native" (5-10٪)، جایگزینی تماس های خواندن/نوشتن با recv/send (5-10٪) و کاهش سربار هنگام استفاده از pthread (2-3٪) . افزایش عملکرد کلی پس از بهینه سازی کد 55٪ بود و توان عملیاتی از 224k req/s به 347k req/s افزایش یافت.
  • غیرفعال کردن محافظت در برابر آسیب‌پذیری‌های اجرای گمانه‌زنی. استفاده از پارامترهای "nospectre_v1 nospectre_v2 pti=off mds=off tsx_async_abort=off" در هنگام بارگذاری کرنل باعث افزایش کارایی تا 28% شد و توان عملیاتی از 347k req/s به 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، تودرتو). مجازی سازی و سایر مدل های CPU).
  • غیرفعال کردن مکانیسم های ممیزی و مسدود کردن تماس های سیستمی با استفاده از دستور "auditctl -a never,task" و مشخص کردن گزینه "--security-opt seccomp=unconfined" هنگام راه اندازی کانتینر docker. افزایش عملکرد کلی 11٪ بود و توان عملیاتی از 446k req/s به 495k req/s افزایش یافت.
  • غیرفعال کردن iptables/netfilter با بارگیری ماژول‌های هسته مرتبط. ایده غیرفعال کردن فایروال، که در راه حل سرور خاصی مورد استفاده قرار نمی گرفت، با نتایج پروفایل ایجاد شد، قضاوت بر اساس آن که اجرای تابع nf_hook_slow 18٪ زمان را صرف کرد. اشاره شده است که nftables کارآمدتر از iptables کار می کند، اما لینوکس آمازون همچنان از iptables استفاده می کند. پس از غیرفعال کردن iptables، افزایش عملکرد 22٪ بود و توان عملیاتی از 495k req/s به 603k req/s افزایش یافت.
  • کاهش مهاجرت هندلرها بین هسته های مختلف CPU برای بهبود کارایی استفاده از حافظه پنهان پردازنده. بهینه‌سازی هم در سطح فرآیندهای لیبراکتور اتصال به هسته‌های CPU (CPU Pinning) و هم از طریق پین کردن کنترل‌کننده‌های شبکه هسته (Receive Side Scaling) انجام شد. به عنوان مثال، irqbalance غیرفعال شد و وابستگی صف به CPU به صراحت در /proc/irq/$IRQ/smp_affinity_list تنظیم شد. برای استفاده از همان هسته CPU برای پردازش فرآیند لیبراکتور و صف شبکه بسته‌های ورودی، از یک کنترل‌کننده BPF سفارشی استفاده می‌شود که با تنظیم پرچم SO_ATTACH_REUSEPORT_CBPF هنگام ایجاد سوکت، متصل می‌شود. برای اتصال صف بسته های خروجی به CPU، تنظیمات /sys/class/net/eth0/queues/tx- تغییر کرده است. /xps_cpus. افزایش عملکرد کلی 38٪ بود و توان عملیاتی از 603k req/s به 834k req/s افزایش یافت.
  • بهینه سازی مدیریت وقفه و استفاده از نظرسنجی. فعال کردن حالت تطبیقی-rx در درایور ENA و دستکاری sysctl net.core.busy_read عملکرد را تا 28 درصد افزایش داد (بازده از 834k req/s به 1.06M req/s افزایش یافت و تأخیر از 361μs به 292μs کاهش یافت).
  • غیرفعال کردن خدمات سیستمی که منجر به مسدود شدن غیر ضروری در پشته شبکه می شود. غیرفعال کردن dhclient و تنظیم دستی آدرس IP منجر به افزایش 6 درصدی عملکرد و افزایش توان عملیاتی از 1.06M req/s به 1.12M req/s شد. دلیل اینکه dhclient بر عملکرد تأثیر می گذارد در تجزیه و تحلیل ترافیک با استفاده از یک سوکت خام است.
  • مبارزه با اسپین قفل. تغییر پشته شبکه به حالت "noqueue" از طریق sysctl "net.core.default_qdisc=noqueue" و "tc qdisc جایگزین dev eth0 root mq" منجر به افزایش عملکرد 2٪ و توان عملیاتی از 1.12M req/s به 1.15M افزایش یافت. req/s
  • بهینه سازی های جزئی نهایی، مانند غیرفعال کردن GRO (Generic Receive Offload) با دستور "ethtool -K eth0 gro off" و جایگزینی الگوریتم کنترل تراکم مکعبی با reno با استفاده از sysctl "net.ipv4.tcp_congestion_control=reno". افزایش بهره وری کلی 4 درصد بود. توان عملیاتی از 1.15M req/s به 1.2M req/s افزایش یافت.

علاوه بر بهینه‌سازی‌هایی که کار می‌کردند، مقاله روش‌هایی را نیز مورد بحث قرار می‌دهد که منجر به افزایش عملکرد مورد انتظار نشدند. به عنوان مثال، موارد زیر بی اثر بود:

  • اجرای لیبراکتور به طور جداگانه از نظر عملکرد با اجرای آن در یک کانتینر تفاوتی نداشت. جایگزینی Writv با send، افزایش maxevents در epoll_wait، و آزمایش با نسخه‌های GCC و پرچم‌ها هیچ تأثیری نداشت (اثر فقط برای پرچم‌های "-O3" و "-مارش-بومی" قابل توجه بود).
  • ارتقای هسته لینوکس به نسخه‌های 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 روی عملکرد تأثیری نداشت.
  • در درایور ENA، فعال کردن حالت‌های Offload (بخش‌بندی، پراکندگی جمع‌آوری، جمع‌بندی کنترلی rx/tx)، ساخت با پرچم «-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_ تأخیر = 1
    • SO_PRIORITY
    • TCP_NODELAY

    منبع: opennet.ru

اضافه کردن نظر