Terkadang lebih banyak berarti lebih sedikit. Ketika mengurangi beban menghasilkan peningkatan latensi

Seperti dalam sebagian besar postingan, ada masalah dengan layanan terdistribusi, sebut saja layanan ini Alvin. Kali ini saya tidak menemukan masalahnya sendiri, orang-orang dari sisi klien memberi tahu saya.

Suatu hari saya terbangun karena email ketidakpuasan karena penundaan yang lama dengan Alvin, yang kami rencanakan untuk diluncurkan dalam waktu dekat. Secara khusus, klien mengalami latensi persentil ke-99 dalam rentang 50 ms, jauh di atas anggaran latensi kami. Hal ini mengejutkan karena saya menguji layanan ini secara ekstensif, terutama pada latensi, yang merupakan keluhan umum.

Sebelum saya menguji Alvin, saya menjalankan banyak eksperimen dengan 40 ribu kueri per detik (QPS), semuanya menunjukkan latensi kurang dari 10 md. Saya siap menyatakan bahwa saya tidak setuju dengan hasil mereka. Tapi ketika melihat kembali surat itu, saya melihat sesuatu yang baru: Saya belum benar-benar menguji kondisi yang mereka sebutkan, QPS mereka jauh lebih rendah daripada saya. Saya menguji pada 40k QPS, tetapi hanya pada 1k. Saya menjalankan eksperimen lain, kali ini dengan QPS yang lebih rendah, hanya untuk menenangkan mereka.

Sejak saya menulis blog tentang ini, Anda mungkin sudah mengetahui bahwa nomor mereka benar. Saya menguji klien virtual saya berulang kali, dengan hasil yang sama: jumlah permintaan yang rendah tidak hanya meningkatkan latensi, namun juga meningkatkan jumlah permintaan dengan latensi lebih dari 10 ms. Dengan kata lain, jika pada QPS 40k sekitar 50 permintaan per detik melebihi 50 ms, maka pada QPS 1k terdapat 100 permintaan di atas 50 ms setiap detik. Paradoks!

Terkadang lebih banyak berarti lebih sedikit. Ketika mengurangi beban menghasilkan peningkatan latensi

Mempersempit pencarian

Ketika dihadapkan pada masalah latensi dalam sistem terdistribusi dengan banyak komponen, langkah pertama adalah membuat daftar pendek tersangka. Mari kita gali lebih dalam tentang arsitektur Alvin:

Terkadang lebih banyak berarti lebih sedikit. Ketika mengurangi beban menghasilkan peningkatan latensi

Titik awal yang baik adalah daftar transisi I/O yang telah selesai (panggilan jaringan/pencarian disk, dll.). Mari kita coba mencari tahu di mana penundaannya. Selain I/O yang jelas dengan klien, Alvin mengambil langkah ekstra: dia mengakses penyimpanan data. Namun, penyimpanan ini beroperasi di cluster yang sama dengan Alvin, jadi latensi di sana harus lebih kecil dibandingkan dengan klien. Nah, daftar tersangkanya:

  1. Panggilan jaringan dari klien ke Alvin.
  2. Panggilan jaringan dari Alvin ke penyimpanan data.
  3. Cari di disk di penyimpanan data.
  4. Panggilan jaringan dari gudang data ke Alvin.
  5. Panggilan jaringan dari Alvin ke klien.

Mari kita coba mencoret beberapa poin.

Penyimpanan data tidak ada hubungannya dengan itu

Hal pertama yang saya lakukan adalah mengonversi Alvin ke server ping-ping yang tidak memproses permintaan. Saat menerima permintaan, ia mengembalikan respons kosong. Jika latensi menurun, maka bug pada implementasi Alvin atau data warehouse tidak akan pernah terjadi. Pada percobaan pertama kita mendapatkan grafik sebagai berikut:

Terkadang lebih banyak berarti lebih sedikit. Ketika mengurangi beban menghasilkan peningkatan latensi

Seperti yang Anda lihat, tidak ada peningkatan saat menggunakan server ping-ping. Ini berarti gudang data tidak meningkatkan latensi, dan daftar tersangka dipotong setengahnya:

  1. Panggilan jaringan dari klien ke Alvin.
  2. Panggilan jaringan dari Alvin ke klien.

