Masalah memory leak di Copilot
(stevenharman.net)Rangkuman proses penyelesaian memory leak terkait ActiveSupport::Notifications
-
Situasi saat memory leak terjadi
- Sejak titik tertentu, penggunaan memori pada Dyno
webmulai meningkat secara tidak normal - Pager mulai berbunyi, dan muncul situasi yang tampak seperti memory leak
- Sejak titik tertentu, penggunaan memori pada Dyno
-
Respons segera
- Di Heroku, jika dicurigai ada memory leak, solusi sementara yang bisa dilakukan adalah me-restart Dyno
- Me-restart sesuai siklus deploy normal atau me-restart secara manual Dyno yang mendekati batas memori
-
Meninjau kode yang dicurigai untuk mengidentifikasi penyebab
- Meninjau perubahan kode yang dirilis tepat sebelum memory spike
- Men-deploy beberapa potong kode yang dicurigai satu per satu untuk memeriksa apakah memory leak terjadi
- Karena tidak ada kode yang tampak sebagai penyebab, perubahan tooling juga dibatalkan deploy-nya untuk diperiksa. Namun memory leak tetap berlanjut
-
Analisis pola peningkatan memori
- Leak hanya terjadi pada Dyno
web. Dyno Sidekiq dan Delayed::Job normal - Tidak semua Dyno
webselalu mengalami leak. Setelah beberapa jam penggunaan normal, satu-dua atau semua Dyno mulai leak - Diduga dipicu oleh traffic tertentu, bukan oleh besarnya jumlah traffic
- Leak tidak terjadi di semua Puma worker dalam Dyno, melainkan hanya sebagian kecil worker yang menggunakan sebagian besar total memori
- Leak hanya terjadi pada Dyno
-
Pengumpulan dan analisis heap dump
- Mengumpulkan heap dump dari Ruby process yang sedang leak menggunakan
rbtrace- SSH ke dyno yang sedang leak dengan
heroku ps:exec - Memilih Ruby worker process yang menggunakan memori paling besar dengan perintah
ps - Attach ke pid tersebut dengan
rbtracelalu mulai melacak alokasi memori (ObjectSpace.trace_object_allocations_start) - Mengumpulkan heap dump dengan
ObjectSpace.dump_all. Jika ukurannya besar, kompres dengan gzip - Mengambil file dump ke lokal dengan
heroku ps:copy
- SSH ke dyno yang sedang leak dengan
- Memvisualisasikan heap dump sebagai flamegraph menggunakan
reap- Ditemukan sebuah Thread yang mereferensikan memori sebesar 1.9GB dan sebuah Array di bawahnya yang mereferensikan 32.067 objek
- Menelusuri objek yang mencurigakan menggunakan
sheap- Thread tersebut ternyata adalah worker thread milik Puma
- Objek
ActiveSupport::SubscriberQueueRegistrymereferensikanHash, dan di bawahnya terdapat objekStringdanArray - Di dalam
Arraybermasalah tersebut menumpuk lebih dari 32.000 objekActiveSupport::Notifications::Event
- Mengumpulkan heap dump dari Ruby process yang sedang leak menggunakan
-
Inferensi penyebab
- Diduga objek
EventdariActiveSupport::Notificationstertumpuk secara keliru di array#children - Diperkirakan jika terjadi error di dalam block
ActiveSupport::Notifications.instrument,Eventtersebut tidak dihapus dari#childrendan tetap tertinggal sehingga menyebabkan memory leak
- Diduga objek
-
Reproduksi secara lokal
- Mengirim request secara lokal dengan request path dan parameter mencurigakan yang ditemukan di production
- Memastikan muncul
500 Internal Server ErrordisertaiURI::InvalidURIError - Memastikan penggunaan memori pada dyno production yang menerima request tersebut meningkat tajam
-
Analisis penyebab yang lebih spesifik
- Ada bug terkait
Event#childrendiActiveSupport::Notificationsyang telah diperbaiki di Rails 7.1 - Di saat yang sama, ada bug pada gem Bugsnag yang me-raise
URI::InvalidURIErrorsaat melakukanURI.parsedalam proses membersihkan request URL, dan kombinasi keduanya menyebabkan memory leak - Karena error yang di-raise di dalam block
ActiveSupport::Notifications.subscribetidak tertangani,Eventtersebut tidak dihapus dari array#childrendan terus menumpuk, menyebabkan memory leak
- Ada bug terkait
-
Solusi
- Jangka pendek: upgrade versi gem Bugsnag agar tidak me-raise error meskipun terjadi
URI::InvalidURIError - Jangka panjang: upgrade ke Rails 7.x tempat bug
ActiveSupport::Notificationssudah diperbaiki
- Jangka pendek: upgrade versi gem Bugsnag agar tidak me-raise error meskipun terjadi
Opini GN⁺
- Proses menemukan masalah lalu mengidentifikasi penyebabnya secara sistematis sangat mengesankan. Tulisan ini merangkum dengan baik proses analisis dasar yang layak dicoba saat mencurigai adanya memory leak
- Berbagai alat open source untuk pengumpulan, visualisasi, dan analisis heap dump Ruby (
rbtrace,reap,sheap, dll.) tampak dikembangkan dengan aktif. Bahkan jika bukan Ruby, penting untuk memahami alat analisis memori yang berguna di tiap bahasa dan mampu menerapkannya pada masalah nyata - Sering kali penyebab memory leak memang berupa bug pada library atau framework yang digunakan, tetapi biasanya tidak ada kondisi untuk menganalisis, memperbaiki, lalu merilis bug tersebut secara langsung. Karena itu, yang penting adalah secepat mungkin menerapkan cara untuk menghindarinya. Menyertakan alternatif yang memungkinkan bersama bug report juga merupakan pendekatan yang baik
- Bukan hanya berhenti pada perbaikan memory leak, artikel ini juga bagus karena menggali root cause masalah secara mendalam. Sikap analitis untuk menelusuri hingga ke penyebab mendasar dengan mencermati kode internal framework tampak penting bagi developer
- Pada akhirnya, penyebab memory leak ternyata berasal dari upgrade versi library kecil yang awalnya tampak sama sekali tidak terkait. Ini menunjukkan pentingnya pengelolaan dependensi dan pelacakan perubahan. Bahkan untuk perubahan kecil, dampaknya perlu dianalisis dengan hati-hati dan tetap dimonitor setelah deploy
1 komentar
Opini Hacker News
Bisa diatasi lewat pelatihan engineering tanpa rasa takut pada manajemen memori manual
Kasus kerugian 5 juta dolar akibat memory leak
Alat debugging memory leak dan cara mengatasinya
Pujian terhadap gaya penulisan