การเพิ่มประสิทธิภาพ Linux เพื่อรองรับคำขอ JSON 1.2 ล้านรายการต่อวินาที

มีการเผยแพร่คำแนะนำโดยละเอียดเกี่ยวกับการปรับแต่งสภาพแวดล้อม Linux เพื่อให้ได้ประสิทธิภาพสูงสุดในการประมวลผลคำขอ HTTP วิธีการที่นำเสนอทำให้สามารถเพิ่มประสิทธิภาพของโปรเซสเซอร์ JSON ตามไลบรารี libreactor ในสภาพแวดล้อม Amazon EC2 (4 vCPU) จากคำขอ API 224 รายการต่อวินาทีด้วยการตั้งค่ามาตรฐานของ Amazon Linux 2 ที่มีเคอร์เนล 4.14 ถึง 1.2 ล้านคำขอต่อ รองจากการปรับให้เหมาะสม (เพิ่มขึ้น 436%) และยังช่วยลดความล่าช้าในการประมวลผลคำขอลง 79% วิธีการที่นำเสนอไม่ได้เฉพาะเจาะจงสำหรับ libreactor และใช้งานได้เมื่อใช้เซิร์ฟเวอร์ http อื่นๆ รวมถึง nginx, Actix, Netty และ Node.js (มีการใช้ libreactor ในการทดสอบเนื่องจากโซลูชันที่ใช้วิธีนี้แสดงประสิทธิภาพที่ดีกว่า)

การเพิ่มประสิทธิภาพ Linux เพื่อรองรับคำขอ JSON 1.2 ล้านรายการต่อวินาที

