Kubernetes: Kubelet / Kubernetes должны работать с включенным Swap

Созданный на 6 окт. 2017  ·  94Комментарии  ·  Источник: kubernetes/kubernetes

Это ОТЧЕТ ОБ ОШИБКЕ или ЗАПРОС О ФУНКЦИОНИРОВАНИИ? :

Раскомментируйте только один, оставьте его в отдельной строке:

/ добрый баг
/ kind feature

Что случилось :

Kubelet / Kubernetes 1.8 не работает с включенным Swap на машинах Linux.

Я обнаружил эту исходную проблему https://github.com/kubernetes/kubernetes/issues/31676
Это пиар https://github.com/kubernetes/kubernetes/pull/31996
и последнее изменение, которое включало его по умолчанию https://github.com/kubernetes/kubernetes/commit/71e8c8eba43a0fade6e4edfc739b331ba3cc658a

Если Kubernetes не знает, как справиться с вытеснением памяти при включенном Swap, он должен найти способ, как это сделать, но не запрашивать избавление от swap.

Пожалуйста, следуйте главе 11 «Управление подкачкой» на kernel.org, например

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

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

Что вы ожидали :

Kubelet / Kubernetes должны работать с включенным Swap. Я считаю, что вместо того, чтобы отключать своп и не предоставлять пользователям никакого выбора, кубернеты должны поддерживать больше вариантов использования и различных рабочих нагрузок, некоторые из них могут быть приложениями, которые могут полагаться на кеши.

Я не уверен, как кубернеты решили, что убить с помощью вытеснения памяти, но, учитывая, что у Linux есть такая возможность, может быть, она должна соответствовать тому, как Linux это делает? https://www.kernel.org/doc/gorman/html/understand/understand016.html

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

Как это воспроизвести (максимально минимально и точно) :

Запустите kubernetes / kublet с настройками по умолчанию в Linux Box

Что еще нам нужно знать? :

Окружающая среда :

  • Версия Kubernetes (используйте kubectl version ):
  • Облачный провайдер или конфигурация оборудования **:
  • ОС (например, из / etc / os-release):
  • Ядро (например, uname -a ):
  • Установить инструменты:
  • Другие:

/ sig узел
cc @mtaufen @vishh @derekwaynecarr @dims

kinfeature sinode

Самый полезный комментарий

Не поддерживает своп по умолчанию? Я был удивлен, услышав это - я думал, Kubernetes готов к прайм-тайму? Своп - одна из таких функций.

На самом деле это не обязательно в большинстве открытых вариантов использования - именно так устроена экосистема Unix, при которой VMM отключает неактивные страницы.

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

Может кто-нибудь прояснить - проблема с вытеснением памяти возникает только в том случае, если вы используете ограничения памяти в определении модуля, но в остальном это нормально?

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

Я искренне думаю, что этот недавний шаг к запуску серверов без подкачки вызван поставщиками PaaS, пытающимися принудить людей к более крупным экземплярам памяти, игнорируя при этом ~ 40-летний дизайн управления памятью. Реальность такова, что ядро ​​действительно хорошо знает, какие страницы памяти активны, а какие нет - пусть оно делает свою работу.

Все 94 Комментарий

Поддержка свопа нетривиальна. Гарантированные стручки никогда не должны требовать замены. Запросы пакетных модулей должны удовлетворяться без необходимости подкачки. На капсулы BestEffort не распространяется гарантия. Кубелету сейчас не хватает сообразительности, чтобы обеспечить нужное предсказуемое поведение здесь между подами.

Ранее в этом году мы обсуждали эту тему на сайте «Управление ресурсами» лицом к лицу. Мы не очень заинтересованы в решении этой проблемы в ближайшем будущем по сравнению с теми выгодами, которые она могла бы получить. Мы предпочли бы повысить надежность обнаружения давления и оптимизировать проблемы, связанные с задержкой, прежде чем пытаться оптимизировать подкачку, но если это для вас более высокий приоритет, мы будем рады вашей помощи.

/ kind feature

@derekwaynecarr спасибо за объяснение! Было сложно получить какую-либо информацию / документацию, почему своп должен быть отключен для кубернетов. Это была основная причина, по которой я открыл эту тему. На данный момент я не считаю этот вопрос приоритетным, просто хотел убедиться, что у нас есть место, где его можно обсудить.

Здесь есть больше контекста: https://github.com/kubernetes/kubernetes/issues/7294 - наличие подкачки имеет очень странное и плохое взаимодействие с ограничениями памяти. Например, контейнер, который достигает предела памяти, _ тогда_ начинает перетекать в своп (похоже, это исправлено, так как f4edaf2b8c32463d6485e2c12b7fd776aef948bc - им не будет разрешено использовать какой-либо своп, независимо от того, есть он или нет).

Для нас это тоже критический вариант использования. У нас есть задание cron, которое иногда приводит к высокому использованию памяти (> 30 ГБ), и мы не хотим постоянно выделять узлы 40+ ГБ. Кроме того, учитывая, что мы работаем в трех зонах (GKE), это выделит 3 таких машины (по 1 в каждой зоне). И эта конфигурация должна быть повторена в 3+ производственных экземплярах и 10+ тестовых экземплярах, что делает использование K8 очень дорогим. Мы вынуждены иметь 25+ узлов по 48 ГБ, что требует огромных затрат !.
Пожалуйста, включите своп !.

Обходной путь для тех, кто действительно хочет подкачки. если ты

  • запустить kubelet с --fail-swap-on=false
  • добавить своп к вашим узлам
  • контейнеры, которые не определяют требования к памяти, по умолчанию смогут использовать всю машинную память, включая подкачку.

Вот что мы делаем. Или, по крайней мере, я почти уверен, что я лично не реализовал это, но я так понимаю.

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

Мы запускаем GKE, и я не знаю, как установить эти параметры.

Я был бы готов рассмотреть возможность внедрения zswap, если кто-нибудь сможет оценить последствия вытеснения памяти в kubelet.

Я запускаю Kubernetes на своем локальном ноутбуке с Ubuntu, и при каждом перезапуске мне приходится отключать свопинг. Также я должен беспокоиться о том, чтобы не приблизиться к пределу памяти, поскольку своп отключен.

Есть ли способ при каждом перезапуске отключать свопинг, например, при изменении файла конфигурации в существующей установке?

Мне не нужна свопинг на узлах, работающих в кластере.

Это просто другие приложения на моем ноутбуке, кроме кластера Kubernetes Local Dev, которым для включения требуется подкачка.

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.2", GitCommit:"5fa2db2bd46ac79e5e00a4e6ed24191080aa463b", GitTreeState:"clean", BuildDate:"2018-01-18T10:09:24Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.2", GitCommit:"5fa2db2bd46ac79e5e00a4e6ed24191080aa463b", GitTreeState:"clean", BuildDate:"2018-01-18T09:42:01Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}

Сейчас флаг не работает.

# systemctl restart kubelet --fail-swap-on=false
systemctl: unrecognized option '--fail-swap-on=false'

Установите следующий флаг Kubelet: --fail-swap-on=false

Во вторник, 30 января 2018 г., в 13:59 icewheel [email protected] написал:

Я запускаю Kubernetes на своем локальном ноутбуке с Ubuntu и при каждом перезапуске
придется отключить своп. Также я должен беспокоиться о том, чтобы не приближаться к памяти
ограничение, если поменять местами, если выключено.

Есть ли способ при каждом перезапуске мне не нужно отключать своп, как некоторые
изменение файла конфигурации в существующей установке?

Мне не нужна свопинг на узлах, работающих в кластере.

Это просто другие приложения на моем ноутбуке, кроме Kubernetes Local Dev.
кластер, которому нужно включить подкачку.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/kubernetes/kubernetes/issues/53533#issuecomment-361748518 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/AA3JwQdj2skL2dSqEVyV46iCllzT-sOVks5tP5DSgaJpZM4PwnD5
.

