Berbagai Metode Debugging di OpenResty

API7.ai

December 16, 2022

OpenResty (NGINX + Lua)

Di grup komunikasi OpenResty, para pengembang sering menanyakan pertanyaan ini: Bagaimana cara melakukan debug di OpenResty? Sejauh yang saya tahu, ada beberapa alat di OpenResty yang mendukung debug dengan breakpoint, termasuk plugin di VSCode, tetapi sejauh ini belum banyak digunakan. Termasuk penulis agentzh dan beberapa kontributor yang saya kenal, semua orang menggunakan cara paling sederhana yaitu ngx.log dan ngx.say untuk melakukan debug.

Ini tidak ramah bagi kebanyakan pemula. Apakah ini berarti bahwa banyak core maintainer OpenResty hanya memiliki metode primitif mencetak log ketika mereka menghadapi masalah yang sulit?

Tentu saja tidak. Di dunia OpenResty, SystemTap dan flame graph adalah alat standar untuk menangani masalah sulit dan masalah performa. Jika Anda memiliki pertanyaan tentang ini di milis atau issue, maintainer proyek akan meminta Anda untuk mengunggah flame graph dan meminta deskripsi grafis daripada deskripsi tekstual.

Dalam dua artikel berikutnya, saya akan berbicara dengan Anda tentang debugging, dan perangkat yang dibuat OpenResty khusus untuk debugging. Hari ini kita akan mulai dengan melihat apa yang tersedia untuk debugging program.

Breakpoint dan Mencetak Log

Untuk waktu yang lama dalam pekerjaan saya, saya mengandalkan fitur debug canggih IDE (lingkungan pengembangan terintegrasi) untuk melacak program, yang terasa alami. Untuk masalah yang dapat direproduksi di lingkungan pengujian, tidak peduli seberapa kompleks, saya yakin bisa menemukan akar masalahnya. Alasannya adalah bug dapat direproduksi berulang kali, penyebabnya dapat ditemukan dengan menetapkan breakpoint dan mencetak log. Yang Anda butuhkan hanyalah kesabaran.

Dari sudut pandang ini, menyelesaikan bug yang muncul secara stabil di lingkungan pengujian adalah pekerjaan fisik. Sebagian besar bug yang saya selesaikan dalam pekerjaan saya termasuk dalam kategori ini.

Namun, perhatikan bahwa ada dua prasyarat: lingkungan pengujian dan reproduksi yang stabil. Kenyataannya selalu kurang ideal. Jika bug hanya muncul di lingkungan produksi, apakah ada cara untuk melakukan debug?

Di sini saya merekomendasikan alat - Mozilla RR. Anda dapat menganggapnya sebagai perekam, merekam perilaku program, dan kemudian memutarnya berulang kali. Sejujurnya, terlepas dari lingkungan produksi atau pengujian, selama Anda dapat merekam "bukti" bug, itu dapat digunakan sebagai "bukti di pengadilan" untuk dianalisis perlahan.

Algoritma Pencarian Biner dan Komentar

Namun, untuk beberapa proyek besar, misalnya, bug mungkin berasal dari salah satu dari beberapa layanan, atau mungkin ada masalah dengan pernyataan SQL yang mengquery database, dalam hal ini, bahkan jika bug dapat direproduksi secara stabil, Anda tidak dapat memastikan bagian mana dari bug tersebut terjadi. Jadi, alat perekam seperti Mozilla RR gagal.

Pada titik ini, Anda mungkin mengingat "algoritma pencarian biner" klasik. Pertama, kita mengomentari setengah dari logika dalam kode, dan jika masalah tetap ada, bug ada di kode yang tidak dikomentari, jadi kita mengomentari setengah logika yang tersisa dan melanjutkan loop. Dalam beberapa kali, masalah akan dipersempit ke ukuran yang sepenuhnya dapat dikelola.