Besar! Daftarnya menyusut dengan cepat. Saya pikir saya hampir menemukan alasannya.

gRPC

Sekarang saatnya memperkenalkan Anda kepada pemain baru: gRPC. Ini adalah perpustakaan sumber terbuka dari Google untuk komunikasi dalam proses RPC. Meskipun gRPC dioptimalkan dengan baik dan digunakan secara luas, ini adalah pertama kalinya saya menggunakannya pada sistem sebesar ini dan saya berharap implementasi saya menjadi kurang optimal - untuk sedikitnya.

tersedianya gRPC di tumpukan memunculkan pertanyaan baru: mungkin itu implementasi saya atau saya sendiri gRPC menyebabkan masalah latensi? Menambahkan tersangka baru ke daftar:

  1. Klien memanggil perpustakaan gRPC
  2. perpustakaan gRPC membuat panggilan jaringan ke perpustakaan di klien gRPC di server
  3. perpustakaan gRPC menghubungi Alvin (tidak ada operasi jika ada server ping-pong)

Untuk memberi gambaran seperti apa kodenya, implementasi klien/Alvin saya tidak jauh berbeda dengan implementasi klien-server contoh asinkron.

Catatan: Daftar di atas sedikit disederhanakan karena gRPC memungkinkan untuk menggunakan model threading (templat?) Anda sendiri, di mana tumpukan eksekusi saling terkait gRPC dan implementasi pengguna. Demi kesederhanaan, kami akan tetap menggunakan model ini.

Pembuatan profil akan memperbaiki segalanya

Setelah mencoret penyimpanan data, saya pikir saya hampir selesai: β€œSekarang mudah! Mari kita terapkan profilnya dan cari tahu di mana penundaan itu terjadi.” SAYA penggemar berat pembuatan profil presisi, karena CPU sangat cepat dan seringkali tidak menjadi hambatan. Kebanyakan penundaan terjadi ketika prosesor harus berhenti memproses untuk melakukan hal lain. Profil CPU Akurat melakukan hal itu: ia mencatat semuanya secara akurat saklar konteks dan memperjelas di mana penundaan terjadi.

Saya mengambil empat profil: dengan QPS tinggi (latensi rendah) dan dengan server ping-pong dengan QPS rendah (latensi tinggi), baik di sisi klien maupun di sisi server. Dan untuk berjaga-jaga, saya juga mengambil contoh profil prosesor. Saat membandingkan profil, saya biasanya mencari tumpukan panggilan yang tidak wajar. Misalnya, sisi buruknya dengan latensi tinggi terdapat lebih banyak peralihan konteks (10 kali atau lebih). Namun dalam kasus saya, jumlah pengalih konteks hampir sama. Yang membuat saya ngeri, tidak ada apa pun yang signifikan di sana.

Debugging Tambahan

Saya putus asa. Saya tidak tahu alat apa lagi yang bisa saya gunakan, dan rencana saya selanjutnya adalah mengulangi eksperimen dengan variasi berbeda daripada mendiagnosis masalahnya dengan jelas.

Bagaimana jika

Sejak awal, saya khawatir tentang latensi spesifik 50 ms. Ini adalah waktu yang sangat besar. Saya memutuskan untuk memotong sebagian kode sampai saya dapat mengetahui dengan tepat bagian mana yang menyebabkan kesalahan ini. Lalu muncullah eksperimen yang berhasil.

Seperti biasa, jika dipikir-pikir, semuanya tampak jelas. Saya menempatkan klien di mesin yang sama dengan Alvin - dan mengirimkan permintaan ke localhost. Dan peningkatan latensi hilang!

Terkadang lebih banyak berarti lebih sedikit. Ketika mengurangi beban menghasilkan peningkatan latensi

Ada yang salah dengan jaringannya.

Mempelajari keterampilan insinyur jaringan

Harus saya akui: pengetahuan saya tentang teknologi jaringan sangat buruk, terutama mengingat saya bekerja dengan mereka setiap hari. Namun jaringanlah yang menjadi tersangka utama, dan saya perlu mempelajari cara men-debugnya.