-
Майкл Тауфен
Google SWE

спасибо @mtaufen

Для систем, которые загружают кластер для вас (например, terraform), вам может потребоваться изменить служебный файл

Это сработало для меня

sudo sed -i '/kubelet-wrapper/a \ --fail-swap-on=false \\\' /etc/systemd/system/kubelet.service

Не поддерживает своп по умолчанию? Я был удивлен, услышав это - я думал, Kubernetes готов к прайм-тайму? Своп - одна из таких функций.

На самом деле это не обязательно в большинстве открытых вариантов использования - именно так устроена экосистема Unix, при которой VMM отключает неактивные страницы.

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

Может кто-нибудь прояснить - проблема с вытеснением памяти возникает только в том случае, если вы используете ограничения памяти в определении модуля, но в остальном это нормально?

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

Я искренне думаю, что этот недавний шаг к запуску серверов без подкачки вызван поставщиками PaaS, пытающимися принудить людей к более крупным экземплярам памяти, игнорируя при этом ~ 40-летний дизайн управления памятью. Реальность такова, что ядро ​​действительно хорошо знает, какие страницы памяти активны, а какие нет - пусть оно делает свою работу.

Это также приводит к тому, что, если память на узле будет исчерпана, она потенциально будет полностью заблокирована, что потребует перезапуска узла, а не просто замедления и восстановления через некоторое время.

Проблемы устаревают после 90 дней бездействия.
Отметьте проблему как новую с помощью /remove-lifecycle stale .
Устаревшие выпуски гниют после дополнительных 30 дней бездействия и в конечном итоге закрываются.

Если сейчас можно безопасно закрыть эту проблему, сделайте это с помощью /close .

Отправьте отзыв в sig-testing, kubernetes / test-infra и / или fejta .
/ жизненный цикл устаревший

У меня много операций чтения с диска в узлах кластера ( K8s Version - v1.11.2 ). Может быть из-за отключения памяти подкачки?

https://stackoverflow.com/questions/51988566/high-number-of-disk-reads-in-kubernetes-nodes

@srevenant В мире кластеров оперативная память другого узла - это новый своп. Тем не менее, я запускаю два экземпляра K8s с одним узлом, где свопинг имеет смысл. Но это не типичный вариант использования K8s.

@srevenant Я полностью согласен с вами, SWAP используется в Unix и Linux по умолчанию с момента их рождения, я думаю, что за 15 лет работы в Linux я не видел приложения, которое запрашивает отключение SWAP.
Проблема SWAP всегда включена по умолчанию, когда мы устанавливаем любой дистрибутив Linux, поэтому я должен отключить его перед установкой K8s, и это было неожиданностью.
Ядро Linux хорошо знает, как управлять SWAP, чтобы временно повысить производительность серверов, когда сервер приближается к пределу ОЗУ.
Означает ли это, что я должен выключить SWAP, чтобы K8s работал нормально?

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

@superdave, пожалуйста,

Я выступаю за правильное включение подкачки в подах Kubernete. На самом деле не имеет смысла не использовать подкачку, поскольку почти все контейнеры являются пользовательскими экземплярами Linux и, следовательно, поддерживают подкачку по умолчанию.
Понятно, что эту функцию сложно реализовать, но с каких это пор это помешало нам двигаться вперед?

Я должен согласиться с тем, что проблемы подкачки должны быть решены в Kubernetes, поскольку отключение подкачки вызывает сбой узла при нехватке памяти на узле. Например, если у вас есть 3 рабочих узла (20 ГБ каждый), и один узел выходит из строя из-за того, что достигнут предел оперативной памяти, 2 других рабочих узла также выйдут из строя после передачи им всех модулей за это время.

Вы можете предотвратить это, установив запросы к памяти в соответствии с фактическим
потребность приложения.

Если одна треть памяти вашего приложения занимает 2 порядка
более медленное хранилище, сможет ли он делать какую-нибудь полезную работу?

В среду, 26 сентября 2018 г., в 6:51 vasicvuk [email protected] написал:

Я должен согласиться с тем, что вопросы подкачки следует решать в Kubernetes, поскольку
отключение подкачки вызывает сбой узла при нехватке памяти на узле. Для
пример, если у вас есть 3 рабочих узла (20 ГБ оперативной памяти каждый), и один узел идет
вниз, потому что достигнут предел оперативной памяти 2 других рабочих узла также пойдут
вниз после передачи им всех стручков за это время.

-
Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/kubernetes/kubernetes/issues/53533#issuecomment-424604731 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/AAICBqZApBscFl5aNA4IcYvlxcvPA88Tks5ueyPlgaJpZM4PwnD5
.

@matthiasr Вы можете сделать это, когда у вас есть 10-50 сервисов. Но когда у вас есть кластер, на котором запущено более 200 сервисов, и половина из них развернута с использованием официальных диаграмм Helm без каких-либо запросов памяти в них, ваши руки приливы.

Но тогда, разве отсутствие запросов к памяти не является проблемой, которую нужно решить?

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

Отключение подкачки также не является хорошим способом обеспечить оперативность. Если вы не закрепите файлы в памяти (по крайней мере, у K8s должна быть возможность для исполняемых файлов), ядро ​​по-прежнему будет выгружать все без исключения страницы с файловой поддержкой в ​​ответ на нехватку памяти или даже на простое неиспользование.

Включение подкачки существенно не меняет поведение ядра. Все, что он делает, - это дает место для замены анонимных страниц или измененных страниц, загруженных из файлов, сопоставленных с COW.

Вы не можете полностью отключить подкачку, поэтому K8s должен выжить, независимо от того, включен

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

@Baughn

ядро по-прежнему будет выгружать все страницы с файловой поддержкой в ​​ответ на нехватку памяти или даже на простое неиспользование. Включение подкачки существенно не меняет поведение ядра.

Вы не можете полностью отключить свопинг,

Не могли бы вы дать какую-нибудь ссылку на это, чтобы я мог заниматься самообразованием?

Если вы не закрепляете файлы в памяти (по крайней мере, у K8s должна быть возможность исполняемых файлов),

Какие возможности вы хотите использовать в k8s? Если двоичный файл статичен, просто его копирование в tmpfs на модуле должно помочь с задержкой подкачки.

@adityakali какие мысли о влиянии свопа в ядре при выключенном свопе?

Не могли бы вы дать какую-нибудь ссылку на это, чтобы я мог заниматься самообразованием?

Как и все современные операционные системы с виртуальной памятью, Linux требует страниц исполняемых файлов с диска в память. При нехватке памяти ядро ​​меняет фактический исполняемый код вашей программы на диск и с него, как и любые другие страницы памяти («подкачка» - это просто отбрасывание, потому что только для чтения, но механизм тот же), и они будут при необходимости повторно загрузить. То же самое касается таких вещей, как строковые константы, которые обычно открываются только для чтения из других разделов исполняемого файла. Другие файлы с расширением mmapped (общие для рабочих нагрузок типа базы данных) также заменяются + выгружаются на соответствующие файлы резервного копирования (требующие фактической записи, если они были изменены) в ответ на нехватку памяти. _Only_ swapping, который вы отключаете путем «отключения swap», называется «анонимной памятью» - памятью, которая _не_ связана с файлом (лучшими примерами являются структуры данных «stack» и «heap»).

Конечно, есть много деталей, которые я пропускаю в приведенном выше описании. В частности, исполняемые файлы могут "блокировать" части своего пространства памяти в оперативной памяти, используя семейство системных вызовов mlock , делать умные вещи с помощью madvise() , это усложняется, когда одни и те же страницы используются несколькими процессами. (например, libc.so) и т. д. Боюсь, что у меня нет более полезного указателя для чтения, кроме этих страниц руководства или общих вещей, таких как учебники или исходный код ядра Linux / docs / список рассылки.