การเพิ่มประสิทธิภาพขั้นพื้นฐาน:

  • การเพิ่มประสิทธิภาพโค้ด libreactor ตัวเลือก R18 จากชุด Techempower ถูกใช้เป็นพื้นฐาน ซึ่งได้รับการปรับปรุงโดยการลบโค้ดเพื่อจำกัดจำนวนคอร์ CPU ที่ใช้ (การเพิ่มประสิทธิภาพอนุญาตให้เร่งการทำงานได้ 25-27%) โดยประกอบใน GCC ด้วยตัวเลือก "-O3" (เพิ่มขึ้น 5-10% ) และ "-march-native" (5-10%) แทนที่การเรียกอ่าน/เขียนด้วย recv/send (5-10%) และลดค่าใช้จ่ายเมื่อใช้ pthreads (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 แบบอะซิงโครนัสยกเลิก) - 6% การตั้งค่าสำหรับการป้องกันการโจมตี L1TF/Foreshadow (l1tf=flush), iTLB multihit, Speculative Store Bypass และการโจมตี SRBDS ยังคงไม่เปลี่ยนแปลง ซึ่งไม่ส่งผลต่อประสิทธิภาพเนื่องจากไม่ได้ตัดกับการกำหนดค่าที่ทดสอบ (เช่น เฉพาะสำหรับ KVM ที่ซ้อนกัน Virtualization และ CPU รุ่นอื่นๆ)
  • ปิดใช้งานกลไกการตรวจสอบและการบล็อกการโทรของระบบโดยใช้คำสั่ง "auditctl -a never,task" และระบุตัวเลือก "--security-opt seccomp=unconfined" เมื่อเริ่มต้นคอนเทนเนอร์นักเทียบท่า ประสิทธิภาพโดยรวมเพิ่มขึ้น 11% และปริมาณงานเพิ่มขึ้นจาก 446k req/s เป็น 495k req/s
  • ปิดการใช้งาน iptables/netfilter โดยยกเลิกการโหลดโมดูลเคอร์เนลที่เกี่ยวข้อง แนวคิดในการปิดการใช้งานไฟร์วอลล์ซึ่งไม่ได้ใช้ในโซลูชันเซิร์ฟเวอร์เฉพาะนั้นได้รับแจ้งจากผลลัพธ์การทำโปรไฟล์ โดยตัดสินว่าฟังก์ชัน nf_hook_slow ใช้เวลา 18% ในการดำเนินการ มีข้อสังเกตว่า nftables ทำงานได้อย่างมีประสิทธิภาพมากกว่า iptables แต่ Amazon Linux ยังคงใช้ iptables ต่อไป หลังจากปิดใช้งาน iptables ประสิทธิภาพเพิ่มขึ้น 22% และปริมาณงานเพิ่มขึ้นจาก 495k req/s เป็น 603k req/s
  • ลดการย้ายตัวจัดการระหว่างคอร์ CPU ที่แตกต่างกันเพื่อปรับปรุงประสิทธิภาพของการใช้แคชของโปรเซสเซอร์ การเพิ่มประสิทธิภาพดำเนินการทั้งในระดับของกระบวนการผูก libreactor กับคอร์ CPU (CPU Pinning) และผ่านการปักหมุดตัวจัดการเครือข่ายเคอร์เนล (Receive Side Scaling) ตัวอย่างเช่น irqbalance ถูกปิดใช้งาน และความสัมพันธ์ของคิวกับ CPU ถูกตั้งค่าอย่างชัดเจนใน /proc/irq/$IRQ/smp_affinity_list หากต้องการใช้ CPU core เดียวกันในการประมวลผลกระบวนการ libreactor และคิวเครือข่ายของแพ็กเก็ตขาเข้า ระบบจะใช้ตัวจัดการ BPF แบบกำหนดเอง เชื่อมต่อโดยการตั้งค่าแฟล็ก SO_ATTACH_REUSEPORT_CBPF เมื่อสร้างซ็อกเก็ต หากต้องการผูกคิวของแพ็กเก็ตขาออกเข้ากับ CPU การตั้งค่า /sys/class/net/eth0/queues/tx- ได้ถูกเปลี่ยนแปลงแล้ว /xps_cpus. ประสิทธิภาพโดยรวมเพิ่มขึ้น 38% และปริมาณงานเพิ่มขึ้นจาก 603k req/s เป็น 834k req/s
  • การเพิ่มประสิทธิภาพการจัดการการขัดจังหวะและการใช้โพล การเปิดใช้งานโหมด Adaptive-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 ความต้องการ/s
  • การปรับปรุงประสิทธิภาพเล็กๆ น้อยๆ ในขั้นสุดท้าย เช่น การปิดใช้งาน GRO (การรับส่งข้อมูลทั่วไป) ด้วยคำสั่ง “ethtool -K eth0 gro off” และแทนที่อัลกอริธึมควบคุมความแออัดแบบลูกบาศก์ด้วย reno โดยใช้ sysctl “net.ipv4.tcp_congestion_control=reno” ผลผลิตโดยรวมเพิ่มขึ้น 4% ปริมาณงานเพิ่มขึ้นจาก 1.15M req/s เป็น 1.2M req/s

นอกเหนือจากการเพิ่มประสิทธิภาพที่ได้ผลแล้ว บทความนี้ยังกล่าวถึงวิธีการที่ไม่นำไปสู่การเพิ่มประสิทธิภาพที่คาดหวังอีกด้วย ตัวอย่างเช่น สิ่งต่อไปนี้กลับกลายเป็นว่าไม่ได้ผล:

  • การเรียกใช้ libreactor แบบแยกกันไม่ได้ทำให้ประสิทธิภาพแตกต่างจากการรันในคอนเทนเนอร์ การแทนที่ writev ด้วย send การเพิ่ม maxevents ใน epoll_wait และการทดลองกับเวอร์ชันและแฟล็ก 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 และ clocksource=tsc ไม่ส่งผลต่อประสิทธิภาพการทำงาน
  • ในไดรเวอร์ ENA การเปิดใช้งานโหมดออฟโหลด (การแบ่งส่วน, การรวบรวมกระจาย, การตรวจสอบ 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_latency = 1
    • SO_ลำดับความสำคัญ
    • TCP_NODELAY

    ที่มา: opennet.ru

เพิ่มความคิดเห็น