Kubernetes и kswapd0 — злая парочка?

Kubernetes и kswapd0 — злая парочка?

Я собираю кластер Kubernetes на чистом железе (ничего сложного, всего три сервера) с помощью kubeadm на Debian 9. Как и просил Kubernetes, я отключаю SWAP:

  • swapoff -a
  • удаление строки SWAP в/etc/fstab
  • Добавление vm.swappiness = 0к/etc/sysctl.conf

Итак, на моих серверах больше нет SWAP.

$ free
              total        used        free      shared  buff/cache   available
Mem:        5082668     3679500      117200       59100     1285968     1050376
Swap:             0           0           0

Один узел используется для запуска некоторых микросервисов. Когда я начинаю играть со всеми микросервисами, они используют 10% ОЗУ каждый. А процесс kswapd0 начинает использовать много ресурсов ЦП.

Если я немного напрягаю микросервисы, они перестают отвечать, потому что kswapd0 использует весь процессор. Я пытаюсь подождать, пока kswapd0 остановит свою работу, но этого так и не произошло. Даже после 10 часов.

Я прочитал много информации, но так и не нашел решения.

Я могу увеличить объем оперативной памяти, но это не решит мою проблему.

Как мастера Kubernetes справляются с такого рода проблемами?

Подробнее:

  • Kubernetes версии 1.15
  • Калико версия 3.8
  • Дебиан версии 9.6

Заранее благодарю вас за вашу бесценную помощь.

-- Редактировать 1 --

По просьбе @john-mahowald

$ cat /proc/meminfo
MemTotal:        4050468 kB
MemFree:          108628 kB
MemAvailable:      75156 kB
Buffers:            5824 kB
Cached:           179840 kB
SwapCached:            0 kB
Active:          3576176 kB
Inactive:          81264 kB
Active(anon):    3509020 kB
Inactive(anon):    22688 kB
Active(file):      67156 kB
Inactive(file):    58576 kB
Unevictable:          92 kB
Mlocked:              92 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:       3472080 kB
Mapped:           116180 kB
Shmem:             59720 kB
Slab:             171592 kB
SReclaimable:      48716 kB
SUnreclaim:       122876 kB
KernelStack:       30688 kB
PageTables:        38076 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     2025232 kB
Committed_AS:   11247656 kB
VmallocTotal:   34359738367 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:      106352 kB
DirectMap2M:     4087808 kB

решение1

Такое поведение kswapd0 является намеренным и объяснимым.

Хотя вы отключили и удалили файл подкачки и установили swappiness на ноль, kswapd следит за доступной памятью. Он позволяет вам потреблять почти всю память, не предпринимая никаких действий. Но как только доступная память падает до критически низкого значения (низкие страницы для зоны Normal в , /proc/zoneinfo~4000 из 4K страниц на моем тестовом сервере), kswapd вступает в дело. Это приводит к высокой загрузке ЦП.

Вы можете воспроизвести проблему и исследовать ее глубже следующим образом. Вам понадобится инструмент, который позволит вам потреблять память контролируемым образом, например скрипт, предложенный Романом Евстифеевым:ramhog.py

Скрипт заполняет память 100-мегабайтными фрагментами ASCII-кода "Z". Для честности эксперимента скрипт запускается на хосте Kubernetes, а не в pod, чтобы не задействовать k8s. Этот скрипт следует запустить в Python3. Он немного изменен, чтобы:

  • быть совместимым с версиями Python ниже 3.6;
  • установите размер выделяемого фрагмента памяти менее 4000 страниц памяти (малые страницы для зоны Normal в /proc/zoneinfo; я установил 10 МБ), чтобы в конечном итоге ухудшение производительности системы было более заметным.
from time import sleep

print('Press ctrl-c to exit; Press Enter to hog 10MB more')

one = b'Z' * 1024 * 1024  # 1MB hog = []

while True:
    hog.append(one * 10)  # allocate 10MB
    free = ';\t'.join(open('/proc/meminfo').read().split('\n')[1:3])
    print("{}\tPress Enter to hog 10MB more".format(free), end='')
    input()
    sleep(0.1)

Вы можете установить 3 терминальных соединения с тестовой системой, чтобы наблюдать за происходящим:

  • запустить скрипт;
  • выполнить верхнюю команду;
  • получить /proc/zoneinfo

Запустите скрипт:

$ python3 ramhog.py

После нескольких нажатий клавиши Enter (из-за небольшого выделенного нами фрагмента памяти (10 МБ)) вы заметите, что

становится MemAvailableвсе меньше и ваша система становится все менее и менее отзывчивой:вывод ramhog.py

вывод ramhog.pu

Бесплатные страницы окажутся ниже нижней отметки:бесплатные страницы

зонаинформация

В результате kswapd и процессы k8s проснутся, а загрузка ЦП возрастет до 100%:вершина

верхний вывод команды

Обратите внимание, что скрипт работает отдельно от k8s, а SWAP отключен. Поэтому и Kubernetes, и kswapd0 простаивали в начале теста. Работающие pod'ы не были затронуты. Хотя со временем нехватка доступной памяти, вызванная третьим приложением, приводит к высокой загрузке ЦП: не только kswapd, но и k8s. Это означает, что первопричина — нехватка памяти, а не сами k8s или kswapd.

Как вы можете видеть из /proc/meminfoпредоставленного вами, MemAvailableстановится довольно низким, что приводит к пробуждению kswapd. Пожалуйста, посмотрите /proc/zoneinfoтакже на вашем сервере.

На самом деле, первопричина не в конфликте или несовместимости k8s и kswap0, а в противоречии между отключенным swap и нехваткой памяти, что в свою очередь вызывает активацию kswapd. Перезагрузка системы временно решит проблему, но добавление большего количества оперативной памяти действительно рекомендуется.

Хорошее объяснение поведения kswapd можно найти здесь: kswapd использует много циклов ЦП

решение2

Kubernetes позволяет нам определить, сколько оперативной памяти мы должны сохранить для системы Linux, используя evictionHard.memory.availableпараметр. Этот параметр задается в ConfigMap, который называется kubelet-config-1.XX. Если объем оперативной памяти превышает уровень, разрешенный конфигурацией, Kubernetes начинает убивать Pod, чтобы сократить их использование.

В моем случае evictionHard.memory.availableпараметр был установлен слишком низко (100Mi). Поэтому для системы Linux не хватает места в оперативной памяти, поэтому kswapd0 начинает бардак, когда использование оперативной памяти слишком велико.

После некоторых тестов, чтобы избежать появления kswapd0, я установил значение evictionHard.memory.available. 800MiПроцесс kswapd0 больше не глючил.

Связанный контент