Таким образом, практический эффект вышеизложенного заключается в том, что по мере того, как ваш процесс приближается к пределу памяти, ядро ​​будет вынуждено вытеснять части и константы _code_ из оперативной памяти. В следующий раз, когда потребуется этот бит кода или постоянное значение, программа остановится, ожидая, пока он загрузится с диска (и вытеснит что-то еще). Таким образом, даже с отключенной подкачкой вы все равно получите такое же ухудшение, когда ваш рабочий набор превышает доступную память.

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

Мой последний личный пример чего-то подобного из реальной жизни - это связывание исполняемых файлов kubernetes. В настоящее время (по иронии судьбы) я не могу скомпилировать кубернеты на моем кластере кубернетов, потому что этап go link требует нескольких гигабайт (анонимной) виртуальной памяти, хотя рабочий набор намного меньше.

Чтобы по-настоящему разобраться в том, что «речь идет о рабочем наборе, а не о виртуальной памяти», рассмотрим программу, которая выполняет множество обычных операций ввода-вывода файлов и не имеет ничего общего с mmap. Если у вас достаточно оперативной памяти, ядро ​​будет кэшировать многократно используемые структуры каталогов и данные файлов в оперативной памяти и избегать обращения к диску, а также позволяет временно выполнять запись в оперативную память для оптимизации записи на диск. Даже такая «наивная» программа будет снижать скорость оперативной памяти до скорости диска в зависимости от размера рабочего набора и доступной оперативной памяти. Когда вы прикрепляете что-то к оперативной памяти без необходимости (например, используя mlock или отключая подкачку), вы не позволяете ядру использовать эту страницу физической оперативной памяти для чего-то действительно полезного и (если у вас не было достаточно оперативной памяти для рабочего набора) вы просто переместил дисковый ввод-вывод куда-нибудь еще дороже.

@superdave : Я тоже заинтересован в улучшении статус-кво здесь. Пожалуйста, включите меня, если вы хотите, чтобы другая пара глаз просматривала документ или держала в руках клавиатуру.

Мой последний личный пример чего-то подобного из реальной жизни - это связывание исполняемых файлов kubernetes. В настоящее время (по иронии судьбы) я не могу скомпилировать кубернеты на моем кластере кубернетов, потому что этап go link требует нескольких гигабайт (анонимной) виртуальной памяти, хотя рабочий набор намного меньше.

@superdave : Я тоже заинтересован в улучшении статус-кво здесь. Пожалуйста, включите меня, если вы хотите, чтобы другая пара глаз просматривала документ или держала в руках клавиатуру.

Хорошее изложение проблемы! На самом деле ключевой проблемой здесь является перебивание подкачки; я надеюсь решить эту проблему рационально. Мне кажется, хотя у меня действительно не было времени на то, чтобы обдумать это достаточно, что какая-то метрика активности обмена (количество страниц / выходов за определенный период времени, возможно, с правилом процентилей, чтобы избежать излишнего рвения, если процесс внезапно внезапно вспыхивает на время) может быть хорошим способом оценить вещи на предмет исключения, когда включен своп. Есть ряд показателей, и я подозреваю, что мы хотели бы предложить множество регуляторов, которые можно использовать, а также тщательно оценить вероятные варианты использования. Я также подозреваю, что возможность инструментальных модулей для взаимодействия с виртуальной памятью должна помочь людям лучше настраиваться; Я недостаточно знаком с тем, что уже предлагалось, чтобы сказать, что там сейчас, но подозреваю, что собираюсь выяснить.

Я также недостаточно знаком с элементами управления, которые нам нужны, чтобы знать, насколько хорошо мы можем контролировать поведение подкачки в отдельных модулях / контейнерах; было бы полезно иметь возможность «переименовывать» вещи для хранения или обмена, но разработчики, очевидно, всегда могут попробовать mlock (), когда им абсолютно необходимо гарантировать, что вещи все равно будут резидентными.

В любом случае, да, я абсолютно хочу двигаться дальше в этом направлении. В последнее время я был перегружен работой (решение некоторых проблем OOM с помощью наших собственных микросервисов под k8s, которые выиграли бы от возможности подкачки под нагрузкой, потому что в 99% случаев им не нужны гигабайты ОЗУ, если кто-то не сделает нецелесообразно большой просьба), но, пожалуйста, сообщите мне об этом. Я никогда раньше не участвовал в процессе KEP, так что я буду довольно зеленым, но в наши дни я гораздо лучше работаю в режиме прерывания, чем в режиме опроса. :-)

Я хотел бы отметить, что zram работает за счет использования свопов. Если на k8 нет свопов, значит, нет сжатия памяти, что в большинстве операционных систем, отличных от Linux, включено по умолчанию (cue Windows, MacOS).

У нас есть экземпляр Ubuntu на k8, который каждую ночь запускает большое пакетное задание, которое потребляет много памяти. Поскольку рабочая нагрузка не предопределена, мы вынуждены (дорого) выделять узлу 16 ГБ независимо от его фактического потребления памяти, чтобы избежать OOM. При сжатии памяти на нашем локальном сервере разработки максимальный объем работы составляет всего 3 ГБ. В противном случае в течение дня потребуется всего 1 ГБ памяти. Запрет свопов и, следовательно, сжатия памяти - довольно глупый ход.

Я думаю, что главная проблема здесь, наверное, в изоляции. Типичная машина может содержать тонну модулей, и если памяти становится мало, они могут начать обмениваться местами и полностью разрушить производительность друг друга. Если нет свопа, изоляция намного проще.

Я думаю, что главная проблема здесь, наверное, в изоляции. Типичная машина может содержать тонну модулей, и если памяти становится мало, они могут начать обмениваться местами и полностью разрушить производительность друг друга. Если нет свопа, изоляция намного проще.

Но, как объяснялось ранее, отключение свопа здесь ничего нам не дает. Фактически, поскольку это увеличивает общую нагрузку на память, это может вынудить ядро ​​отбросить части рабочего набора, когда в противном случае оно могло бы выгрузить неиспользуемые данные - так что это ухудшает ситуацию.

Включение свопа само по себе должно улучшить изоляцию.

Но это очень выгодно, если вы запускаете вещи так, как должны (и как Google запускает вещи на Borg): все контейнеры должны указывать верхний предел памяти. Borg использует преимущества инфраструктуры Google и при желании изучает ограничения (исходя из прошлого использования ресурсов и поведения OOM), но, тем не менее, ограничения существуют.

На самом деле я немного сбит с толку, что ребята из K8S разрешили ограничение памяти быть необязательным. В отличие от ЦП, нехватка памяти оказывает очень нелинейное влияние на производительность системы, что подтвердит любой, кто видел полную блокировку системы из-за подкачки. Он действительно должен требовать его по умолчанию и предупреждать вас, если вы решите отключить его.

Но это очень выгодно, если вы запускаете вещи так, как должны (и как Google запускает вещи на Borg): все контейнеры должны указывать верхний предел памяти. Borg использует преимущества инфраструктуры Google и при желании изучает ограничения (исходя из прошлого использования ресурсов и поведения OOM), но, тем не менее, ограничения существуют.

На самом деле я немного сбит с толку, что ребята из K8S разрешили ограничение памяти быть необязательным. В отличие от ЦП, нехватка памяти оказывает очень нелинейное влияние на производительность системы, что подтвердит любой, кто видел полную блокировку системы из-за подкачки. Он действительно должен требовать его по умолчанию и предупреждать вас, если вы решите отключить его.