Pendekatan ini mungkin terdengar agak bodoh, tetapi efisien dalam banyak skenario. Tentu saja, seiring kemajuan teknologi dan peningkatan kompleksitas sistem, kami merekomendasikan menggunakan standar seperti OpenTracing untuk pelacakan terdistribusi.

OpenTracing dapat ditanam di berbagai bagian sistem dan melaporkan rantai panggilan dan pelacakan peristiwa yang terdiri dari beberapa Span ke server melalui Trace ID untuk analisis dan presentasi grafis. Ini dapat membantu pengembang menemukan banyak masalah tersembunyi, dan data historis akan disimpan sehingga kita dapat membandingkan dan melihatnya kapan saja.

Juga, jika sistem Anda lebih kompleks, seperti dalam lingkungan microservices, maka Zipkin, Apache SkyWalking adalah pilihan yang baik.

Debugging Dinamis

Metode debugging yang telah saya jelaskan di atas cukup untuk menyelesaikan sebagian besar masalah. Namun, jika Anda mengalami kesalahan yang hanya terjadi sesekali di produksi, akan membutuhkan waktu yang cukup lama untuk melacaknya dengan menambahkan log dan pelacakan peristiwa.

Bertahun-tahun yang lalu, saya bertanggung jawab atas sistem yang kehabisan sumber daya database sekitar pukul 1:00 pagi setiap hari dan menyebabkan seluruh sistem mengalami avalanche. Saat itu, kami memeriksa tugas terjadwal dalam kode di siang hari, dan pada malam hari, tim menunggu bug direproduksi di perusahaan, dan kemudian memeriksa status berjalan submodul saat direproduksi. Kami tidak menemukan penyebab bug sampai malam ketiga.

Pengalaman saya mirip dengan latar belakang beberapa insinyur sistem Solaris yang menciptakan Dtrace. Saat itu, insinyur Solaris juga menghabiskan hari dan malam untuk memecahkan masalah produksi yang aneh, hanya untuk mengetahui bahwa itu karena konfigurasi yang salah ditulis. Tetapi tidak seperti saya, insinyur Solaris memutuskan untuk menghindari masalah ini sama sekali dan menciptakan Dtrace, khusus untuk debugging dinamis.

Tidak seperti alat debugging statis seperti GDB, debugging dinamis dapat melakukan debug layanan online. Seluruh proses debugging tidak sensitif dan tidak mengganggu untuk program yang di-debug, tanpa memodifikasi kode, apalagi me-restart. Sebagai analogi, debugging dinamis seperti sinar-X, yang dapat memeriksa tubuh pasien tanpa perlu pengambilan sampel darah dan gastroskopi.

Dtrace adalah salah satu framework pelacakan dinamis pertama, dan pengaruhnya telah menyebabkan munculnya alat debugging dinamis serupa di sistem lain. Misalnya, insinyur di Red Hat menciptakan Systemtap di Linux, yang akan saya bahas selanjutnya.

Systemtap

Systemtap memiliki DSL-nya sendiri, yang dapat digunakan untuk mengatur titik probe. Sebelum kita masuk ke detail lebih lanjut, mari kita instal Systemtap untuk melampaui abstrak. Di sini, cukup gunakan manajer paket sistem untuk menginstal.

sudo apt install systemtap

Mari kita lihat seperti apa program hello world yang ditulis dalam Systemtap:

# cat hello-world.stp probe begin { print("hello world!") exit() }

Tidak terlihat mudah? Anda perlu menggunakan hak sudo untuk menjalankannya.

sudo stap hello-world.stp

Ini akan mencetak hello world!. Dalam kebanyakan skenario, kita tidak perlu menulis skrip stap kita sendiri untuk melakukan analisis, karena OpenResty sudah memiliki banyak skrip stap siap pakai untuk melakukan analisis rutin, dan saya akan memperkenalkannya kepada Anda di artikel berikutnya. Jadi, hari ini kita perlu memiliki pemahaman singkat tentang skrip stap.

