Saya akan lebih dalam di bawah tanah, atau apa yang harus Anda ketahui, mengoptimalkan aplikasi jaringan

Salam sahabat!

Dalam dua artikel sebelumnya ( satu , dua ), kami terjun ke kompleksitas pilihan antara teknologi dan mencari pengaturan optimal untuk solusi kami di Ostrovok.ru . Topik apa yang akan kita angkat hari ini?

Setiap layanan harus bekerja pada beberapa server, berkomunikasi dengan perangkat keras melalui alat sistem operasi. Ada banyak sekali alat-alat ini, serta pengaturan untuk mereka. Dalam kebanyakan kasus, pengaturan default mereka akan lebih dari cukup. Pada artikel ini, saya ingin berbicara tentang kasus-kasus ketika pengaturan standar masih tidak cukup, dan saya harus mengenal sistem operasi sedikit lebih dekat - dalam kasus kami dengan Linux .



Kami menggunakan kernel dengan bijak


Dalam artikel sebelumnya, saya berbicara tentang opsi cpu-map di Haproxy . Dengan itu, kami mengikat proses Haproxy ke utas dari satu inti pada server prosesor ganda. Kami memberikan inti kedua untuk penanganan interupsi kartu jaringan.

Di bawah ini adalah layar di mana Anda dapat melihat pemisahan serupa. Di sebelah kiri, kernel ditempati oleh Haproxy di user space , dan di sebelah kanan, dengan memproses interupsi dalam kernel space .



Binding interupsi ke kartu jaringan dilakukan secara otomatis menggunakan ini
Skrip bash:
 #! /bin/bash interface=${1} if [ -z "${interface}" ];then echo "no interface specified" echo "usage: ${0} eth1" exit 1 fi nproc=$(grep 'physical id' /proc/cpuinfo|sort -u|wc -l) ncpu=$(grep -c 'processor' /proc/cpuinfo) cpu_per_proc=$[ncpu / nproc] queue_threads=$[cpu_per_proc / 2] binary_map="" cpumap="" for(( i=0; i < ncpu; i++ ));do cpumap=${cpumap}1 b+='{0..1}' done binary_map=($(eval echo ${b})) ###         ###    ,      . ethtool -L ${interface} combined ${queue_threads} || true count=${ncpu} while read irq queue;do let "cpu_num=$[count-1]" let "cpu_index=$[2**cpu_num]" printf "setting ${queue} to %d (%d)\n" $((2#${binary_map[${cpu_index}]})) ${cpu_num} printf "%x\n" "$((2#${binary_map[${cpu_index}]}))" > /proc/irq/${irq}/smp_affinity [ ${interface} != ${queue} ] && count=$[count-1] [ $[ncpu - count] -gt ${queue_threads} ] && count=${ncpu} done < <(awk "/${interface}/ {if(NR > 1){ sub(\":\", \"\", \$1); print \$1,\$(NF)} }" /proc/interrupts) exit 0 


Ada banyak skrip sederhana dan lebih kompleks yang cocok di Internet yang melakukan pekerjaan yang sama, tetapi skrip ini cukup untuk kebutuhan kita.

Di Haproxy, kami menautkan proses ke kernel, dimulai dengan kernel pertama. Script yang sama mengikat interupsi, dimulai dengan yang terakhir. Dengan demikian, kita dapat membagi prosesor server menjadi dua kubu.

Untuk wawasan yang lebih dalam tentang gangguan dan jaringan, saya sangat merekomendasikan membaca artikel ini.

Kami mengungkapkan kemampuan perangkat jaringan


Kebetulan banyak frame dapat terbang melalui jaringan pada satu saat, dan antrian kartu mungkin tidak siap untuk masuknya tamu, bahkan jika ia memiliki kesempatan untuk melakukannya.

Mari kita bicara tentang buffer kartu jaringan. Paling sering, nilai default tidak menggunakan seluruh buffer yang tersedia. Anda dapat melihat pengaturan saat ini menggunakan utilitas ethtool yang kuat.

Contoh penggunaan perintah:

 > ethtool -g eno1 Ring parameters for eno1: Pre-set maximums: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096 Current hardware settings: RX: 256 RX Mini: 0 RX Jumbo: 0 TX: 256 

Sekarang mari kita ambil semuanya dari kehidupan:

 > ethtool -G eno1 rx 4096 tx 4096 > ethtool -g eno1 Ring parameters for eno1: Pre-set maximums: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096 Current hardware settings: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096 

Sekarang Anda dapat yakin bahwa kartu tidak tertahan dan berfungsi maksimal dari kemampuannya.

Pengaturan sysctl minimum untuk manfaat maksimal


Sysctl memiliki beragam pilihan dalam semua warna dan ukuran yang dapat Anda bayangkan. Dan, sebagai suatu peraturan, artikel-artikel di Internet, yang membahas masalah optimisasi, mencakup bagian yang agak mengesankan dari parameter-parameter ini. Saya akan mempertimbangkan hanya mereka yang benar-benar berguna untuk berubah dalam kasus kami.

net.core.netdev_max_backlog - antrian di mana frame dari kartu jaringan dapatkan, yang kemudian diproses oleh kernel. Dengan antarmuka cepat dan sejumlah besar lalu lintas, ia dapat terisi dengan cepat. Default : 1000.
Kita dapat mengamati kelebihan antrian ini dengan melihat kolom kedua di file / proc / net / softnet_stat.
 awk '{print $2}' /proc/net/softnet_stat 