Я думаю, что проблема, которую здесь не удается решить, заключается в том, что верхний предел является переменным и не всегда известен для некоторых процессов. Проблема, с которой я занимаюсь, в частности, касается использования k8s для управления узлами рендеринга 3D-моделей. В зависимости от ресурсов для модели и сцены, требуемых для рендеринга, необходимое количество оперативной памяти может немного отличаться, и хотя большинство рендеров будут небольшими, тот факт, что _some_ может быть огромным, означает, что наши запросы и ограничения должны резервировать гораздо больше памяти. чем на самом деле нам нужно 90% времени, чтобы избежать OOM, вместо того, чтобы модуль иногда превышал настроенный лимит и мог перетекать в пространство подкачки.

Да, и в этом случае вы должны установить верхний предел на «Нет» или что-то в этом роде. Я хочу сказать, что это не должно быть по умолчанию. Установка его на «ничто» полностью разрушает любой вид интеллектуального планирования рабочей нагрузки, поскольку мастер просто не знает размер «предмета» (задания), который он собирается положить в «рюкзак» (кубелет).

Проблема здесь не в том, что ваша работа будет передана на свопинг, а в том, что все другие задания, запущенные на этом узле, тоже будут. А некоторым (большинству?) Это совсем не понравится.

Программы на Borg написаны так, чтобы их можно было вытеснить (убить, для тех, кто не знаком с жаргоном) в любое время, не влияя на целостность данных. На самом деле я не очень часто вижу это за пределами Google, и признание потенциальной внезапной смерти вашей программы приводит к написанию гораздо более надежного программного обеспечения. Но я отвлекся.

Системы, построенные с помощью таких программ, предпочли бы, чтобы эти программы умерли и были перевоплощены в другом месте ячейки (кластер Borg), а не продолжали страдать на узле с избыточной подпиской. В противном случае задержка хвоста может быть действительно проблематичной, особенно когда количество задач в задании велико.

Не поймите меня неправильно, я не говорю, что это единственный «правильный» способ управления вещами. Я просто пытаюсь объяснить возможное обоснование этого дизайна.

Отказ от ответственности: я бывший сотрудник Google, который использовал Borg для запуска нескольких очень крупных сервисов, поэтому я знаю это достаточно хорошо, и эти знания в значительной степени переносятся в Kubernetes. В настоящее время я не работаю в Google, и все, что я пишу здесь, является моими собственными мыслями.

@ 1e100 : вы объединяете «общий размер виртуальной машины» с размером «рабочего набора». Рабочую нагрузку необходимо планировать на основе размера _ рабочего набора_, и программа будет ухудшаться после превышения размера _ рабочего набора_ (при условии, что имеется достаточный общий доступный своп). Обоснование, которое вы указали выше, также основано на неверном предположении, что подкачка (и другие компромиссы с ухудшением производительности ввода-вывода ram <->) не произойдет только потому, что подкачка отключена.

(Я также бывший сотрудник Google-SRE, и я согласен с тем, что эти распространенные мифы Google почти наверняка повлияли на решение о том, что было нормально (или даже желательно) отключить свопинг и на k8. Я наблюдал, как несколько команд Google пошли через изучение того, что отключение подкачки не отключает подкачку, и совокупную потерю памяти, которая вытекает только из описания «жесткого» (oom-kill) лимита для памяти - это именно некоторые из вещей, которые я хотел бы улучшить с помощью k8s. Сейчас доступно несколько настраиваемых ручек cgroup / swap, которых у нас не было, когда изначально разрабатывалась модель ресурсов borg, и я убежден, что мы можем достичь желаемых результатов без такого подхода «выбросить ребенка с водой в ванну» Я также отмечу, что компромисс Google _ часто_ в том, чтобы быть менее эффективным в среднем для достижения лучшего / известного наихудшего времени (например, поведения в реальном времени), и что это часто _не_ желаемый выбор за пределами Google - меньше / меньше хостов, более расслабленные SLO, более низкие бюджеты, более плохо определенные ed, пакетные задания, большее использование нескомпилированных неэффективных в куче языков и т. д.)

Подкачки анонимной памяти не произойдет. Все, что отображается в памяти (включая программный код и данные), может и все равно будет менять местами, если есть нехватка памяти, поэтому я предположил, что ограничения ОЗУ должны быть обязательными по умолчанию: чтобы уменьшить вероятность возникновения нехватки памяти в первую очередь. Для рабочих нагрузок, требующих еще более строгих гарантий, есть также mlockall() и низкое значение swappiness .

Как бывший сотрудник Google SRE, вы не можете утверждать, что не указывать верхний предел ОЗУ или позволять задачам менять местами все, что они хотят, по прихоти - это хорошо, если вы просто не хотите быть противником. Подкачка файлов с отображением памяти - это уже плохо, добавление еще большего потенциального скачка производительности в микс - нехорошо.

Это общие среды по замыслу, и вы хотите исключить способы, которыми программы могут сделать производительность друг друга непредсказуемой, а не добавлять новые. Как говорят специалисты Google SRE, «надежда - это не стратегия». Свопинг - это самый простой из известных мне способов заставить Linux-машину полностью и безвозвратно заблокироваться, даже если вы переключаетесь на SSD. Это не может быть хорошо, даже если вы запускаете на машине всего одну рабочую нагрузку, не говоря уже о паре десятков. Коррелированные сбои могут быть особенно болезненными в небольших кластерах с небольшим количеством задач / модулей.

Можно проигнорировать проверку свопа даже сегодня, если захочется, но с явным пониманием того, что в этом случае все ставки отключены.

Да, полностью согласен с тем, что у нас должен быть «размер», который мы используем для планирования и во избежание (непреднамеренного) переопределения. И мы также хотим избежать глобального сбоя виртуальных машин, потому что Linux плохо справляется с этим. Мы хотим, чтобы ядро ​​позволяло заменять анонимную память и повторно использовать эту память для чего-то еще, где это имеет смысл, поскольку это строго превосходит систему, которая не может этого сделать. В идеале мы хотим, чтобы отдельные контейнеры могли управлять компромиссами между оперативной памятью и диском и сталкиваться с последствиями выбора собственных ресурсов (избыточного / недостаточного доступа) с минимальным влиянием на другие контейнеры.

Чтобы показать, к чему я клоню, мое текущее предложение соломенного человека таково:

  • Метафора состоит в том, что каждый контейнер ведет себя так, как будто он находится на машине сам по себе с определенным количеством оперативной памяти (задается limits.memory ) и свопом.
  • То же, что и другие ресурсы: расписание на основе requests.memory , ограничение на основе limits.memory . «Память» в данном случае означает «баран» - использование свопа бесплатно.
  • В частности, k8s requests.memory -> cgroup memory.low (уменьшено любым коэффициентом превышения); k8s limits.memory -> cgroup memory.high .
  • Если контейнер превышает сконфигурированный предел памяти, он начинает подкачку - независимо от количества доступной свободной оперативной памяти. Благодаря cgroups, это _не_ только использование виртуальной машины, но также включает в себя блочный кеш, буферы сокетов и т. Д., Относящиеся к контейнеру. Это предотвращает нагрузку на память других контейнеров (или хост-процессов). При поиске страницы для удаления ядро ​​будет искать контейнеры, размер которых превышает размер запроса памяти.
  • Ввести мягкое ограничение kubelet на использование полной подкачки, при котором k8s перестанет планировать новые поды на хосте (точно так же, как другие «общие файловые системы», такие как imagefs).
  • Если мы достигнем жесткого предела общего использования подкачки, то начнем выселение подов на основе qos-class / priority и размера виртуальной машины сверх «запросов» (точно так же, как другие «общие файловые системы», такие как imagefs).
  • Если контейнер значительно превышает свой рабочий набор ( requests.memory ), то он может перегружаться (если он также превышает limits.memory или на хосте недостаточно оперативной памяти). Мы явно ничего не делаем с этим через механизм ресурсов. Если контейнер подвергается обмену данными подкачки, то он (предположительно) откажет в проверке состояния / готовности и будет уничтожен с помощью этого механизма (то есть: замена подкачки возможна, если у нас нет настроенных соглашений об уровне обслуживания по отзывчивости).

