# k8s Memory

Источник: https://ealebed.github.io/posts/2019/ресурсы-в-kubernetes-часть-1-memory/

### Пример

```yaml
# Ваш контейнер в Pod
resources:
  requests:
    memory: "500Mi"    # → memory.min в cgroup v2
  limits:
    memory: "1Gi"      # → memory.high в cgroup v2
```

### Что делает cgroups в данном примере?

* Резервирует 500MB (memory.min) — эта память ВСЕГДА доступна;

* Разрешает использовать до 1GB (memory.high);

* Если контейнер использует 900MB → начинает мягко ограничивать;

* Если использует 500MB — всё работает на полной скорости.

### Что означает память (memory) в данном контексте? 

В нашем случае, это общее значение размера страниц памяти (Resident set size, RSS) и использования кэша страниц (page cache) контейнерами.

Примечание. В “чистом” docker’е в это значение также входит своп (swap), который предусмотрительно отключен в Kubernetes.

RSS - размер страниц памяти, выделенных процессу операционной системой и в настоящее время находящихся в ОЗУ. Н/р, для Java процесса это [heap (куча)](/3%20Memory%20and%20Concurrency/3.1%20Memory/3.1.2%20RandomAccessMemory/3.1.2.3%20Heap.md), [non-heap (стек)](/3%20Memory%20and%20Concurrency/3.1%20Memory/3.1.2%20RandomAccessMemory/3.1.2.2%20Stack.md) [память](/3%20Memory%20and%20Concurrency/3.1%20Memory/3.1.1%20AboutMemory/3.1.1.1%20Memory.md), оff-heap (она же native memory) и т. д.

Кэш страниц - иногда также называемый дисковый кэшем, используется для кеширования блоков с HDD/SSD. Все операции ввода/вывода обычно происходят через этот кэш (из соображений производительности). Чем больше данных читает/записывает ваше приложение на диск, тем больший объем памяти необходим для кэша страниц. Ядро будет использовать доступную память для кэша страниц, но будет освобождать ее, если память понадобится в другом месте/процессе - таким образом производительность вашего приложения может снижаться при недостаточном объеме оперативной памяти.

Исходя из документации docker, можно сказать, что размер кэша страниц, используемых контейнером, может сильно отличаться в зависимости от того, могут ли некоторые файлы “поделены” между несколькими контейнерами, запущенными на одном рабочем узле (достигается благодаря overlayfs storage driver).

## Проверить данные

Информацию активного пода по `memory` можно получить по пути: `/sys/fs/cgroup/memory/memory.stat` для cgroupsV1 или `cat /sys/fs/cgroup/memory.stat` для cgroupsV2.

Вывод:

