6 pelajaran dari pengalaman pengoptimalan kinerja layanan Node.js

Klarna telah melakukan upaya besar untuk membantu pengembang menciptakan layanan berkualitas tinggi dan aman. Salah satu alat yang ditujukan untuk pengembang adalah platform untuk melakukan tes A / B. Komponen terpenting dari sistem ini adalah banyaknya proses yang, untuk setiap permintaan yang masuk, memutuskan jenis tes (A atau B) yang akan dikirimi permintaan. Ini, pada gilirannya, menentukan warna untuk menampilkan tombol, tata letak mana yang akan ditampilkan kepada pengguna, atau bahkan paket pihak ketiga mana yang digunakan. Keputusan ini memiliki dampak langsung pada pengalaman pengguna.



Klarna menggunakan platform Node.js. Artikel, terjemahan yang kami terbitkan hari ini, dikhususkan untuk pelajaran-pelajaran yang berhasil dipelajari oleh para spesialis perusahaan dari pengalaman mengoptimalkan kinerja layanan mereka.

Pelajaran nomor 1: pengujian kinerja dapat memberikan keyakinan bahwa kecepatan sistem tidak menurun pada setiap rilis


Kinerja setiap proses memainkan peran besar, karena proses ini digunakan secara serempak dalam jalur keputusan kritis ekosistem Klarna. Persyaratan kinerja yang biasa untuk tugas-tugas tersebut adalah bahwa untuk 99,9% dari permintaan, keputusan harus dibuat dengan penundaan, waktu yang dinyatakan dalam satu digit. Untuk memastikan bahwa sistem tidak menyimpang dari persyaratan ini, perusahaan mengembangkan konveyor untuk menguji layanan tersebut.

Pelajaran nomor 2: secara mandiri “membongkar” beban, Anda dapat mengidentifikasi masalah bahkan sebelum mereka mencapai produksi


Meskipun kami praktis tidak melihat masalah kinerja selama dua tahun bahwa platform telah digunakan dalam produksi, tes jelas menunjukkan beberapa masalah. Dalam beberapa menit pengujian, pada tingkat penerimaan permintaan yang cukup stabil, durasi pemrosesan permintaan meningkat tajam dari nilai normal menjadi beberapa detik.


Informasi tentang waktu yang diperlukan untuk memproses permintaan. Beberapa jenis masalah terdeteksi

Kami memutuskan, meskipun ini belum terjadi dalam produksi, bahwa itu hanya masalah waktu. Jika beban nyata mencapai tingkat tertentu, kita mungkin mengalami sesuatu yang serupa. Oleh karena itu, diputuskan bahwa masalah ini harus diselidiki.

Pelajaran nomor 3: pengujian stres jangka panjang dapat mengidentifikasi berbagai masalah. Jika semuanya terlihat baik, coba tingkatkan durasi tes.


Hal lain yang patut diperhatikan adalah bahwa masalah sistem kami muncul setelah 2-3 menit bekerja di bawah beban. Awalnya, kami menjalankan tes hanya 2 menit. Dan masalahnya hanya terlihat ketika waktu pelaksanaan tes ditingkatkan menjadi 10 menit.

Pelajaran nomor 4: jangan lupa untuk memperhitungkan waktu yang diperlukan untuk resolusi-DNS nama, mempertimbangkan permintaan keluar. Jangan abaikan masa hidup entri cache - ini serius dapat mengganggu aplikasi


Biasanya kami memantau layanan menggunakan metrik berikut: jumlah permintaan masuk per detik, durasi pemrosesan permintaan masuk, tingkat kesalahan. Ini memberi kita indikator yang cukup bagus tentang keadaan sistem, yang menunjukkan apakah ada masalah di dalamnya.

Tetapi metrik ini tidak memberikan informasi berharga selama kegagalan layanan. Ketika terjadi kesalahan, Anda perlu tahu di mana hambatan sistem. Untuk kasus seperti itu, Anda perlu memantau sumber daya yang digunakan oleh runtime Node.js. Jelas bahwa komposisi indikator, keadaan yang dipantau dalam situasi masalah, termasuk penggunaan prosesor dan memori. Tetapi kadang-kadang kecepatan sistem tidak bergantung pada mereka. Dalam kasus kami, misalnya, tingkat pemanfaatan prosesor rendah. Hal yang sama dapat dikatakan tentang tingkat konsumsi memori.

Sumber daya lain yang menentukan kinerja proyek Node.js adalah loop peristiwa. Seperti halnya penting bagi kita untuk mengetahui tentang berapa banyak memori yang digunakan oleh proses, kita perlu tahu tentang berapa banyak "tugas" yang Anda butuhkan untuk memproses loop peristiwa. Loop acara Node.js diimplementasikan di pustaka C ++ libuv (di sini ada video yang bagus tentang itu). "Tugas" disebut di sini sebagai "Permintaan Aktif". Metrik penting lainnya adalah jumlah "Handles Aktif" yang diwakili oleh deskriptor file terbuka atau soket yang digunakan oleh proses Node.js. Daftar lengkap tipe deskriptor dapat ditemukan di dokumentasi libuv. Akibatnya, jika tes menggunakan 30 koneksi, maka dapat diharapkan bahwa sistem akan memiliki 30 deskriptor aktif. Indikator yang mencirikan jumlah permintaan aktif menunjukkan jumlah operasi yang menunggu dalam antrian untuk deskriptor tertentu. Operasi apa ini? Misalnya, operasi baca / tulis. Daftar lengkapnya dapat ditemukan di sini .