Конечным результатом является то, что администратор отвечает за настройку "достаточного" свопа в каждой системе. Приложения должны сконфигурировать limits.memory с _max_ ram, которое они когда-либо захотят использовать, и requests.memory с их предполагаемым рабочим набором (включая буферы ядра и т. Д.). Как и в случае с другими ресурсами, по-прежнему применяются гарантированные классы qos (лимит == запрос), пакетный (лимит не определен или! = Запрос), максимальные усилия (без лимита или запроса). В частности, это побуждает пакетные процессы объявлять близкие к их предполагаемому рабочему набору (без большого буфера безопасности), что обеспечивает эффективное распределение (в идеале ровно 100% оперативной памяти, выделенной для рабочего набора) и дает плавное снижение производительности, когда контейнеры превышают это - точно так же, как и другие «снисходительные» ресурсы, такие как cpu.

Я думаю, что это реализуемо в cgroups Linux, решает проблемы изоляции, продолжает концептуальные прецеденты, установленные другими ресурсами k8s, и ухудшается до существующего поведения, когда своп отключен (что упрощает миграцию). Единственный открытый вопрос, который у меня есть, это то, что уже реализовано (за вычетом мягкого / жесткого ограничения kubelet "swapfs") - мне нужно пойти и прочитать фактический код kubelet / CRI cgroups, прежде чем я смогу написать конкретное предложение и элементы действий. .

Комментарии / обсуждение вышеизложенного, вероятно, неуместны в этом выпуске github (это плохой форум для обсуждения). Если в приведенном выше есть что-то ужасно неправильное, я был бы признателен за обратную связь с гусли о k8s Slack, иначе я напишу надлежащий документ и в какой-то момент пройду обычное обсуждение дизайна.

Я рекомендую написать официальный документ, чтобы у нас был лучший форум для обсуждения.

Согласовано. Я счастлив помочь написать KEP, потому что у меня есть определенные идеи для этого, но я никогда не делал их раньше и предпочел бы иметь более опытную руку на руле направления.

Но, кроме того, у меня нет пропускной способности, чтобы не отставать от канала Slack в свободное время; если есть более асинхронный метод координации, дайте мне знать.

Просто для поддержания жизни: я все еще очень заинтересован в работе над KEP и / или реализацией этого; как только все уляжется (у меня есть семинар, который нужно подготовить к следующим выходным), я попробую присоединиться к каналу Slack.

Привет, идет ли в настоящее время какое-либо публичное обсуждение этого вопроса? (В настоящий момент слабина k8s открыта не для всех, и я предполагаю, что не будет в ближайшее время).

@leonaves, в настоящее время @guslees - последний из обсуждения. Обратите внимание, что для начала должен быть KEP с подробностями в репозитории kubernetes / Enhancements, а также, возможно, потоки списков рассылки.

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

Оказывается, у меня все еще не хватает мыслей, чтобы присоединиться к еще одному каналу Slack. Я все еще не согласен с этим по электронной почте.

Обходной путь для тех, кто действительно хочет подкачки. если ты

  • запустить kubelet с --fail-swap-on=false
  • добавить своп к вашим узлам
  • контейнеры, в которых _не__ указано требование к памяти, по умолчанию смогут использовать всю машинную память, включая подкачку.

Вот что мы делаем. Или, по крайней мере, я почти уверен, что я лично не реализовал это, но я так понимаю.

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

Этот метод больше не работает !? Я включаю своп и разворачиваю под без настройки памяти, и получил этот контейнер

$ docker inspect <dockerID> | grep Memory
            "Memory": 0,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": -1

MemorySwap имеет значение «0», что означает, что этот контейнер не может получить доступ к свопу :(

Проблемы устаревают после 90 дней бездействия.
Отметьте проблему как новую с помощью /remove-lifecycle stale .
Устаревшие выпуски гниют после дополнительных 30 дней бездействия и в конечном итоге закрываются.

Если сейчас можно безопасно закрыть эту проблему, сделайте это с помощью /close .

Отправьте отзыв в sig-testing, kubernetes / test-infra и / или fejta .
/ жизненный цикл устаревший

/ remove-жизненный цикл устаревший.

/ remove-жизненный цикл устаревший

Я собираюсь оставить это здесь как еще одну ссылку для читателей этого выпуска: https://chrisdown.name/2018/01/02/in-defence-of-swap.html

Проблемы устаревают после 90 дней бездействия.
Отметьте проблему как новую с помощью /remove-lifecycle stale .
Устаревшие выпуски гниют после дополнительных 30 дней бездействия и в конечном итоге закрываются.

Если сейчас можно безопасно закрыть эту проблему, сделайте это с помощью /close .

Отправьте отзыв в sig-testing, kubernetes / test-infra и / или fejta .
/ жизненный цикл устаревший

/ remove-жизненный цикл устаревший

эта функция действительно необходима в некоторых случаях использования. в настоящее время мы используем k8s для машинного обучения, и иногда нам нужно загружать большие модели в память (в нашем случае иногда 500 МБ на запрос api!), а ограничения физической памяти вызывают серьезные проблемы. Масштабирование будет работать с технической точки зрения, но затраты будут зашкаливающими. Если бы у нас была виртуальная память в качестве опции, это было бы здорово.

Есть ли шанс, что этот билет снова вернется в дорожную карту?

Похоже на случай для mmap.

Меня тоже очень интересует эта функция. Есть какие-нибудь новости по этому поводу?

Я был бы счастлив начать изучать это, когда у меня будет время, которого сейчас не хватает, но было бы хорошо иметь один или два канонических случая, которые усугубляют проблему, чтобы ее можно было более полно охарактеризовать (помимо "это начинает биться, и все идет к черту "), и окончательный подход и исправление подтверждены.

Любое перспективное решение должно также учитывать последствия подкачки для безопасности. Это, очевидно, верно для всего, что работает в среде Unix, но если люди привыкли запускать модули k8s с псевдогарантией отсутствия подкачки и ленились насчет дисциплины памяти, это может быть довольно грубым сюрпризом, если это разрешено дефолт.

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

Похоже на KEP .

Любое перспективное решение должно также учитывать последствия подкачки для безопасности. Это, очевидно, верно для всего, что работает в среде Unix, но если люди привыкли запускать модули k8s с псевдогарантией отсутствия подкачки и ленились насчет дисциплины памяти, это может быть довольно грубым сюрпризом, если это разрешено дефолт.

Эта логика будет применяться к любым процессам, работающим в смеси контейнеров, независимо от того, используется Kubernetes или нет.

Согласовано! Но Docker уже явно поддерживает работу со свопом. Kubernetes явно этого не делает (хотя вы можете заставить его это сделать). Я считаю, что это должно быть хотя бы вызвано, потому что это не для всех моделей угроз, особенно если им не приходилось думать об этом раньше.

Также да, @sftim , это так. :-) Я думаю, что я говорю, что я хотел бы написать / внести свой вклад в KEP, но я хотел бы увидеть минимальный тестовый пример или два, которые надежно проверяют проблему на данной тестовой системе, прежде чем решиться на это. что мы можем быть уверены, что решаем правильные проблемы.

@superdave, какой тестовый пример вы имеете в виду?

Вот банальный тест:

  1. Настройте кластер с 1 узлом, 16 ГБ ОЗУ и 64 ГБ файла подкачки.
  2. Попробуйте запланировать 20 модулей, каждый с запросом памяти 1 ГБ и ограничением памяти 1 ГБ.
  3. Обратите внимание, что это не все по расписанию.

Вот еще один:

  1. Настройте 6 машин, каждая с 16 ГБ ОЗУ и 64 ГБ файла подкачки.
  2. Попробуйте использовать kubeadm с параметрами по умолчанию, чтобы настроить эти машины как кластер Kubernetes.
  3. Обратите внимание, что kubeadm недоволен использованием свопа.

