Как можно было бы быстро извлечь из процесса подкачки всю замененную память процесса без записи на диск?
Контекст по этому вопросу тривиален, поскольку системная проблема, требующая решения этого вопроса, решается другими сторонами. Однако прямо сейчас у меня есть проблема, из-за которой мне часто приходится освобождать пространство подкачки на узле 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.Ответы:
Вы можете достичь того же результата, используя команду GDB 'dump memory' и записав ее в / dev / null.
Вам просто нужно найти регионы в / proc / $ PID / smaps, которые нужно развернуть. пример из / proc / $ PID / smaps:
а затем используйте режим --batch для выполнения команды gdb, чтобы вы могли использовать ее в своей функции:
источник