File Swap yang Hilang dan Membekukan Server Kami
Pada 24 September, salah satu server produksi kami berhenti merespons. Load balancer menandainya tidak sehat dan tool perintah jarak jauh kami tidak bisa menjangkaunya, tetapi tidak ada yang crash dan tidak ada proses yang dibunuh karena memakai memori terlalu banyak. Server itu sedang thrashing: tanpa ruang swap dan dengan container yang diizinkan memakai lebih banyak memori daripada yang dimiliki mesin, Linux menghabiskan waktunya untuk mengusir dan membaca ulang file yang dibutuhkan untuk berjalan, dan hampir tidak membuat kemajuan. Menambahkan file swap 2 GB di setiap server memperbaikinya. Pelajaran yang lebih menarik menyangkut health check.
Seperti apa “macet” itu
- Health check load balancer habis waktu pada server tersebut.
- Perintah yang dikirim lewat AWS Systems Manager tertahan di “Pending” dan tidak pernah berjalan.
- Tidak ada pembunuhan karena kehabisan memori di log. Tidak ada proses yang mati.
Seminggu sebelumnya kami telah memindahkan produksi ke server ARM yang lebih kecil dengan RAM 2 GB masing-masing. Server staging kami, yang bahkan lebih kecil, pernah membeku dengan cara yang sama saat mengekstrak image container selama deploy.
Mengapa tidak ada error memori?
Linux hanya membunuh proses ketika benar-benar kehabisan memori yang bisa direklamasi. Sebelum titik itu, ia mengambil memori dari page cache, yaitu salinan file yang disimpan di RAM, termasuk kode dari setiap program yang sedang berjalan.
Di server kami, gabungan batas memori container mencapai sekitar 3,3 GB pada mesin dengan sekitar 1,8 GB yang bisa dipakai. Biasanya mereka tidak semua memakai batasnya sekaligus. Saat mereka melakukannya, kernel terus mengusir kode program dari cache untuk memberi ruang, lalu harus membacanya kembali dari disk begitu kode itu berjalan lagi. Siklus itu, thrashing, bisa membuat mesin hampir sepenuhnya tidak responsif tanpa pernah benar-benar kehabisan memori. Jadi tidak ada yang dibunuh, dan tidak ada yang pulih.
Tanpa swap, kernel tidak punya tempat untuk menaruh memori yang dialokasikan tetapi jarang dipakai, sehingga ia harus mengambilnya dari cache.
Perbaikannya
Skrip bootstrap server sekarang membuat file swap 2 GB dengan swappiness rendah (10) setiap kali server boot atau diperbaiki. Swappiness rendah berarti kernel tetap lebih suka menyimpan memori kerja di RAM, tetapi halaman yang jarang disentuh bisa dipindahkan ke disk alih-alih memaksa kode program keluar dari cache. Kami menerapkannya langsung pada kedua server produksi dan staging, dan pipeline deploy menerbitkan ulang skrip bootstrap pada setiap deploy produksi sehingga server yang diganti juga mendapatkannya.
Bagian yang lebih mengkhawatirkan kami: server yang tidak sehat tetap ada
Grup server kami memakai health check EC2, yaitu “apakah mesinnya berjalan?”, bukan health check load balancer, yaitu “apakah ia menjawab permintaan?”. Jadi server yang sudah ditinggalkan load balancer tetap dianggap sehat oleh grup. Server itu tidak akan pernah diganti. Produksi akan diam-diam berjalan di satu server sampai seseorang menyadarinya dan me-reboot yang lain.
Mengganti grup ke health check load balancer terdengar seperti perbaikan yang jelas, tetapi bagi kami tidak sesederhana itu: selama deploy, server sengaja menjawab endpoint health-nya dengan error agar balancer mengeluarkannya dari rotasi (lihat bagaimana kami membuat deploy tanpa 502). Grup yang mengganti server berdasarkan sinyal itu akan menggantinya di tengah setiap deploy.
Jadi untuk sekarang kami menambahkan satu langkah ke checklist deploy kami: setelah setiap deploy, periksa kesehatan setiap target di load balancer, bukan hanya apakah job deploy lulus. Jika perintah ke sebuah server tertahan di “Pending”, server itu sedang thrashing: reboot, ia sudah keluar dari rotasi.
Yang kami ambil dari ini
- “Tidak crash” bukan berarti “sehat”. Thrashing tidak menghasilkan error, hanya perlambatan yang begitu ekstrem sampai mesin berhenti menjawab.
- Server kecil membutuhkan swap. Bahkan sedikit, dengan swappiness rendah, memberi kernel tempat untuk menaruh memori dingin.
- Batas memori yang jumlahnya melebihi mesin adalah sebuah taruhan. Kadang Anda kalah. Ketahui kapan Anda sudah bertaruh.
- Ketahui health check mana yang dipercaya autoscaling Anda. Health check yang hanya bertanya “apakah VM-nya menyala?” tidak akan mengganti server yang sudah berhenti bekerja.