Сейчас наблюдается огромный сдвиг в сторону SSD на самых респектабельных облачных платформах, и, учитывая, что Linux имеет специальную оптимизацию для обмена на SSD https://lwn.net/Articles/704478/ с дополнительной возможностью сжатия, эта ситуация дает совершенно новую возможность использовать swap как предсказуемый и быстрый ресурс для дополнительной оперативной памяти в случае нехватки памяти.
Отключенная подкачка становится потраченным впустую ресурсом так же, как неиспользуемая оперативная память расходуется впустую, если не используется для буферов ввода-вывода.

@superdave

Согласовано! Но Docker уже явно поддерживает работу со свопом. Kubernetes явно этого не делает (хотя вы можете заставить его это сделать). Я считаю, что это должно быть хотя бы вызвано, потому что это не для всех моделей угроз, особенно если им не приходилось думать об этом раньше.

В этом случае было бы справедливо предположить, что kubelet будет mlock() своем пространстве памяти и установит низкий приоритет уничтожения OOM, чтобы избежать подкачки или уничтожения OOM, и запустить все контейнеры в cgroups с swapiness 0 по умолчанию установлено значение enableSwapiness: 50 для конкретного контейнера (ов) в модуле.
Никаких сюрпризов, батарейки в комплекте.

@sftim Это продемонстрирует, что а) Kubelet не хочет планировать контейнеры и б) Kubelet не запускается с включенным свопом по умолчанию. Я хочу поупражняться в ситуациях, находящихся в верхней части @derekwaynecarr :

Поддержка свопа нетривиальна. Гарантированные стручки никогда не должны требовать замены. Запросы пакетных модулей должны удовлетворяться без необходимости подкачки. На капсулы BestEffort не распространяется гарантия. Кубелету сейчас не хватает сообразительности, чтобы обеспечить нужное предсказуемое поведение здесь между подами.

Ранее в этом году мы обсуждали эту тему на сайте «Управление ресурсами» лицом к лицу. Мы не очень заинтересованы в решении этой проблемы в ближайшем будущем по сравнению с теми выгодами, которые она могла бы получить. Мы предпочли бы повысить надежность обнаружения давления и оптимизировать проблемы, связанные с задержкой, прежде чем пытаться оптимизировать подкачку, но если это для вас более высокий приоритет, мы будем рады вашей помощи.

А также прямо под ним из @matthiasr :

Здесь есть больше контекста: # 7294 - наличие подкачки очень странно и плохо взаимодействует с ограничениями памяти. Например, контейнер, который достигает своего предела памяти, _ тогда_ начинает перетекать в своп (похоже, это исправлено с момента

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

@superdave

Согласовано! Но Docker уже явно поддерживает работу со свопом. Kubernetes явно этого не делает (хотя вы можете заставить его это сделать). Я считаю, что это должно быть хотя бы вызвано, потому что это не для всех моделей угроз, особенно если им не приходилось думать об этом раньше.

В этом случае было бы справедливо предположить, что kubelet будет mlock() своем пространстве памяти и установит низкий приоритет уничтожения OOM, чтобы избежать подкачки или уничтожения OOM, и запустить все контейнеры в cgroups с swapiness 0 по умолчанию установлено значение enableSwapiness: 50 для конкретного контейнера (ов) в модуле.
Никаких сюрпризов, батарейки в комплекте.

Думаю, я здесь со всем согласен. По умолчанию используется текущее поведение, чтобы избежать неприятных сюрпризов.

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

#include <iostream>
#include <vector>
#include <unistd.h>
int main() {
  std::vector<int> data;
  try
    {
        while(true) { data.resize(data.size() + 200); };
    }
    catch (const std::bad_alloc& ex)
    {
        std::cerr << "Now we filled up memory, so assume we never access that stuff again and just moved on, or we're stuck in an endless loop of some sort...";
        while(true) { usleep(20000); };
    }
  return 0;
}

Обходной путь для тех, кто действительно хочет подкачки. если ты

  • запустить kubelet с --fail-swap-on=false
  • добавить своп к вашим узлам
  • контейнеры, в которых _не__ указано требование к памяти, по умолчанию смогут использовать всю машинную память, включая подкачку.

Вот что мы делаем. Или, по крайней мере, я почти уверен, что я лично не реализовал это, но я так понимаю.

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

Привет @hjwp , спасибо за

Могу я задать вопрос после этого?

После настройки всего, как вы сказали, есть ли способ ограничить использование памяти подкачки контейнерами?

Я думал о настройке --memory-swap параметров Docker
https://docs.docker.com/config/containers/resource_constraints/# --memory-swap-details
В настоящее время в моем контейнере нет ограничений на использование подкачки ( "MemorySwap": -1 )

sudo docker inspect 482d70f73c7c | grep Memory
            "Memory": 671088640,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": -1,
            "MemorySwappiness": null,

Но я не смог найти этот параметр в k8s.

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

Мои настройки, связанные с виртуальной машиной

vm.overcommit_kbytes = 0
vm.overcommit_memory = 1
vm.overcommit_ratio = 50
vm.swappiness = 20
vm.vfs_cache_pressure = 1000

Спасибо!

@ pai911 Я не думаю, что это возможно,

в настоящее время CRI не поддерживает это, см. это , в докере нет такой опции, как --memory-swap

это ограничение CRI, однако спецификация OCI поддерживает эту опцию, но не экспортируется на уровень CRI

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

cgroup

Привет @ win-t,

Спасибо за ваш отзыв!

Так что пока эта опция предназначена только для внутреннего использования?

Вы случайно не знаете, какое значение cgroup сопоставлено с этой опцией --memory-swap?

Так что пока эта опция предназначена только для внутреннего использования?

Да, вы не можете установить эту опцию, так как они не отображаются в k8s

кстати, MemorySwap в проверке докеров должно совпадать с Memory соответствии с этим , я не знаю, как вы можете получить -1 в проверке докеров

Вы случайно не знаете, какое значение cgroup сопоставлено с этой опцией --memory-swap?

  • --memory в карте докеров memory.limit_in_bytes в cgroup v1
  • --memory-swap в карте докеров memory.memsw.limit_in_bytes в cgroup v1

@ win-t Большое спасибо!

Я использую следующую версию

Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.10", GitCommit:"1bea6c00a7055edef03f1d4bb58b773fa8917f11", GitTreeState:"clean", BuildDate:"2020-02-11T20:05:26Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}

и я посмотрел историю. похоже, что исправление было добавлено в этот коммит

Может, его нет в той версии, которую я использую?

Так что пока эта опция предназначена только для внутреннего использования?

Да, вы не можете установить эту опцию, так как они не отображаются в k8s

кстати, MemorySwap в проверке докеров должно совпадать с Memory соответствии с этим , я не знаю, как вы можете получить -1 в проверке докеров

Вы случайно не знаете, какое значение cgroup сопоставлено с этой опцией --memory-swap?

  • --memory в карте докеров memory.limit_in_bytes в cgroup v1
  • --memory-swap в карте докеров memory.memsw.limit_in_bytes в cgroup v1

Это странно.

Я использовал kops + Debian, и проверка Docker показывает, что на память подкачки нет ограничений.
(Информация о проверке Docker, которую я опубликовал ранее)

Но потом я перешел на образ Amazon Linux, и вот что у меня получилось

            "Memory": 671088640,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 671088640,
            "MemorySwappiness": null,

Я проведу дополнительное расследование и посмотрю, не ошибка ли это

Так что пока эта опция предназначена только для внутреннего использования?

Да, вы не можете установить эту опцию, так как они не отображаются в k8s
кстати, MemorySwap в проверке докеров должно совпадать с Memory соответствии с этим , я не знаю, как вы можете получить -1 в проверке докеров