File itu sendiri menjelaskan struktur netif_rx_stats per baris untuk setiap CPU dalam sistem.
Secara khusus, kolom kedua menjelaskan jumlah paket dalam status yang dijatuhkan. Jika nilai di kolom kedua tumbuh seiring waktu, maka mungkin layak meningkatkan nilai net.core.netdev_max_backlog atau menempatkan CPU lebih cepat.

net.core.rmem_default / net.core.rmem_max && net.core.wmem_default / net.core.wmem_max - parameter ini menunjukkan nilai default / nilai maksimum untuk buffer baca dan tulis soket. Nilai default dapat diubah pada level aplikasi pada saat soket dibuat (omong-omong, Haproxy memiliki parameter yang melakukan ini). Kami memiliki kasus ketika kernel melempar lebih banyak paket daripada yang berhasil Haproxy rake, dan kemudian masalah dimulai. Karena itu, masalahnya penting.

net.ipv4.tcp_max_syn_backlog - bertanggung jawab atas batas koneksi baru yang belum dibuat untuk paket SYN yang diterima. Jika ada aliran besar koneksi baru (misalnya, banyak permintaan HTTP dari Connection: close ), masuk akal untuk meningkatkan nilai ini agar tidak membuang waktu mengirim paket yang diteruskan.

net.core.somaxconn - di sini kita berbicara tentang koneksi yang dibuat, tetapi belum diproses oleh aplikasi. Jika server single-threaded, dan dua permintaan datang ke sana, maka permintaan pertama akan diproses oleh fungsi accept() , dan yang kedua akan menggantung di backlog , yang ukurannya bertanggung jawab atas parameter ini.

nf_conntrack_max mungkin yang paling terkenal dari semua parameter. Saya pikir hampir semua orang yang berurusan dengan iptables tahu tentang itu. Idealnya, tentu saja, jika Anda tidak perlu menggunakan iptables yang menyamar, maka Anda dapat membongkar modul conntrack dan tidak memikirkannya. Dalam kasus saya, Docker digunakan, jadi Anda tidak akan mengunggah sesuatu yang istimewa.

Pemantauan Jelas dan tidak terlalu


Agar tidak secara membabi buta mencari mengapa "proksi Anda melambat," akan berguna untuk membuat beberapa grafik dan menatanya dengan pemicu.

nf_conntrack_count adalah metrik yang paling jelas. Di atasnya, Anda dapat memantau berapa banyak koneksi yang sekarang ada di tabel conntrack . Ketika tabel meluap, jalur untuk koneksi baru akan ditutup.

Nilai saat ini dapat ditemukan di sini:

 cat /proc/sys/net/netfilter/nf_conntrack_count 



Segmen Tcp mentransmisikan kembali - jumlah transfer segmen. Metriknya sangat tebal, karena dapat berbicara tentang masalah di tingkat yang berbeda. Peningkatan transfer dapat mengindikasikan masalah jaringan, kebutuhan untuk mengoptimalkan pengaturan sistem, atau bahkan bahwa perangkat lunak akhir (misalnya, Haproxy) tidak melakukan tugasnya. Bagaimanapun, pertumbuhan abnormal dari nilai ini dapat berfungsi sebagai alasan untuk proses.



Di negara kami, peningkatan nilai paling sering menunjukkan masalah dengan salah satu pemasok, meskipun ada masalah dengan kinerja server dan jaringan.

Contoh untuk verifikasi:

 netstat -s|grep 'segments retransmited' 

Socket Recv-Q - ingat, kita berbicara tentang saat-saat ketika sebuah aplikasi mungkin tidak memiliki cukup waktu untuk memproses permintaan, dan kemudian socket backlog akan bertambah? Pertumbuhan indikator ini memperjelas bahwa ada sesuatu yang salah dengan aplikasi tersebut dan tidak dapat mengatasinya.

Saya melihat pegunungan dalam grafik dengan metrik ini, ketika parameter maxconn di Haproxy memiliki nilai default (2000), dan itu sama sekali tidak menerima koneksi baru.

Dan lagi sebuah contoh:

 ss -lntp|awk '/LISTEN/ {print $2}' 



Tidak akan berlebihan untuk memiliki grafik dengan gangguan menurut status koneksi TCP:



Dan secara terpisah membuat time-wait/established , karena nilai-nilai mereka, sebagai suatu peraturan, sangat berbeda dari yang lain:



Selain metrik ini, ada banyak lainnya, tetapi lebih jelas - misalnya, beban pada antarmuka jaringan atau CPU. Pilihan mereka akan lebih bergantung pada spesifikasi beban kerja Anda.

Alih-alih sebuah kesimpulan


Secara umum, itu saja - saya mencoba menggambarkan poin-poin kunci yang harus saya hadapi ketika menyiapkan proxy reverse http. Tampaknya tugas itu tidak sulit, tetapi dengan peningkatan beban, jumlah jebakan yang selalu muncul pada waktu yang salah juga meningkat. Saya harap artikel ini membantu Anda menghindari kesulitan yang harus saya hadapi.

Semua Damai

Source: https://habr.com/ru/post/id440782/


All Articles