Untungnya, Internet menyukai mereka yang ingin belajar. Kombinasi ping dan tracert sepertinya merupakan awal yang cukup baik untuk men-debug masalah transportasi jaringan.

Pertama, saya meluncurkannya PsPing ke port TCP Alvin. Saya menggunakan pengaturan default - tidak ada yang istimewa. Dari lebih dari seribu ping, tidak ada yang melebihi 10 ms, kecuali yang pertama untuk pemanasan. Hal ini bertentangan dengan peningkatan latensi yang diamati sebesar 50 mdtk pada persentil ke-99: di sana, untuk setiap 100 permintaan, kita seharusnya melihat sekitar satu permintaan dengan latensi 50 mdtk.

Lalu saya mencoba tracert: Mungkin ada masalah di salah satu node di sepanjang rute antara Alvin dan klien. Namun pelacak itu juga kembali dengan tangan kosong.

Jadi bukan kode saya, penerapan gRPC, atau jaringan yang menyebabkan penundaan. Saya mulai khawatir bahwa saya tidak akan pernah memahami hal ini.

Sekarang kita menggunakan OS apa

gRPC banyak digunakan di Linux, tetapi eksotis di Windows. Saya memutuskan untuk mencoba sebuah eksperimen, dan berhasil: Saya membuat mesin virtual Linux, mengkompilasi Alvin untuk Linux, dan menerapkannya.

Terkadang lebih banyak berarti lebih sedikit. Ketika mengurangi beban menghasilkan peningkatan latensi

Dan inilah yang terjadi: server ping-pong Linux tidak mengalami penundaan yang sama seperti host Windows serupa, meskipun sumber datanya tidak berbeda. Ternyata masalahnya ada pada implementasi gRPC untuk Windows.

Algoritma Nagle

Selama ini saya pikir saya kehilangan sebuah bendera gRPC. Sekarang saya mengerti apa itu sebenarnya gRPC Bendera Windows tidak ada. Saya menemukan perpustakaan RPC internal yang saya yakini akan berfungsi dengan baik untuk semua flag yang disetel winsock. Lalu saya menambahkan semua tanda ini ke gRPC dan menerapkan Alvin di Windows, di server ping-pong Windows yang telah dipatch!

Terkadang lebih banyak berarti lebih sedikit. Ketika mengurangi beban menghasilkan peningkatan latensi

Hampir Selesai: Saya mulai menghapus tanda yang ditambahkan satu per satu hingga regresi kembali sehingga saya dapat menentukan penyebabnya. Itu sangat terkenal TCP_NODELAY, saklar algoritma Nagle.

Algoritma Nagle upaya untuk mengurangi jumlah paket yang dikirim melalui jaringan dengan menunda transmisi pesan hingga ukuran paket melebihi jumlah byte tertentu. Meskipun hal ini mungkin bagus untuk rata-rata pengguna, hal ini merugikan bagi server real-time karena OS akan menunda beberapa pesan, menyebabkan kelambatan pada QPS rendah. kamu gRPC tanda ini disetel dalam implementasi Linux untuk soket TCP, tetapi tidak di Windows. saya adalah ini dikoreksi.

Kesimpulan

Latensi yang lebih tinggi pada QPS rendah disebabkan oleh optimalisasi OS. Kalau dipikir-pikir lagi, pembuatan profil tidak mendeteksi latensi karena dilakukan dalam mode kernel, bukan dalam mode kernel mode pengguna. Saya tidak tahu apakah algoritma Nagle dapat diamati melalui tangkapan ETW, tapi ini akan menarik.

Sedangkan untuk percobaan localhost, mungkin tidak menyentuh kode jaringan sebenarnya dan algoritma Nagle tidak berjalan, sehingga masalah latensi hilang ketika klien menghubungi Alvin melalui localhost.

Saat berikutnya Anda melihat peningkatan latensi seiring menurunnya jumlah permintaan per detik, algoritma Nagle harusnya ada dalam daftar tersangka Anda!

Sumber: www.habr.com

Tambah komentar