Вы случайно не знаете, какое значение cgroup сопоставлено с этой опцией --memory-swap?

  • --memory в карте докеров memory.limit_in_bytes в cgroup v1
  • --memory-swap в карте докеров memory.memsw.limit_in_bytes в cgroup v1

Это странно.

Я использовал kops + Debian, и проверка Docker показывает, что на память подкачки нет ограничений.
(Информация о проверке Docker, которую я опубликовал ранее)

Но потом я перешел на образ Amazon Linux, и вот что у меня получилось

            "Memory": 671088640,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 671088640,
            "MemorySwappiness": null,

Я проведу дополнительное расследование и посмотрю, не ошибка ли это

Теперь я могу воспроизвести проблему, существующую в официальном образе Debian, автор: kops

Похоже, что этот официальный образ kops сделает память подкачки неограниченной
kope.io/k8s-1.15-debian-stretch-amd64-hvm-ebs-2020-01-17

Этапы воспроизведения:

Моя группа экземпляров kops определяется следующим образом:

apiVersion: kops.k8s.io/v1alpha2
kind: InstanceGroup
metadata:
  creationTimestamp: "2020-03-12T06:33:09Z"
  generation: 5
  labels:
    kops.k8s.io/cluster: solrcluster.k8s.local
  name: node-2
spec:
  additionalUserData:
  - content: |
      #!/bin/sh
      sudo cp /etc/fstab /etc/fstab.bak
      sudo mkfs -t ext4 /dev/nvme1n1
      sudo mkdir /data
      sudo mount /dev/nvme1n1 /data
      echo '/dev/nvme1n1       /data   ext4    defaults,nofail        0       2' | sudo tee -a /etc/fstab
      sudo fallocate -l 2G /data/swapfile
      sudo chmod 600 /data/swapfile
      sudo mkswap /data/swapfile
      sudo swapon /data/swapfile
      echo '/data/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
      sudo sysctl vm.swappiness=10
      sudo sysctl vm.overcommit_memory=1
      echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
      echo 'vm.overcommit_memory=1' | sudo tee -a /etc/sysctl.conf
    name: myscript.sh
    type: text/x-shellscript
  image: kope.io/k8s-1.15-debian-stretch-amd64-hvm-ebs-2020-01-17
  instanceProtection: true
  kubelet:
    failSwapOn: false
  machineType: t3.micro

Шаги:

  1. После того, как кластер будет запущен.

  2. Разверните Solr Helm Chart со следующими настройками ресурсов

resources:
  limits:
    cpu: "1"
    memory: 640Mi
  requests:
    cpu: 100m
    memory: 256Mi

** Любой другой модуль тоже должен работать

  1. Список контейнеров, чтобы найти идентификатор контейнера
    sudo docker container ls

  2. Проверить параметры памяти контейнера
    sudo docker inspect d67a72bba427 | grep Memory

            "Memory": 671088640,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": -1,
            "MemorySwappiness": null,

Должен ли я куда-нибудь отправить проблему? к8с или копс?

Шаги:

  1. После того, как кластер будет запущен.
  2. Разверните Solr Helm Chart со следующими настройками ресурсов
resources:
  limits:
    cpu: "1"
    memory: 640Mi
  requests:
    cpu: 100m
    memory: 256Mi

** Любой другой модуль тоже должен работать

  1. Список контейнеров, чтобы найти идентификатор контейнера
    sudo docker container ls
  2. Проверить параметры памяти контейнера
    sudo docker inspect d67a72bba427 | grep Memory
            "Memory": 671088640,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": -1,
            "MemorySwappiness": null,

Должен ли я куда-нибудь отправить проблему? к8с или копс?

Я могу подтвердить, что могу видеть правильное поведение только в Amazon Linux
ami-0cbc6aae997c6538a : amzn2-ami-hvm-2.0.20200304.0-x86_64-gp2

            "Memory": 671088640,
            "CpusetMems": "",
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 671088640,
            "MemorySwappiness": null,

То есть: "MemorySwap" == "Память"

Два других изображения имеют одинаковые настройки: "MemorySwap": -1 , что приводит к неограниченному использованию свопа.

  • Debian

    • ami-075e61ad77b1269a7 : k8s-1.15-debian-stretch-amd64-hvm-ebs-2020-01-17

  • Ubuntu

    • ami-09a4a9ce71ff3f20b : ubuntu / изображения / hvm-ssd / ubuntu-bionic-18.04-amd64-server-20200112

Так я думаю, это может быть проблема k8s?

Истории пользователей:

(1) Программа, предоставленная моим поставщиком, использует среду выполнения языка, которая требует доступа к источнику программного кода. Благодаря этому при инициализации весь исходный код программы размещается в отдельной области памяти. После инициализации программы и перехода контейнера в состояние готовности доступ к этой памяти не будет (вы не можете это доказать, но это не так). Кроме того, программа выделяет несколько страниц для пользовательской обработки OOM. Эту память можно выгрузить. Я не хочу, чтобы эта «мертвая память» вытеснила другие кластерные приложения. Я могу точно рассчитать объем памяти, который станет мертвым, и указать его как запрос на подкачку в спецификации Pod.

(2) Я выполняю рабочую нагрузку машинного обучения или анализа данных, при которой использование памяти может внезапно увеличиваться или уменьшаться. Ничего страшного, если эти приложения замедляются, если они не завершаются и в конечном итоге не завершаются. Я хочу подготовить кластер с помощью подкачки, чтобы смягчить вытеснение, когда происходят эти всплески памяти. Эти поды будут иметь низкие запросы на память и подкачку, умеренный лимит памяти - возможно, достаточный для базового + одного рабочего набора - и большой лимит подкачки.

(3) Я запускаю веб-сервер в интерпретаторе (например, Ruby on Rails), которому иногда требуется fork + exec. Строгий учет памяти приводит к сбою вилки, что недопустимо. Я хочу подготовить подкачку, чтобы у ядра был гарантированный запас памяти для покрытия поведения процесса между вызовами fork и exec. Значение vm.swappiness может быть установлено таким образом, чтобы исключить возможность подкачки, и я установил предупреждения для уведомления операций, если подкачка действительно используется во время производства. Спецификация модуля установит запрос на подкачку и ограничит одно и то же значение.

Недавно мы попытались перенести все наши сервисы на основе докеров в Kubernetes, но нам пришлось отказаться от проекта из-за того, что своп не поддерживается.

Мы обнаружили, что нам нужно было бы выделить в 3 раза больше оборудования, чтобы поддерживать то же количество контейнеров, которые мы в настоящее время использовали с включенной подкачкой.

Основная проблема заключается в том, что наша рабочая нагрузка состоит из ряда контейнеров, которые могут использовать до 1 ГБ или около того памяти (или подкачки), но обычно используют около 50 МБ или около того при нормальной работе.

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

В итоге мы отказались от миграции на Kubernetes и временно переместили все на Swarm в надежде, что своп будет поддерживаться в будущем.

Основная проблема заключается в том, что наша рабочая нагрузка состоит из ряда контейнеров, которые могут использовать до 1 ГБ или около того памяти (или подкачки), но обычно используют около 50 МБ или около того при нормальной работе.

Можно рискнуть сказать, что приложения, работающие в этих контейнерах, написаны невероятно плохо.

Можно рискнуть сказать, что приложения, работающие в этих контейнерах, написаны невероятно плохо.

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

Основная проблема заключается в том, что наша рабочая нагрузка состоит из ряда контейнеров, которые могут использовать до 1 ГБ или около того памяти (или подкачки), но обычно используют около 50 МБ или около того при нормальной работе.

Можно рискнуть сказать, что приложения, работающие в этих контейнерах, написаны невероятно плохо.

lol, это функция ядра, приложение может использовать madvise(2) в файле shm, и мы не блокируем системные вызовы madvise,
поэтому пользователь имеет право использовать эту функцию в своем дизайне, нельзя сказать, что «написаны очень плохо»,

