понедельник, 28 января 2013 г.

Падение сервера и небольшое расследование

Добрый день.

Сегодня у меня упал сервер и хотел бы оставить заметку для себя на будущее.



Ехал домой и тут мне пришла смска с Zabbix-сервера, о недоступности одного из моих серверов. Приехав домой и проверив, что сервер не доступен. Первым делом я решил его перезагрузить (сильно не пинайте, я только начинающий), через панель управления серверами hetznera.

После перезагрузки удостоверился, что сервер работает в штатном режиме.
Но когда я вызвал atop, я увидел, что DISK busy 100% и тогда я немного запаниковал, в чем же может быть причина.

Первым делом в интерактивном режиме atop я нажал клавишу d, который строит процессы по использованию диска и на удивление для себя не обнаружил ни одного процесса, который бы забивал диск.

Тогда я решил воспользоваться программой nmon - которая разработана для анализа и мониторинга данных производительности системы.
$ nmon

увидев приглашение:
Нажимаем на кнопку d .
И увидел не утешительную информацию о Disk I/O:
Как-то сразу я решил проверить, а все ли хорошо у меня с рейдом, так как hetzner при заказе сервера сразу устанавливает все на рейдах и вот что я увидел:

Странно это все подумал я, но сразу обнаружил откуда такое количество процессов чтения и записи. Походу при перезагрузке сервера произошла ошибка и информация на дисках раз синхронизировалась.  И теперь идет процесс синхронизации.

В Linux есть две переменные, которые задают минимальную и максимальную скорость синхронизации рейд массива. Для того, что бы их посмотреть можно воспользоваться такими командами:
Просмотреть минимальную скорость:
$ sysctl dev.raid.speed_limit_min
или
$ cat /proc/sys/dev/raid/speed_limit_min

Просмотреть максимальную скорость:
$ sysctl dev.raid.speed_limit_max
или
$ cat /proc/sys/dev/raid/speed_limit_max

Для увеличения скорости перестроения программного RAID я решил увеличить минимальную и максимальную скорость для этого дела:
$ echo "50000" > /proc/sys/dev/raid/speed_limit_min
или
$ sysctl -w dev.raid.speed_limit_min=50000
Увеличили минимальную скорость до 50 мб/c.

$ echo "300000" > /proc/sys/dev/raid/speed_limit_max
или
$ sysctl -w dev.raid.speed_limit_max=300000
Увеличив максимальную скорость до 300 мб/c.

И с этим я закончил в ожидании когда синхронизируется рейд. Так как у меня занято всего 32Гб дискового пространства, то это должно занять максимум пару часов.


Дальше я решил разобраться в чем же проблема зависания сервера.
$ cat /var/log/message | less
И ищем записи предшествующие:

Jan 28 23:17:24 serv kernel: [    0.000000] Initializing cgroup subsys cpuset
Jan 28 23:17:24 serv kernel: [    0.000000] Initializing cgroup subsys cpu

Тут я увидел очень много непонятного мне текста. Но самое важное (как мне кажется) находится примерно в таких строках:
Jan 28 23:13:35 serv kernel: [2245843.840156] Free swap  = 0kB
Jan 28 23:13:35 serv kernel: [2245843.840164] Total swap = 2096056kB
Jan 28 23:13:35 serv kernel: [2245843.865152] 515968 pages RAM
Jan 28 23:13:35 serv kernel: [2245843.865166] 8992 pages reserved
Jan 28 23:13:35 serv kernel: [2245843.865179] 68362 pages shared
Jan 28 23:13:35 serv kernel: [2245843.865192] 474470 pages non-shared
Jan 28 23:13:43 serv kernel: [2245853.424972] php invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0
...
Jan 28 23:13:43 serv kernel: [2245853.425729] Free swap  = 0kB
Jan 28 23:13:43 serv kernel: [2245853.425738] Total swap = 2096056kB
Jan 28 23:13:43 serv kernel: [2245853.453090] 515968 pages RAM
Jan 28 23:13:43 serv kernel: [2245853.453105] 8992 pages reserved
Jan 28 23:13:43 serv kernel: [2245853.453117] 66634 pages shared
Jan 28 23:13:43 serv kernel: [2245853.453130] 476069 pages non-shared
Jan 28 23:14:06 serv kernel: [2245874.237441] mysqld invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0


А точнее даже в строках выделенные красным цветом.
Я сразу обратился в гугл за сведениями о oom-killer и вот что я нашел.

OOM Killer - это способ ядра решить проблему, когда памяти недостаточно. Известно, что виртуальной памяти может быть бесконечно много (в пределах адресации), а вот физической - вполне конечное число. Иногда процессы системы съедают ее всю. и системе надо кого-то убить, чтобы продолжить работу. Текущая версия OOM Killer в Linux стремится выбрать наименее важный процесс. Он выбирает среди всех процессов, кроме init и kernel threads, самый негодный (badness).


Алгоритм расчета уровня негодности процесса (итоговое значение будет измеряться в очках негодности (badness ponts)):
  1. Берется размер виртуальной памяти процесса (total_vm). Это базовые очки негодности (mm/oom_kill.c:69).
  2. К текущим очкам прибавляется total_vm/2 + 1 для всех порожденных процессов (mm/oom_kill.c:85).
  3. Текущие очки делятся на int_sqrt(cpu_time), где cpu_time — это user + system время процесса сдвинутое вправо наSHIFT_HZ + 3, т.е. для HZ=1000 приблизительно будет равен значению int_sqrt((utime+stime)/10). причем если результат деления и последующего округления будет 0 — то очки не изменяются (mm/oom_kill.c:100).
  4. Текущие очки делятся на int_sqrt(int_sqrt(run_time/1024)), где run_time — время прошедшое с момента запуска процесса. Если результат 0 — то очки не изменяются (mm/oom_kill.c:100).
  5. Очки умножаются на 2, если nice процесса больше 0 (mm/oom_kill.c:118).
  6. Если процесс имеет привилегию CAP_SYS_ADMIN или CAP_SYS_RESOURCE или (e)uid в нуле, то текущие очки делятся на 4 (mm/oom_kill.c:125).
  7. Если процесс имеет привилегию CAP_SYS_RAWIO, то текущие очки делятся на 4 (mm/oom_kill.c:133).
  8. Если память процесса, для которого мы считаем очки негодности, пересекается с памятью процесса, для которого в момент выделения новой памяти произошла ошибка out of memory, тогда очки делятся на 8 (для ядер старше 2.6.28,mm/oom_kill.c:142).
  9. Набранные очки умножаются на 2oom_adj, где oom_adj — берется из /proc/$PID/oom_adj, он может принимать значения от -17 до 15. В случае значения -17 процесс не будет тронут OOM Killer (mm/oom_kill.c:150).
И самый негодный (с самыми большими очками) процесс будет убит.

Вся эта информация нагло украдена отсюда [3], за что и спасибо ему. Там есть немного дополнительной информации и пояснений.


Теперь ясно, что проблема, скорее всего, заключается в прожорливых php и mysql.

Так как опыта у меня мало, я сразу решил пойти в настройки и тюнить php и mysql.
А это уже тема для отдельной заметки.

Полезные ссылки:
[1] HowTo: Speed UP Linux Software Raid Building And Re-syncing
[2] Увеличение скорости перестроения программного RAID в Linux
[3] Про память: OOM Killer

Комментариев нет:

Отправить комментарий