Керування cвоп-памʼяттю
Kubernetes може бути налаштовано на використання памʼяті підкачки на вузлі, що дозволяє ядру звільняти фізичну памʼять, підкачуючи сторінки до резервного сховища. Це корисно для багатьох випадків використання. Наприклад, вузли, на яких виконуються робочі навантаження, що можуть отримати вигоду від використання свопу, наприклад, ті, що займають багато памʼяті, але мають доступ лише до частини цієї памʼяті у будь-який момент часу. Це також допомагає запобігти завершенню роботи Podʼів під час стрибків тиску на памʼять, захищає вузли від системних стрибків памʼяті, які можуть порушити стабільність роботи, дозволяє гнучкіше керувати памʼяттю на вузлі та багато іншого.
Щоб дізнатися про налаштування свопу у вашому кластері, прочитайте Налаштування своп-памʼяті на вузлах Kubernetes.
Підтримка операційних систем
- Вузли Linux підтримують своп; для його увімкнення потрібно налаштувати кожен вузол. Стандартно kubelet не запускається на вузлі Linux, на якому увімкнено своп.
- Вузли Windows потребують простору для свопу. Стандартно kubelet не запускається на вузлі Windows, на якому вимкнено своп.
Як це працює?
Існує кілька можливих способів, якими можна уявити використання свопу на вузлі. Якщо kubelet вже працює на вузлі, його потрібно буде перезапустити після налаштування свопу, щоб він міг його виявити.
Коли kubelet запускається на вузлі, на якому налаштовано та доступно своп (з конфігурацією failSwapOn: false), kubelet буде:
- Мати можливість запускатися на цьому вузлі з увімкненим свопом.
- Направляти реалізацію Container Runtime Interface (CRI), часто звану контейнерним середовищем, щоб стандартно виділяти нульову памʼять свопу для робочих навантажень Kubernetes.
Конфігурація свопу на вузлі доступна для адміністратора кластера через memorySwap в KubeletConfiguration. Як адміністратор кластера, ви можете вказати поведінку вузла в присутності своп-памʼяті, встановивши memorySwap.swapBehavior.
Поведінка свопу
Вам потрібно вибрати поведінку свопу для використання. Різні вузли у вашому кластері можуть використовувати різну поведінку свопу.
Поведінка свопу, яку ви можете вибрати для вузлів Linux, є такою:
NoSwap(стандартно)- Робочі навантаження, що виконуються як Podʼи на цьому вузлі, не використовують і не можуть використовувати своп.
LimitedSwap- Робочі навантаження Kubernetes можуть використовувати своп-памʼять.
Примітка:
Якщо ви виберете поведінку NoSwap і налаштуєте kubelet на толерантність до простору свопу (failSwapOn: false), ваші робочі навантаження не використовуватимуть своп.
Однак процеси поза контейнерами, що управляються Kubernetes, такі як системні сервіси (і навіть сам kubelet!), можуть використовувати своп.
Ви можете прочитати конфігурацію своп-памʼяті на вузлах Kubernetes, щоб дізнатися про ввімкнення свопу для вашого кластера.
Container runtime integration
Kubelet використовує API контейнерного середовища та направляє контейнерне середовище на застосування конкретної конфігурації (наприклад, у випадку cgroup v2, memory.swap.max) таким чином, щоб включити бажану конфігурацію свопу для контейнера. Для середовищ виконання, які використовують контрольні групи або cgroups, контейнерне середовище несе відповідальність за запис цих налаштувань у cgroup на рівні контейнера.
Спостережуваність для використання свопу
Статистика метрік рівня Node та контейнер
Kubelet тепер збирає статистику метрик на рівні вузлів і контейнерів, доступ до якої можна отримати за допомогою точок доступу HTTP Kubelet /metrics/resource (яка використовується в основному інструментами моніторингу, такими як Prometheus) і /stats/summary (яка використовується в основному автомасштабувальниками). Це дозволяє клієнтам, які можуть безпосередньо запитувати kubelet, відстежувати використання свопу та залишок памʼяті підкачки при використанні LimitedSwap. Крім того, до cadvisor було додано метрику machine_swap_bytes, яка показує загальний обсяг фізичної памʼяті підкачки на компʼютері. Докладні відомості наведено на цій сторінці.
Наприклад, підтримуються такі /metrics/resource:
node_swap_usage_bytes: Поточне використання свопу вузлом в байтах.container_swap_usage_bytes: Поточна кількість використання свопу контейнером в байтах.container_swap_limit_bytes: Поточна кількість ліміту свопу контейнера в байтах.
Використання kubectl top --show-swap
Запит метрик є цінним, але дещо громіздким, оскільки ці метрики призначені для використання програмним забезпеченням, а не людьми. Щоб споживати ці дані більш зручним способом, команда kubectl top була розширена для підтримки метрик свопу з використанням прапорця --show-swap.
Щоб отримати інформацію про використання свопу на вузлах, можна використовувати kubectl top nodes --show-swap:
kubectl top nodes --show-swap
Це призведе до виводу, подібного до:
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%) SWAP(bytes) SWAP(%)
node1 1m 10% 2Mi 10% 1Mi 0%
node2 5m 10% 6Mi 10% 2Mi 0%
node3 3m 10% 4Mi 10% <unknown> <unknown>
Щоб отримати інформацію про використання свопу контейнерами, можна використовувати kubectl top pod -n kube-system --show-swap:
kubectl top pod -n kube-system --show-swap
Це призведе до виводу, подібного до:
NAME CPU(cores) MEMORY(bytes) SWAP(bytes)
coredns-58d5bc5cdb-5nbk4 2m 19Mi 0Mi
coredns-58d5bc5cdb-jsh26 3m 37Mi 0Mi
etcd-node01 51m 143Mi 5Mi
kube-apiserver-node01 98m 824Mi 16Mi
kube-controller-manager-node01 20m 135Mi 9Mi
kube-proxy-ffgs2 1m 24Mi 0Mi
kube-proxy-fhvwx 1m 39Mi 0Mi
kube-scheduler-node01 13m 69Mi 0Mi
metrics-server-8598789fdb-d2kcj 5m 26Mi 0Mi
Вузли повідомлятимуть про можливості підкачки як частини статусу вузла
Додано нове поле стану вузла node.status.nodeInfo.swap.capacity, щоб повідомити про ємність підкачки вузла.
Наприклад, наступна команда може бути використана для отримання інформації про ємність підкачки вузлів у кластері:
kubectl get nodes -o go-template='{{range .items}}{{.metadata.name}}: {{if .status.nodeInfo.swap.capacity}}{{.status.nodeInfo.swap.capacity}}{{else}}<unknown>{{end}}{{"\n"}}{{end}}'
Це призведе до отримання результату, схожого на
node1: 21474836480
node2: 42949664768
node3: <unknown>
Примітка:
Значення<unknown> вказує на те, що поле .status.nodeInfo.swap.capacity не встановлено для цього вузла. Це, ймовірно, означає, що на вузлі не передбачено свопу, або, що менш ймовірно, що kubelet не може визначити ємність свопу на вузлі.Вивлення свопу за допомогою Node Feature Discovery (NFD)
Node Feature Discovery це надбудова Kubernetes для виявлення апаратних можливостей та конфігурації. Її можна використовувати для виявлення, які вузли мають своп.
Наприклад, щоб зʼясувати, які вузли мають своп, використовуйте наступну команду:
kubectl get nodes -o jsonpath='{range .items[?(@.metadata.labels.feature\.node\.kubernetes\.io/memory-swap)]}{.metadata.name}{"\t"}{.metadata.labels.feature\.node\.kubernetes\.io/memory-swap}{"\n"}{end}'
Це призведе до отримання результату, схожого на:
k8s-worker1: true
k8s-worker2: true
k8s-worker3: false
У цьому прикладі своп передбачено на вузлах k8s-worker1 та k8s-worker2, але не на k8s-worker3.
Ризики та застереження
Увага:
Наполегливо рекомендується шифрувати простір підкачки. Докладніші відомості наведено у розділі Томи з кешем.Наявність у системі свопу знижує передбачуваність. Хоча своп може підвищити продуктивність за рахунок збільшення обсягу оперативної памʼяті, повернення даних назад у памʼять є важкою операцією, іноді повільнішою на багато порядків, що може призвести до неочікуваного зниження продуктивності. Крім того, своп змінює поведінку системи під тиском на памʼять. Увімкнення свопу збільшує ризик появи галасливих сусідів, коли Podʼи, які часто використовують свою оперативну памʼять, можуть спричинити спрацювання свопу в інших Podʼах. Крім того, оскільки у Kubernetes своп дозволяє збільшувати використання памʼяті для робочих навантажень, які неможливо передбачити, а також через непередбачувані конфігурації пакування, планувальник наразі не враховує використання памʼяті свопу. Це підвищує ризик появи галасливих сусідів.
Продуктивність вузла з увімкненою памʼяттю підкачки залежить від фізичного сховища. Коли використовується памʼять підкачки, продуктивність буде значно гіршою в середовищі з обмеженою кількістю операцій вводу/виводу в секунду (IOPS), наприклад, у хмарній віртуальній машині з гальмуванням вводу/виводу, порівняно з більш швидкими носіями даних, такими як твердотільні диски або NVMe. Оскільки своп може спричинити тиск на ввід-вивід, рекомендується надавати вищий пріоритет затримки вводу-виводу для критично важливих для системи демонів. Див. відповідний розділ у розділі рекомендовані практики нижче.
Томи з кешем
На вузлах Linux томи з кешем (такі як secret або emptyDir з medium: Memory) реалізуються за допомогою файлової системи tmpfs. Вміст таких томів повинен залишатися в памʼяті в будь-який час, отже, не повинен бути переміщений на диск. Щоб забезпечити збереження вмісту таких томів у памʼяті, використовується опція noswap для tmpfs.
Ядро Linux офіційно підтримує опцію noswap з версії 6.3 (докладніше можна знайти в Вимогах до версії ядра Linux). Однак різні дистрибутиви часто вирішують повернути цю опцію монтування до старіших версій Linux.
Щоб перевірити, чи підтримує вузол опцію noswap, kubelet виконає такі дії:
- Якщо версія ядра перевищує 6.3, то буде вважатися, що опція
noswapпідтримується. - В іншому випадку kubelet спробує змонтувати фейковий tmpfs з опцією
noswapпід час запуску. Якщо kubelet зазнає збою з помилкою, що вказує на невідому опцію,noswapбуде вважатися не підтримуваною, отже, не буде використовуватися. У журналі kubelet буде виведено запис, щоб попередити користувача про те, що томи з кешем можуть бути переміщені на диск. Якщо kubelet успішно завершить цю операцію, фейковий tmpfs буде видалено, а опціяnoswapбуде використовуватися.- Якщо опція
noswapне підтримується, kubelet виведе запис попередження в журналі, а потім продовжить свою роботу.
- Якщо опція
Див. розділ вище з прикладом налаштування незашифрованого свопу. Однак обробка зашифрованого свопу не входить до сфери відповідальності kubelet; швидше, це загальна проблема конфігурації ОС і повинна бути вирішена на цьому рівні. Адміністратору належить забезпечити зашифрування свопу, щоб зменшити цей ризик.
Виселення
Налаштування порогів вивільнення памʼяті для вузлів з увімкненим свопом може бути складним завданням.
Якщо своп вимкнено, доцільно налаштувати пороги вивільнення памʼяті kubelet трохи нижче, ніж обсяг памʼяті на вузлі. Це повʼязано з тим, що ми хочемо, щоб Kubernetes починав виселяти Podʼи до того, як у вузла закінчиться памʼять і він викличе утиліту Out Of Memory (OOM), оскільки утиліта OOM не знає про Kubernetes, тому не враховує такі речі, як QoS, пріоритет podʼів або інші специфічні для Kubernetes фактори.
З увімкненим свопом ситуація складніша. У Linux параметр vm.min_free_kbytes визначає поріг памʼяті, після досягнення якого ядро починає агресивно вивільняти памʼять, що включає підкачку сторінок. Якщо пороги вивільнення памʼяті у kubelet встановлено таким чином, що воно відбувається до того, як ядро почне вивільняти памʼять, це може призвести до того, що робочі навантаження ніколи не зможуть вивільнити памʼять під час тиску на памʼять на вузлах. Однак, встановлення занадто високих порогів виселення може призвести до вичерпання памʼяті на вузлі та виклику функції OOM, що також не є ідеальним варіантом.
Щоб вирішити цю проблему, рекомендується встановлювати пороги виселення kubelet трохи нижчими за значення vm.min_free_kbytes. Таким чином, вузол може почати підкачку до того, як kubelet почне виселяти Podʼи, дозволяючи робочим навантаженням обмінюватися невикористаними даними і запобігаючи виселенню. З іншого боку, оскільки це значення трохи нижче, kubelet, швидше за все, почне виселяти Podʼи до того, як вузол вичерпає свої ресурси
cat /proc/sys/vm/min_free_kbytes
Невикористаний простір свопу
У режимі LimitedSwap обсяг памʼяті, доступної для Podʼа, визначається автоматично, виходячи з частки запитуваної памʼяті відносно загального обсягу памʼяті вузла (докладніше див. розділ нижче).
Така конструкція означає, що зазвичай для робочих навантажень Kubernetes залишатиметься певна частина памʼяті, яку буде обмежено. Наприклад, оскільки Kubernetes 1.34 не дозволяє використовувати своп для Podʼів в Guaranteed QoS class, обсяг свопу, пропорційний запиту на памʼять для Guaranteed podʼів, залишатиметься невикористаним робочими навантаженнями Kubernetes.
Така поведінка несе в собі певний ризик у ситуації, коли багатьом podʼам не дозволено використовувати свопінг. З іншого боку, це ефективно зберігає деякий зарезервований системою обсяг памʼяті підкачки, який може бути використаний процесами поза межами Kubernetes, такими як системні демони і навіть сам kubelet.
Рекомендації щодо використання свопу в кластері Kubernetes
Вимкнення свопу для критично важливих системних демонів
Під час тестування та на основі відгуків користувачів було виявлено, що продуктивність критично важливих демонів і служб може знижуватися. Це означає, що системні демони, включаючи kubelet, можуть працювати повільніше, ніж зазвичай. Якщо це питання виникає, рекомендується налаштувати cgroup системного слайсу щоб запобігти свопінгу (тобто, встановити memory.swap.max=0).
Захист критично важливих демонів системи від затримок I/O
Своп може збільшити навантаження на I/O на вузлі. Коли тиск на памʼять змушує ядро швидко свопити сторінки, системні демони і служби, які покладаються на операції I/O, можуть зіштовхнутися зі зниженням продуктивності.
Щоб помʼякшити цю ситуацію, рекомендується для користувачів systemd пріоритизувати системний слайс з точки зору затримки I/O. Для користувачів, які не використовують systemd, рекомендується налаштувати окремий cgroup для системних демонів і процесів та пріоритизувати затримку I/O таким же чином. Це можна досягти, встановивши io.latency для системного слайсу, тим самим надаючи йому вищий пріоритет I/O. Дивіться документацію cgroup для отримання додаткової інформації.
Своп та вузли панелі управління
Проєкт Kubernetes рекомендує запускати вузли панелі управління без будь-якого налаштованого свопу. Панель управління в основному містить Podʼи з Guaranteed QoS, тому своп зазвичай можна вимкнути. Основна проблема полягає в тому, що свопінг критично важливих служб на панелі управління може негативно вплинути на продуктивність.
Використання виділеного диска для свопу
Проєкт Kubernetes рекомендує використовувати зашифрований своп, коли ви запускаєте вузли з увімкненим свопом. Якщо своп розташований на розділі або кореневій файловій системі, робочі навантаження можуть заважати системним процесам, які потребують запису на диск. Коли вони використовують один і той же диск, процеси можуть перевантажити своп, порушуючи I/O kubelet, контейнерного середовища та systemd, що вплине на інші робочі навантаження. Оскільки простір свопу розташований на диску, важливо забезпечити, щоб диск був достатньо швидким для запланованих випадків використання. Альтернативно, можна налаштувати пріоритети I/O між різними змонтованими областями одного пристрою зберігання.
Планування з урахуванням свопу
Kubernetes 1.34 не підтримує розподіл Podʼів між вузлами у спосіб, що враховує використання памʼяті підкачки. Планувальник зазвичай використовує запити на ресурси інфраструктури для керування розміщенням Podʼів, а Podʼи не запитують простір підкачки; вони лише запитують memory. Це означає, що планувальник не враховує памʼять підкачки при прийнятті рішень щодо планування. Хоча ми активно працюємо над цим, це ще не реалізовано.
Для того, щоб адміністратори могли гарантувати, що Podʼи не плануватимуться на вузлах з памʼяттю підкачки, якщо вони спеціально не призначені для її використання, адміністратори можуть позначити вузли з доступною памʼяттю підкачки, щоб захиститися від цієї проблеми. Таке позначення гарантує, що робочі навантаження, які допускають використання кешу, не перекидатимуться на вузли без кешу під навантаженням.
Вибір сховища для оптимальної продуктивності
Пристрій зберігання, призначений для простору підкачки, є критично важливим для підтримки чутливості системи під час високого використання памʼяті. Звичайні жорсткі диски (HDD) не підходять для цієї задачі, оскільки їх механічна природа вводить значну затримку, що призводить до серйозного зниження продуктивності та коливання системи. Для сучасних вимог до продуктивності, таким пристроєм, як твердотільний накопичувач (SSD), ймовірно, є відповідним вибором для свопу, оскільки його електронний доступ з низькою затримкою мінімізує сповільнення.
Детальна інформація про поведінку свопу
Як визначається ліміт свопу з LimitedSwap?
Конфігурація памʼяті підкачки, включаючи її обмеження, є значним викликом. Вона не тільки схильна до неправильного налаштування, але як властивість на рівні системи, будь-яке неправильне налаштування може потенційно скомпрометувати весь вузол, а не лише конкретне робоче навантаження. Щоб зменшити цей ризик і забезпечити справність вузла, ми реалізували своп з автоматичною конфігурацією обмежень.
За допомогою параметра LimitedSwap Podʼів, які не підпадають під класифікацію Burstable QoS (тобто BestEffort/Guaranteed QoS Pods), заборонено використовувати памʼять підкачки. QoS-поди BestEffort демонструють непередбачувані шаблони споживання памʼяті та не мають інформації про її використання, що ускладнює визначення безпечного розподілу памʼяті підкачки. І навпаки, QoS-поди Guaranteed зазвичай використовуються для застосунків, які покладаються на точний розподіл ресурсів, визначених робочим навантаженням, з негайним наданням памʼяті. Щоб підтримувати вищезгадані гарантії безпеки та працездатності вузла, цим Podʼам не дозволяється використовувати памʼять підкачки, коли діє LimitedSwap. Крім того, високопріоритетним podʼам заборонено використовувати памʼять підкачки, щоб гарантувати, що памʼять, яку вони споживають, завжди знаходиться на диску, а отже, завжди готова до використання.
Перш ніж детально описати обчислення ліміту памʼяті підкачки, необхідно визначити наступні терміни:
nodeTotalMemory: Загальний обсяг фізичної памʼяті, доступної на вузлі.totalPodsSwapAvailable: Загальний обсяг памʼяті підкачки на вузлі, доступний для використання Podʼам (частина памʼяті підкачки може бути зарезервована для системного використання).containerMemoryRequest: Запит памʼяті контейнера.
Обмеження памʼяті підкачки налаштовується як: ( containerMemoryRequest / nodeTotalMemory ) × totalPodsSwapAvailable.
Іншими словами, обсяг памʼяті підкачки, яку може використовувати контейнер, пропорційний його запиту памʼяті, загальному обсягу фізичної памʼяті вузла та загальному обсягу памʼяті підкачки на вузлі, яка доступна для використання Podʼами.
Важливо зазначити, що для контейнерів у Podʼах з Burstable QoS можливо відмовитися від використання памʼяті підкачки, вказавши запити памʼяті, які дорівнюють лімітам памʼяті. Контейнери, налаштовані таким чином, не матимуть доступу до памʼяті підкачки.
Що далі
- Щоб дізнатися про управління свопом на вузлах Linux, прочитайте Налаштування своп-памʼяті на вузлах Kubernetes.
- Ви можете переглянути допис у блозі про Kubernetes та swap
- Для отримання додаткової інформації, будь ласка, перегляньте оригінальний KEP, KEP-2400, та його дизайн.