Извлечение всей обмененной памяти процесса из обмена

8

Как можно было бы быстро извлечь из процесса подкачки всю замененную память процесса без записи на диск?

Контекст по этому вопросу тривиален, поскольку системная проблема, требующая решения этого вопроса, решается другими сторонами. Однако прямо сейчас у меня есть проблема, из-за которой мне часто приходится освобождать пространство подкачки на узле OpenVZ, когда нагрузка и ожидание ввода-вывода чрезвычайно высоки.

Своп часто используется в основном несколькими процессами MySQL и clamd, работающими в отдельных контейнерах. Перезапуск этих служб освобождает подкачку и решает проблему на узле, но нежелателен по очевидным причинам.

Я ищу способ быстро освободить подкачку от этих процессов, пока узел перегружен, и мне нужно что-то быстрее, чем мой текущий метод:

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

Этот основной дамп обеспечивает доступ ко всему ОЗУ и, таким образом, выполняет работу по извлечению его из свопинга, но мне еще предстоит найти способ избежать его записи в файл. Кроме того, кажется, что процесс был бы быстрее, если бы я мог изолировать диапазоны адресов, которые в настоящее время поменялись местами, и просто сбросить эту часть в / dev / null, но мне еще предстоит найти способ сделать это.

Это огромный узел, поэтому обычный метод swapoff / swapon занимает непомерно много времени, и опять же, настройка узла не находится под моим контролем, поэтому устранение основной причины не является частью этого вопроса. Тем не менее, любое понимание того, как я могу быстро освободить значительную часть свопа, не убивая / не перезапуская что-либо, будет оценено.

Окружающая среда: CentOS 6.7 / OpenVZ

Обновление для тех, кто может наткнуться на это позже:

Используя вход Jlong, я создал следующую функцию:

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;};

Это немного медленно, но делает именно то, что было запрошено здесь в противном случае. Вероятно, можно улучшить скорость, найдя только самые большие диапазоны адресов в разделе подкачки, и пропуская итерации для тривиально небольших областей, но предпосылка разумна.

Рабочий пример:

#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

Окончательное решение для массового дампа только больших кусков подкачанной памяти:

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 

Мне еще предстоит определить, представляет ли этот метод какой-либо риск для работоспособности процесса или системы, особенно при одновременном наложении нескольких процессов. Если у кого-то есть понимание возможного влияния, которое это может оказать на процессы или систему, пожалуйста, не стесняйтесь комментировать.

Брэндон ДюПри
источник
Мне кажется, что «окончательное решение» может запустить огромное количество параллельных gdbэкземпляров, если процесс, в который нужно заменить, имеет много замененных фрагментов. Скрипт запустит gdbэкземпляр paraller для каждого замененного (большого) фрагмента для 20 крупнейших процессов. Я думаю, что нужно по крайней мере добавить | tail -n20после того, как awkперед передачей результатов в whileцикл, чтобы ограничить максимальное число параллельных процессов до 400.
Микко Rantalainen

Ответы:

8

Вы можете достичь того же результата, используя команду GDB 'dump memory' и записав ее в / dev / null.

Вам просто нужно найти регионы в / proc / $ PID / smaps, которые нужно развернуть. пример из / 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

а затем используйте режим --batch для выполнения команды gdb, чтобы вы могли использовать ее в своей функции:

[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
источник
Хорошая идея, я улучшил это немного позже, тогда другие люди улучшили это еще больше за эти годы, и это стало github.com/wiedemannc/deswappify-auto
kubanczyk