Setelah beberapa praktik, kembali ke konsep kita, Systemtap bekerja dengan mengubah skrip stap di atas ke C dan menjalankan kompiler C sistem untuk membuat modul kernel. Ketika modul dimuat, itu mengaktifkan semua peristiwa probe dengan mengaitkan kernel.

Misalnya, begin akan berjalan di awal probe, dan end yang sesuai, sehingga program hello world di atas juga dapat ditulis dengan cara berikut:

probe begin { print("hello ") exit() } probe end { print("world!")

Di sini, saya hanya memberikan pengenalan yang sangat singkat tentang Systemtap. Frank Ch. Eigler, penulis Systemtap, menulis buku elektronik Systemtap tutorial yang memperkenalkan Systemtap secara detail. Jika Anda ingin mempelajari lebih lanjut dan memahami Systemtap secara mendalam, saya sarankan memulai dengan buku ini sebagai jalur pembelajaran terbaik.

Framework Pelacakan Dinamis Lainnya

Systemtap tidak cukup untuk insinyur analisis kernel dan performa.

  1. Systemtap tidak masuk ke kernel sistem secara default.
  2. Cara kerjanya lambat untuk boot dan mungkin berdampak pada operasi normal sistem.

eBPF (extended BPF) adalah fitur baru yang ditambahkan ke kernel Linux dalam beberapa tahun terakhir. Dibandingkan dengan Systemtap, eBPF memiliki keunggulan dukungan kernel langsung, tidak ada crash, dan boot cepat. Pada saat yang sama, ia tidak menggunakan DSL, tetapi sintaks C langsung, sehingga jauh lebih mudah untuk memulai.

Selain solusi open-source, VTune dari Intel juga merupakan salah satu alat terbaik. Operasi antarmuka yang intuitif dan presentasi data memungkinkan Anda menganalisis bottleneck performa tanpa menulis kode.

Flame Graph

Akhirnya, mari kita mengingat flame graph yang disebutkan di artikel sebelumnya. Seperti yang kami sebutkan sebelumnya, data yang dihasilkan oleh alat seperti perf dan Systemtap dapat ditampilkan lebih visual menggunakan flame graph. Diagram berikut adalah contoh flame graph.

flame graph

Dalam flame graph, warna dan kegelapan blok warna tidak memiliki arti, hanya untuk membuat perbedaan sederhana antara blok warna yang berbeda. Flame graph adalah superposisi data yang diambil setiap kali, sehingga data pengguna adalah lebar dan panjang blok.

Untuk flame graph pada CPU, lebar blok warna adalah persentase waktu CPU yang ditempati oleh fungsi: semakin lebar blok, semakin besar drain performa. Jika ada puncak yang rata, di situlah bottleneck performa berada. Panjang blok warna, di sisi lain, mewakili kedalaman panggilan fungsi, dengan kotak di atas menunjukkan fungsi yang sedang berjalan dan semua yang di bawahnya adalah pemanggil fungsi tersebut. Jadi, fungsi di bawah adalah supertipe dari fungsi di atas: semakin tinggi puncaknya, semakin dalam fungsi dipanggil.

Ringkasan

Penting untuk diketahui bahwa bahkan teknik non-intrusif seperti pelacakan dinamis tidak sempurna. Ini hanya dapat mendeteksi proses individu tertentu; secara umum, kita hanya menyalakannya sebentar untuk menggunakan data yang diambil selama waktu itu. Jadi jika Anda perlu mendeteksi di beberapa layanan atau untuk waktu yang lama, Anda masih membutuhkan teknik pelacakan terdistribusi seperti opentracing.

Alat dan teknik debugging apa yang Anda gunakan dalam pekerjaan rutin Anda? Silakan tinggalkan komentar dan diskusikan dengan saya, juga silakan bagikan artikel ini dengan teman-teman Anda, sehingga kita dapat belajar dan berkembang bersama.