Bagaimana cara cepat menarik semua memori proses yang ditukar keluar dari swap tanpa menulis ke disk?
Konteks masalah ini sepele, karena masalah sistemik yang memerlukan pertanyaan sedang ditangani oleh pihak lain. Namun, saat ini, saya memiliki masalah di mana saya sering harus membebaskan ruang swap pada simpul OpenVZ sementara memuat dan IO menunggu sangat tinggi.
Swap ini sering dikonsumsi terutama oleh segelintir proses MySQL dan clamd yang berjalan pada kontainer individual. Restart layanan ini membebaskan swap dan menyelesaikan masalah pada node, tetapi tidak diinginkan karena alasan yang jelas.
Saya mencari cara untuk dengan cepat membebaskan swap dari proses-proses tersebut sementara node kelebihan beban dan membutuhkan sesuatu yang lebih cepat daripada metode saya saat ini:
unswap(){ [[ $1 && $(ls /proc/$1/maps) ]] && ((gcore -o /tmp/deleteme $1 &>/dev/null; rm -fv /tmp/deleteme.$1)&) 2>/dev/null || echo "must provide valid pid";};unswap
Core dump ini memaksa semua ram untuk diakses dan dengan demikian melakukan pekerjaan menariknya keluar dari swap, tapi saya belum menemukan cara untuk menghindari penulisan ke file. Juga, sepertinya proses akan lebih cepat jika saya bisa mengisolasi rentang alamat yang saat ini ditukar dan hanya membuang bagian itu ke / dev / null, tapi saya belum menemukan cara untuk melakukan itu.
Ini adalah simpul yang sangat besar, jadi metode swapoff / swapon yang biasa menghabiskan banyak waktu, dan sekali lagi, konfigurasi simpul tidak di bawah kendali saya, jadi memperbaiki akar penyebabnya bukan bagian dari pertanyaan ini. Namun, wawasan apa pun tentang bagaimana saya bisa membebaskan sebagian besar pertukaran dengan cepat tanpa mematikan / memulai kembali apa pun akan dihargai.
Lingkungan: CentOS 6.7 / OpenVZ
Pembaruan untuk siapa saja yang mungkin mengalami hal ini nanti:
Menggunakan input Jlong, saya membuat fungsi berikut:
unswap(){ (awk -F'[ \t-]+' '/^[a-f0-9]*-[a-f0-9]* /{recent="0x"$1" 0x"$2}/Swap:/&&$2>0{print recent}' /proc/$1/smaps | while read astart aend; do gdb --batch --pid $1 -ex "dump memory /dev/null $astart $aend" &>/dev/null; done&)2>/dev/null;};
Agak lambat, tetapi melakukan apa yang diminta di sini sebaliknya. Mungkin bisa meningkatkan kecepatan dengan hanya menemukan rentang alamat terbesar di swap, dan menghilangkan iterasi untuk area yang sepele, tetapi premisnya bagus.
Contoh kerja:
#Find the process with the highest swap use
[~]# grep VmSwap /proc/*/status 2>/dev/null | sort -nk2 | tail -n1 | while read line; do fp=$(echo $line | cut -d: -f1); echo $line" "$(stat --format="%U" $fp)" "$(grep -oP "(?<=NameS).*" $fp); done | column -t
/proc/6225/status:VmSwap: 230700 kB root mysqld
#Dump the swapped address ranges and observe the swap use of the proc over time
[~]# unswap(){ (awk -F'[ t-]+' '/^[a-f0-9]*-[a-f0-9]* /{recent="0x"$1" 0x"$2}/Swap:/&&$2>0{print recent}' /proc/$1/smaps | while read astart aend; do gdb --batch --pid $1 -ex "dump memory /dev/null $astart $aend" &>/dev/null; done&)2>/dev/null;}; unswap 6225; while true; do grep VmSwap /proc/6225/status; sleep 1; done
VmSwap: 230700 kB
VmSwap: 230700 kB
VmSwap: 230676 kB
VmSwap: 229824 kB
VmSwap: 227564 kB
... 36 lines omitted for brevity ...
VmSwap: 9564 kB
VmSwap: 3212 kB
VmSwap: 1876 kB
VmSwap: 44 kB
VmSwap: 0 kB
Solusi terakhir untuk bulk-dumping hanya sebagian besar dari memori yang ditukar:
unswap(){ (awk -F'[ \t-]+' '/^[a-f0-9]*-[a-f0-9]* /{recent="0x"$1" 0x"$2}/Swap:/&&$2>1000{print recent}' /proc/$1/smaps | while read astart aend; do gdb --batch --pid $1 -ex "dump memory /dev/null $astart $aend" &>/dev/null; done&)2>/dev/null;}; grep VmSwap /proc/*/status 2>/dev/null | sort -nk2 | tail -n20 | cut -d/ -f3 | while read line; do unswap $line; done;echo "Dumps Free(m)"; rcount=10; while [[ $rcount -gt 0 ]]; do rcount=$(ps fauxww | grep "dump memory" | grep -v grep | wc -l); echo "$rcount $(free -m | awk '/Swap/{print $4}')"; sleep 1; done
Saya belum menentukan apakah metode ini menimbulkan risiko bagi kesehatan proses atau sistem, terutama ketika dilingkarkan melalui beberapa proses secara bersamaan. Jika ada yang memiliki wawasan tentang efek potensial ini terhadap proses atau sistem, jangan ragu untuk berkomentar.
gdb
contoh paraller jika proses yang akan ditukar memiliki banyak fragmen yang ditukar. Script akan meluncurkangdb
instance paraller untuk setiap fragmen (besar) yang ditukar untuk 20 proses terbesar. Saya pikir kita harus menambahkan setidaknya| tail -n20
setelahawk
melewati hasil untukwhile
mengulangi untuk membatasi proses paraller maksimum ke 400.Jawaban:
Anda dapat mencapai hasil yang sama dengan menggunakan perintah 'dump memory' GDB dan menulisnya ke / dev / null.
Anda hanya perlu menemukan wilayah di / proc / $ PID / smaps yang perlu dibuka. contoh dari / proc / $ PID / smaps:
dan kemudian gunakan --batch mode untuk menjalankan perintah gdb sehingga Anda dapat menggunakannya dalam fungsi Anda:
sumber