| Метрика | Значение (байты/события) | Человеческий формат | Что это значит |
|---------|--------------------------|---------------------|----------------|
| **anon** | 670 474 240 Б | **639.4 МБ** | Анонимная память (куча, стек) — основная память приложения. Выделена под данные, не связанные с файлами. |
| **file** | 32 768 Б | **32 КБ** | Файловый кеш — страницы с данными из файлов на диске. Мало, значит приложение почти не читает файлы. |
| kernel_stack | 1 163 264 Б | **1.1 МБ** | Память под стеки ядра для каждого потока. Растёт с количеством потоков в контейнере. |
| pagetables | 2 080 768 Б | **2.0 МБ** | Таблицы страниц — накладные расходы виртуальной памяти. Высокое значение может указывать на фрагментацию памяти. |
| percpu | 0 Б | **0 Б** | Per-CPU память, выделенная под данные, локальные для каждого ядра процессора. |
| sock | 24 576 Б | **24 КБ** | Буферы сокетов — память под сетевые соединения. Растёт с количеством открытых соединений. |
| shmem | 0 Б | **0 Б** | Разделяемая память (tmpfs, shared memory segments). Используется для межпроцессного взаимодействия. |
| file_mapped | 32 768 Б | **32 КБ** | Отображённые файлы (библиотеки, бинарники). Те же 32 КБ из file, но замапленные в адресное пространство. |
| file_dirty | 12 288 Б | **12 КБ** | Грязные страницы — изменённые данные, которые ещё не записаны на диск. |
| file_writeback | 0 Б | **0 Б** | Страницы в процессе записи на диск. Активно, когда система сбрасывает dirty-страницы. |
| swapcached | 0 Б | **0 Б** | Страницы, вытесненные в swap и затем прочитанные обратно, но всё ещё хранящиеся в swap-кэше. |
| **inactive_anon** | 670 408 704 Б | **639.3 МБ** | Неактивная анонимная память — кандидат на вытеснение в swap. Память выделена, но давно не использовалась. |
| **active_anon** | 32 768 Б | **32 КБ** | Активная анонимная память — недавно использовалась, не подлежит вытеснению. |
| inactive_file | 32 768 Б | **32 КБ** | Неактивный файловый кеш — кандидат на освобождение. Страницы, к которым давно не обращались. |
| active_file | 0 Б | **0 Б** | Активный файловый кеш — недавно использовался, не будет вытесняться. |
| unevictable | 0 Б | **0 Б** | Невытесняемая память (mlock, ramfs, секреты). Не может быть вытеснена даже под давлением памяти. |
| slab_reclaimable | 317 352 Б | **310 КБ** | Slab-память, которую можно вернуть (кэши inode/dentry). При необходимости ядро может её освободить. |
| slab_unreclaimable | 937 264 Б | **915 КБ** | Slab-память, которую нельзя вернуть (структуры ядра, драйверы). Постоянные накладные расходы. |
| slab | 1 254 616 Б | **1.2 МБ** | Общая Slab-память (reclaimable + unreclaimable). Кэши различных объектов ядра. |
| workingset_refault_anon | 0 | 0 раз | Возврат страниц анонимной памяти из swap. Высокое значение = память вытесняется, но снова требуется. |
| workingset_refault_file | 0 | 0 раз | Возврат страниц файлового кеша с диска. Высокое значение = недостаточно RAM для файлового кеша. |
| workingset_activate_anon | 0 | 0 раз | Активация анонимных страниц после refault. Страница была вытеснена, затем срочно понадобилась. |
| workingset_activate_file | 0 | 0 раз | Активация файловых страниц после refault. Страница была вытеснена, затем снова запрошена. |
| pgfault | 407 665 | 407.7k раз | Всего page faults (обычные + minor). Каждое обращение к новой странице памяти. |
| pgmajfault | 0 | 0 раз | **Критично!** Major faults — обращения к диску. Нулевое значение — отлично, диск не тормозит работу. |
| pgrefill | 0 | 0 раз | Страницы, перемещённые из active в inactive список реклаймером. Подготовка к вытеснению. |
| pgscan | 0 | 0 раз | Страницы, просканированные реклаймером в поисках кандидатов на освобождение. |
| pgsteal | 0 | 0 раз | Страницы, успешно освобождённые реклаймером. Ноль = память не освобождалась. |
| pgactivate | 2 | 2 раза | Страницы, перемещённые из inactive в active список. Указывает на повторное обращение к старым страницам. |
| pgdeactivate | 0 | 0 раз | Страницы, перемещённые из active в inactive список. Подготовка к возможному вытеснению. |
| pglazyfree | 0 | 0 раз | Ленивое освобождение страниц (KSM). Пометка страниц как доступных для объединения. |
| pglazyfreed | 0 | 0 раз | Страницы, освобождённые лениво и позже повторно использованные. |
| thp_fault_alloc | 0 | 0 раз | Выделение Transparent Huge Pages при page fault. Улучшает производительность для больших областей памяти. |
| thp_collapse_alloc | 0 | 0 раз | Объединение обычных 4КБ страниц в 2МБ Huge Page. Фоновый процесс khugepaged. |


В cgroupsV2:
* `memory.max` — это жесткий лимит (limits.memory). `anon` из `memory.stat` показывает текущее потребление;
* `memory.low/memory.min` — это вроде как должно быть requests.memory. **Но! в k8s не записывается.** Ядро не умеет "резервировать" память.

### Inside Pod

Описание анализа внутренностей поды: [ссылка](https://gist.github.com/eldaroid/f759ccb490d8a80e004b4af9d18d2f94)

----------

[4.3.6.6.1 k8s CPU Theme](./4.3.6.6.1%20k8sCPU.md) | [Back To iTWiki Contents](https://github.com/eldaroid/iTWiki) | [4.3.6.6.3 k8s Thread And Heap Dump Theme](./4.3.6.6.3%20k8sThreadAndHeapDump.md)