Setelah menganalisis metrik layanan, kami menyadari bahwa ada sesuatu yang salah di sini. Sementara jumlah deskriptor aktif adalah apa yang kami harapkan (dalam tes ini - sekitar 30), jumlah permintaan aktif sangat tinggi - beberapa puluh ribu.


Penjelas Aktif dan Permintaan Aktif

Benar, kami belum tahu jenis permintaan apa yang ada dalam antrian. Setelah kami membagi kueri aktif menjadi beberapa tipe, situasinya sedikit membaik. Yaitu, permintaan UV_GETADDRINFO ternyata sangat nyata. Mereka dihasilkan ketika Node.js mencoba untuk menyelesaikan nama DNS.

Mengapa sistem menghasilkan banyak permintaan resolusi nama DNS? Ternyata klien StatsD kami mencoba untuk menyelesaikan nama host untuk setiap pesan keluar. Perlu dicatat bahwa klien ini menawarkan kemungkinan caching hasil permintaan DNS, tetapi TTL dari catatan DNS yang sesuai tidak diperhitungkan di sini. Hasil di-cache untuk periode waktu yang tidak terbatas. Akibatnya, jika catatan diperbarui setelah klien telah menyelesaikan nama yang sesuai, ia tidak akan pernah mengetahuinya. Karena penyeimbang beban StatsD dapat digunakan kembali dengan alamat IP yang berbeda, dan kami tidak dapat memaksa memulai kembali layanan untuk memperbarui cache DNS, pendekatan ini, yang menggunakan caching untuk waktu yang tidak terbatas, tidak cocok untuk kami.

Solusi yang kami datangi adalah dengan menggunakan sarana eksternal untuk klien untuk caching permintaan DNS. Ini mudah dilakukan dengan menjalankan "tambalan monyet" pada modul DNS. Hasilnya sekarang terlihat jauh lebih baik dari sebelumnya.


Informasi tentang waktu yang diperlukan untuk memproses permintaan. Hasil menggunakan cache DNS eksternal

Pelajaran # 5: Lakukan operasi I / O dalam mode batch. Operasi semacam itu, bahkan tidak sinkron, adalah konsumen sumber daya yang serius.


Setelah menyelesaikan masalah di atas, kami menyalakan beberapa fitur layanan yang dinonaktifkan sebelumnya, dan mengujinya lagi. Secara khusus, kami telah memasukkan kode yang mengirim pesan ke topik Kafka untuk setiap permintaan yang masuk. Tes, sekali lagi, mengungkapkan puncak yang signifikan dalam hasil pengukuran waktu respons (kita berbicara tentang detik), diamati selama interval waktu yang besar.


Informasi tentang waktu yang diperlukan untuk memproses permintaan. Tes ini mengungkapkan peningkatan tajam dalam waktu yang diperlukan untuk pembentukan jawaban

Hasil ini menunjukkan masalah yang jelas tepatnya pada fungsi yang kami sertakan sebelum pengujian. Secara khusus, kita dihadapkan dengan kenyataan bahwa mengirim pesan ke Kafka membutuhkan terlalu banyak waktu.


Informasi tentang waktu yang diperlukan untuk menghasilkan pesan untuk Kafka

Kami memutuskan untuk menggunakan peningkatan paling sederhana di sini - untuk menempatkan pesan keluar dalam antrian dalam memori, dan untuk mentransfer pesan-pesan ini setiap detik dalam mode batch. Dengan menjalankan tes lagi, kami menemukan peningkatan yang jelas dalam waktu yang diperlukan untuk layanan untuk membentuk respons.


Informasi tentang waktu yang diperlukan untuk memproses permintaan. Perbaikan setelah mengatur pemrosesan pesan batch

Pelajaran nomor 6: sebelum Anda mencoba melakukan perbaikan pada sistem, siapkan tes, yang hasilnya dapat dipercaya


Pekerjaan yang dijelaskan di atas untuk mengoptimalkan kinerja suatu layanan tidak akan mungkin terjadi tanpa mekanisme peluncuran uji, yang memungkinkan hasil yang dapat direproduksi dan seragam. Versi pertama dari sistem pengujian kami tidak memberikan hasil yang seragam, jadi kami tidak dapat mengandalkannya dalam membuat keputusan penting. Setelah berinvestasi dalam menciptakan sistem pengujian yang andal, kami dapat menguji proyek dalam mode yang berbeda, bereksperimen dengan koreksi. Sistem pengujian baru, sebagian besar, memberi kami keyakinan bahwa hasil tes yang diperoleh adalah sesuatu yang nyata, dan bukan angka yang datang entah dari mana.

Katakanlah beberapa kata tentang alat khusus yang digunakan untuk mengatur pengujian.

Beban dihasilkan oleh alat internal yang membuatnya mudah untuk menjalankan Locust dalam mode terdistribusi. Secara umum, semuanya bermuara pada eksekusi satu perintah, setelah itu generator beban diluncurkan, skrip uji ditransfer kepada mereka dan hasilnya divisualisasikan oleh panel kontrol Grafana dikumpulkan. Hasil yang sesuai disajikan dalam materi pada grafik dengan latar belakang gelap. Ini adalah bagaimana sistem terlihat dalam pengujian dari sudut pandang klien.

Layanan yang sedang diuji memberikan informasi pengukuran dalam Datalog. Informasi ini disajikan di sini dengan grafik dengan latar belakang yang cerah.

Pembaca yang budiman! Sistem pengujian layanan Node.js apa yang Anda gunakan?

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


All Articles