Основная проблема заключается в том, что наша рабочая нагрузка состоит из ряда контейнеров, которые могут использовать до 1 ГБ или около того памяти (или подкачки), но обычно используют около 50 МБ или около того при нормальной работе.

Можно рискнуть сказать, что приложения, работающие в этих контейнерах, написаны невероятно плохо.

Ваш ответ указывает на то, что вы не понимаете рабочих нагрузок, с которыми работают многие разработчики.

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

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

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

Некоторые развертывания Kubernetes требуют подкачки

У меня есть допустимый вариант использования - я разрабатываю локальный продукт, дистрибутив linux, включенный в kubeadm. нет горизонтального масштабирования по дизайну. Чтобы пережить пики конъюнктурной памяти и по-прежнему функционировать (но медленно), мне определенно нужен своп .

Чтобы установить kubeadm с включенным свопом

  1. Создайте файл в /etc/systemd/system/kubelet.service.d/20-allow-swap.conf с содержимым:

    [Service]
    Environment="KUBELET_EXTRA_ARGS=--fail-swap-on=false"
    
  2. Запустить

    sudo systemctl daemon-reload
    
  3. Инициализировать kubeadm флагом --ignore-preflight-errors=Swap

    kubeadm init --ignore-preflight-errors=Swap
    

https://stackoverflow.com/a/62158455/3191896

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

Для моих собственных нужд многие мои приложения используют кеши. Тем не менее, если приложению внезапно понадобится много памяти, было бы предпочтительнее отправить самый старый кеш на диск, если эти приложения не отвечают на запрос, чтобы снизить давление на память, чем позволить новой рабочей нагрузке исчерпать память или иметь для поддержки всплеска с помощью физической памяти + больше для скользящих развертываний + больше на случай возможного сбоя узла.

@metatick сказал:

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

Стандартная библиотека C Linux предназначена для замены распределителя памяти; для этой цели malloc , realloc и free вызываются через указатели. Таким образом, вы можете просто LD_PRELOAD библиотеку, которая переопределит их для выделения из файла mmapped.

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

На самом деле он будет работать точно так же, как обычный своп, потому что им будет управлять тот же самый код в ядре. Единственное отличие будет заключаться в отсутствии параметра swappiness для настройки его приоритета.

Единственный открытый вопрос, который у меня есть, это то, что уже реализовано (за вычетом мягкого / жесткого ограничения kubelet "swapfs") - мне нужно пойти и прочитать фактический код kubelet / CRI cgroups, прежде чем я смогу написать конкретное предложение и элементы действий. .

@anguslees ,
Вы когда-нибудь приходили проверять поведение? Если да, не могли бы вы добавить какое-нибудь разрешение или ссылку на него, пожалуйста?

Спасибо,
Янв

Вы когда-нибудь приходили проверять поведение? Если да, не могли бы вы добавить какое-нибудь разрешение или ссылку на него, пожалуйста?

Я не. (Я немного покопался в коде докера, но к настоящему времени забыл об этом, и мне нужно будет начать заново)

Остальные волонтеры приветствуются! Надеюсь, я не украл кислород у кого-то, сказав, что буду работать над этим, а затем не смог выполнить :(

Чтобы добавить к истории @metatick :

В настоящее время я использую Gigalixir в качестве хоста, работающего поверх Kubernetes. Это веб-приложение. Иногда клиенты загружают пачку фотографий, поэтому мое приложение запускает кучу (тьфу) процессов ImageMagick для изменения их размера. Пики использования памяти, срабатывает убийца OOM, и мое приложение отключается (ненадолго), и загрузка прерывается.

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

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

Пожалуйста исправьте. :)

Для меня это тоже очень большая проблема. В моем случае использования мне нужно было бы запускать модули, которые большую часть времени используют ~ 100 МБ, но время от времени, когда пользователь запускает определенные события, он может увеличивать до 2 ГБ ОЗУ на несколько минут, прежде чем откатиться (и нет, дело не в том, что написано плохо, а в реальности загруженности).
Я выполняю почти сотню таких рабочих нагрузок одновременно на машинах объемом 16 ГБ со свопингом. Я просто не могу перенести эту рабочую нагрузку в Kubernetes, потому что это вообще не сработает. Итак, прямо сейчас у меня есть собственный оркестратор, который запускает эти рабочие нагрузки в системах, отличных от кубернетов, в то время как мое основное приложение работает в Kubernetes, и это сводит на нет цель моего перехода на k8s. Без подкачки он либо убивается, либо мне всегда нужно тратить много доступной оперативной памяти на несколько минут, когда приложения могут (или не могут) взорваться.

Если вы можете установить ограничение ЦП, которое ограничивает ЦП для модуля, вы должны иметь возможность установить ограничение памяти, которое ограничивает объем памяти, используемый модулем. Убивать модуль, когда он достигает предела памяти, так же нелепо, как убивать один, если он использует больше ресурсов ЦП, чем было установлено ограничение ЦП (извините, но не каждый модуль является репликой, которую можно отключить без последствий).

Kubernetes не может работать с подкачкой, установленной на узле, потому что это может повлиять на всю производительность всего кластера, хорошо (хотя я не думаю, что это верный аргумент). В идеале, что должно произойти, так это то, что у самого модуля будет файл подкачки на уровне модуля, в котором будут заменяться только процессы в этих контейнерах. Это теоретически ограничит использование ОЗУ и производительность (из-за подкачки) модулей, которые превышают их пределы памяти, точно так же, как ограничения ЦП ограничивают их.
К сожалению, не похоже, что cgroups могут указывать файл подкачки, только их подкачку, и вы не можете сказать ядру, что нужно «поменять местами, если использование памяти выше этого предела», поскольку вместо этого оно, кажется, решает, когда производить подкачку на основе последнего доступ и другие метрики.

Но тем временем, почему бы не позволить свопу существовать на узле, установить swappiness на 0 для модулей, для которых не установлен предел, а когда установлен предел (или какое-либо другое поле спецификации, чтобы сказать "swapInsteadOfKill"), установите замена на ненулевое значение?

Помимо обсуждения «менять или не менять местами», мне любопытно, что поведение, описанное @ pai911, больше не рассматривалось командой k8s.

Я могу подтвердить, что kubelet, похоже, ведет себя по-другому (и в некоторых ОС не в соответствии с фрагментом кода, упомянутым выше) в отношении настроек памяти docker deamon. Наши кластеры работают на SUSE linux, и мы испытываем такое же неограниченное использование подкачки, как указано в https://github.com/kubernetes/kubernetes/issues/53533#issuecomment -598056151

Сведения об ОС: SUSE Linux Enterprise Server 12 SP4 - Linux 4.12.14-95.45-default

В любом случае без надлежащей поддержки Swap в k8s мне бы хотелось, чтобы kubelet последовательно обрабатывал настройки памяти Docker независимо от базовой ОС.

Я включил обмен в повестку дня, чтобы узнать, есть ли у сообщества желание или добровольцы, которые помогут продвинуть это вперед в 1.21. У меня нет возражений против поддержки свопа, как я отмечал в 2017 году, просто нужно убедиться, что вы не путаете вытеснение кубелета, приоритет пода, качество обслуживания пода, и, что важно, поды должны иметь возможность сказать, допускают ли они своп или нет. Все это важно для обеспечения портативности капсул.

В последнее время много энергии было сосредоточено на том, чтобы заставить работать такие вещи, как память, выровненная по NUMA, но если есть люди, которые менее чувствительны к производительности и одинаково мотивированы, чтобы помочь продвинуть это пространство вперед, мы хотели бы помочь получить фору при проектировании подробный KEP в этом пространстве.

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

Была ли эта страница полезной?
0 / 5 - 0 рейтинги