Menarik semua memori proses yang ditukar keluar dari swap

8

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.

Brandon DuPree
sumber
Saya melihat kepada saya bahwa "solusi akhir" dapat meluncurkan sejumlah besar gdbcontoh paraller jika proses yang akan ditukar memiliki banyak fragmen yang ditukar. Script akan meluncurkan gdbinstance paraller untuk setiap fragmen (besar) yang ditukar untuk 20 proses terbesar. Saya pikir kita harus menambahkan setidaknya | tail -n20setelah awkmelewati hasil untuk whilemengulangi untuk membatasi proses paraller maksimum ke 400.
Mikko Rantalainen

Jawaban:

8

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:

02205000-05222000 rw-p 00000000 00:00 0 
Size:              49268 kB
Rss:               15792 kB
Pss:                9854 kB
Shared_Clean:          0 kB
Shared_Dirty:      11876 kB
Private_Clean:         0 kB
Private_Dirty:      3916 kB
Referenced:          564 kB
Anonymous:         15792 kB
AnonHugePages:         0 kB
Swap:              33276 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB

dan kemudian gunakan --batch mode untuk menjalankan perintah gdb sehingga Anda dapat menggunakannya dalam fungsi Anda:

[root@nunya ~]# swapon -s ; gdb --batch --pid 33795 -ex "dump memory /dev/null 0x02205000 0x05222000" ;swapon -s
Filename                Type        Size    Used    Priority
/dev/sda2                               partition   7811068 7808096 -1

[Thread debugging using libthread_db enabled]

Filename                Type        Size    Used    Priority
/dev/sda2                               partition   7811068 7796012 -1
jlong
sumber
Ide bagus, saya memperbaikinya sedikit kemudian, kemudian orang lain memperbaikinya bahkan lebih selama bertahun-tahun, dan itu menjadi github.com/wiedemannc/deswappify-auto
kubanczyk