Node, sebagai runtime Javascript di sisi server, sangat memperkaya skenario aplikasi Javascript.
Namun, Node.js Runtime sendiri adalah kotak hitam. Kami tidak dapat melihat status runtime, dan sulit untuk mereproduksi masalah online.
Oleh karena itu, pemantauan kinerja adalah landasan dari "operasi normal" aplikasi Node.js. Berbagai indikator runtime tidak hanya dapat dipantau kapan saja, namun juga dapat membantu memecahkan masalah skenario abnormal.
Pemantauan kinerjadapat dibagi menjadi dua bagian:
pengumpulan dan tampilan indikator kinerja
menangkap dan menganalisis data kinerja
seperti QPS, HTTP lambat, log tautan pemrosesan bisnis, dll.Dari gambar di atas, Anda dapat melihat kelebihan dan kekurangan dari tiga solusi pemantauan kinerja Node.js mainstream saat ini. Berikut ini adalah pengenalan singkat tentang komposisi ketiga solusi tersebut:
Prometheus
AliNode loop tertutup.
Alinode adalah runtime diperpanjang yang kompatibel dengan nodejs resmi, menyediakan Beberapa fungsi tambahan:
Agenthub adalah proses tetap yang digunakan untuk mengumpulkan indikator kinerja
tampilan
,
, dan analisis. Aksesnya mudah dan sederhana, tetapi masih ada risiko saat memperluas runtime
Node.js Addon
untuk mengimplementasikanData konsumsi waktu CPU dari proses saat ini dapat diperoleh melalui process.cpuUsage()
Satuan nilai yang dikembalikan adalah mikrodetik
Data alokasi memori dari proses saat ini dapat diperoleh melalui process.memoryUsage()
. Unit nilai yang dikembalikan adalah byte
Seperti dapat dilihat dari gambar di atas, rss
mencakup segmen kode ( Code Segment
), memori tumpukan ( Stack
), dan memori heap ( Heap
).
dapat memperoleh data analisis memori heap v8 dan ruang heap melalui v8.getHeapStatistics()
dan v8.getHeapSpaceStatistics()
Gambar berikut menunjukkan distribusi komposisi memori heap v8:
Ruang memori heap pertama-tama dibagi menjadi beberapa spasi, dan ruang tersebut dibagi menjadi beberapa halaman.
Ruang Baru: Ruang generasi baru, digunakan untuk menyimpan beberapa data objek dengan siklus hidup yang relatif pendek, dibagi menjadi dua ruang (tipe ruang adalah semi space
): from space
, to space
Ruang Lama : ruang generasi lama, digunakan untuk menyimpan objek yang dipromosikan oleh New Space
Code Space: menyimpan kode yang dapat dieksekusi yang dikompilasi oleh v8 JIT.
Map Space: menyimpan objek penunjuk dari kelas tersembunyi yang ditunjuk oleh Object Penunjuk kelas tersembunyi dicatat oleh v8 menurut runtime. Struktur tata letak objek digunakan untuk mengakses anggota objek dengan cepat.
Ruang Objek Besar: digunakan untuk menyimpan objek yang lebih besar dari 1MB yang tidak dapat dialokasikan ke halaman.
Algoritma pengumpulan sampah
Mark-Sweep-Compact
. Minor GC untuk daur ulang objek di generasi lamaScavenge
digunakan untuk mendaur ulang objek di generasi baruPremis: New space
dibagi menjadi dua ruang objek: from
dan to
Waktu pemicu: ketika New space
sudah penuh.
Langkah-langkah:
Di from space
, lakukan penjelajahan luasnya terlebih dahulu
dan temukan bahwa objek yang bertahan (dapat dijangkau)
Old space
danto space
Saat penyalinan berakhir, hanya ada objek yang bertahan di to space
, from space
dikosongkan,
ditukar from space
dan to space
, dan memulai putaran berikutnya Scavenge
cocok untuk daur ulang yang sering dan memori yang tidak mencukupi. Untuk objek berukuran besar, strategi ruang-untuk-waktu yang umum memiliki kelemahan yaitu membuang ruang dua kali lebih banyak dibandingkan
Tiga langkah: menandai, membersihkan, dan mengatur
Waktu pemicu: ketika Old space
penuh
Langkah:
Menandai (metode penandaan tiga warna)
marking queue
(tumpukan eksplisit), dan tandai objek ini sebagai abu-abu.pop
objek dari marking queue
dan tandai dengan warna hitam.push
ke dalam marking queue
Sapu
.
Old space
, sehingga ruang kosong terus menerus dan lengkap.Ketika v8 pertama kali melakukan pengumpulan sampah, ia perlu menghentikan program, memindai seluruh heap, dan mendapatkan kembali memori sebelum menjalankan kembali program. Perilaku ini disebut jeda penuh ( Stop-The-World
).
Meskipun objek aktif pada generasi baru berukuran kecil dan sering didaur ulang, titik penuh memiliki dampak yang kecil. Namun, objek yang bertahan pada generasi lama berjumlah banyak dan berukuran besar. dan jeda yang disebabkan oleh penandaan, pembersihan, dan penyortiran, dll. Ini akan menjadi lebih serius.
Konsep ini sebenarnya mirip dengan arsitektur Fiber dalam kerangka React. Hanya selama waktu luang browser ia akan melintasi Fiber Tree untuk melakukan tugas-tugas terkait. Jika tidak, eksekusi akan tertunda, sehingga mempengaruhi tugas-tugas thread utama sesedikit mungkin , menghindari kelambatan aplikasi, dan meningkatkan kinerja Aplikasi.
Karena v8 memiliki batas default pada ruang generasi baru dan lama.
New space
: 32M untuk sistem 64-bit dan 16M untuk sistem 32-Old space
700M untuk sistem 32-bit.Oleh karena itu, node
Dua parameter disediakan untuk menyesuaikan batas ruang atas generasi baru dan lama
--max-semi-space-size
: Tetapkan nilai maksimum ruang New Space
--max-old-space-size
: Menetapkan nilai maksimum dari Old Space
spacenode
menyediakan tiga cara untuk melihat log GC:
--trace_gc
: Sebaris log menjelaskan secara singkat waktu, jenis, perubahan ukuran heap dan penyebab setiap GC--trace_gc_verbose
: Menampilkan setiap heap V8 setelah setiap GC Status detail ruang--trace_gc_nvp
: Informasi detail pasangan nilai kunci dari setiap GC, termasuk jenis GC, waktu jeda, perubahan memori, dll.Karena log GC relatif primitif dan memerlukan
pemrosesan sekunder, Anda dapat menggunakan v8-gc- yang dikembangkan oleh tim AliNode.pengurai log
mengambil snapshot dari memori heap dari program yang sedang berjalan dan dapat digunakan untuk menganalisis konsumsi memori dan mengubah
.heapsnapshot
Heapsnapshot dihasilkan dengan cara berikut:
menggunakan heapdump
Menggunakan profil heap v8
v8.getHeapSnapshot()
yang disediakan oleh modul nodejs v8 bawaan
v8.writeHeapSnapshot(fileName)
Menggunakan v8-profiler-berikutnya
.heapsnapshot
diunggah ke Memori pada toolbar Chrome devtools, dan hasilnya akan ditampilkan seperti gambar di bawah ini:
Tampilan defaultnya adalah tampilan Summary
. Di sini kita perlu memperhatikan dua kolom paling kanan: Shallow Size
dan Retained Size
Retained Size
Shallow Size
ukuran objek itu sendiri yang dialokasikan dalam memori heap v8Shallow Size
dari semua objek yang direferensikanketika ditemukan bahwa Retained Size
sangat besar, mungkin ada kebocoran memori di dalam objek. Anda dapat memperluas lebih jauh untuk menemukan
Comparison
menganalisis cuplikan heap dari dua periode berbeda. Kolom Delta
dapat digunakan untuk memfilter objek dengan perubahan memori terbesar.
melakukan pengambilan sampel snapshot dari CPU yang menjalankan program, yang dapat digunakan untuk menganalisis waktu dan proporsi CPU.
Ada beberapa cara untuk menghasilkan file .cpuprofile
:
Ini adalah kumpulan sampel Profil CPU 5 menit
File .cpuprofile
yang dihasilkan Javascript Profiler
Tampilan defaultnya adalah tampilan Heavy
. Di sini kita melihat dua kolom: Self Time
dan Total Time
Total Time
eksekusi fungsi iniSelf Time
(tidak termasuk panggilan lainnya).mungkin
Total Time
Self Time
intensif CPU yang memakan banyak waktu. Anda juga dapat melakukan pemecahan masalah lebih lanjut.
sistem akan secara otomatis mencatatnya. Proses ini menghentikan informasi alokasi memori, Penghitung Program dan penunjuk tumpukan serta informasi penting lainnya pada saat itu untuk menghasilkan
. Tiga metode untuk menghasilkan file .core
:
ulimit -c unlimited
membuka batas kernelnode --abort-on-uncaught-exception
Menambahkan parameter ini saat memulai node dapat menghasilkan file inti ketika terjadi pengecualian yang tidak tertangkap dalam aplikasi.gcore <pid>
MenghasilkanSetelah mendapatkan file .core
, analisis dan diagnosis dapat dicapai melalui alat seperti mdb, gdb, lldb, dll. Penyebab sebenarnya dari proses crash
llnode `which node` -c /path/to/core/dump
Dari pemantauan terlihat bahwa memori heap terus bertambah, sehingga snapshot heap diperlukan untuk pemecahan masalah
Berdasarkan heapsnapshot
kita dapat menganalisis dan menemukan bahwa ada objek newThing
yang selalu memiliki memori yang relatif besar
theThing
newThing
unused
kasus replaceThing
yang disebabkan oleh penutupan.
Kebocoran memori yang umum mencakup situasi berikut:
Oleh karena itu, dalam situasi di atas, Anda harus mempertimbangkan dengan cermat apakah objek dalam memori akan didaur ulang secara otomatis tidak dapat didaur ulang secara otomatis, Anda perlu melakukan daur ulang secara manual, seperti menyetel objek secara manual ke null
, menghapus pengatur waktu, melepas pengikatan peristiwa, dll.
Artikel ini telah memberikan pengenalan mendetail tentang keseluruhan sistem pemantauan kinerja
Pertama, bab ini memperkenalkan permasalahan yang diselesaikan melalui pemantauan kinerja, komponen-komponennya, dan perbandingan kelebihan dan kekurangan solusi umum.
Kemudian, dua bagian utama dari indikator kinerja dan alat snapshot diperkenalkan secara rinci.
Terakhir, kasus kebocoran memori sederhana direproduksi dari observasi, analisis, dan pemecahan masalah, serta situasi dan solusi kebocoran memori yang umum dirangkum.
Saya harap artikel ini dapat membantu semua orang memahami keseluruhan sistem pemantauan kinerja Node.js.