Compare commits

...

7 Commits

5 changed files with 180 additions and 0 deletions

View File

@ -0,0 +1,28 @@
---
title: Ограничение использования диска
description:
published: true
date: 2024-08-09T07:39:28.081Z
tags: limit, disk
editor: markdown
dateCreated: 2024-08-09T07:39:28.081Z
---
Стал регулярно сталкиваться с одной проблемой. Есть сервер с бюджетными SSD дисками. Они для многих задач вполне подходят, несмотря на низкую стоимость и скорость записи. Последнее как раз их узкое место. Но если у вас в основном с дисков чтение, то можно существенно экономить, используя десктопные диски.
У меня как раз такой случай. Несколько виртуалок под веб сервера, где в основном чтение из кэшей на дисках. По производительности никаких нареканий, кроме одного момента. Когда дампишь для бэкапов базы данных, весь гипервизор начинает прилично тормозить, а в мониторинг сыпятся уведомления о медленном ответе веб сервера и увеличении отклика дисков. Обычно это происходит ночью и особых проблем не доставляет. Но тем не менее, решил это исправить.
Самый простой способ в лоб - ограничить скорость пайпа, через который данные с mysqldump записываются в файл. По умолчанию всё читается и пишется параллельными потоками с одних и тех же SSD. Десктопные диски такой режим очень не любят и заметно тормозят при выполнении.
Я использовал утилиту pv:
```
# apt install pv
# mysqldump --opt -v --single-transaction --databases db01 | pv -L 20m > /mnt/backup/db01.sql
```
Ограничил скорость записи в 20 MiB/s через ключ -L. Для того, чтобы посмотреть текущую скорость записи, используйте pv без ограничения:
```
# mysqldump --opt -v --single-transaction --databases db01 | pv > /mnt/backup/db01.sql
............................
 1319MiB 0:00:06 [ 205MiB/s]
```
Вообще pv интересная утилита. Стоит написать о ней отдельно. Если знаете ещё какие-то способы решения этой задачи, поделитесь в комментариях. Если дампишь сразу по сети, то можно скорость сетевой передачи ограничивать. А вот так, чтобы локально, больше ничего в голову не приходит. Разве что жать сразу на лету с сильной компрессией, чтобы медленно было. Но это как-то муторно подбирать подходящую скорость.

View File

@ -0,0 +1,71 @@
---
title: Ограничение использования диска, вариант 2
description:
published: true
date: 2024-08-09T07:42:49.725Z
tags: limit, disk
editor: markdown
dateCreated: 2024-08-09T07:42:49.725Z
---
Первый вариант - [Disk-limit](/sysadmin/Linux/Base-znaniy/Disk-limit)
Недавно делал заметку (https://t.me/srv_admin/3817) про ограничение использования диска при создании дампов базы данных, чтобы не вызывать замедление всех остальных процессов в системе. Использовал утилиту pv (https://t.me/srv_admin/3823). Способ простой и рабочий, я его внедрил и оставил. Поставленную задачу решает.
Тем не менее, захотелось сделать это более изящно через использование приоритетов. Если диск не нагружен, то неплохо было бы его использовать с максимальной производительностью. А если нагружен, то отдать приоритет другим процесса. Это был бы наиболее рациональный и эффективный способ.
Я знаю утилиту ionice, которая в большинстве дистрибутивов есть по умолчанию. Она как раз существует для решения именно этой задачи. У неё не так много параметров, так что пользоваться ей просто. Приоритет можно передать через ключи. Для этого нужно задать режим работы:
Idle - идентификатор 1, процесс работает с диском только тогда, когда он не занят
Best effort - идентификатор 2, стандартный режим работы с возможностью выставления приоритета от 0 до 7 (0 - максимальный)
Real time - режим работы реального времени тоже с возможностью задавать приоритет от 0 до 7
На практике это выглядит примерно так:
```
# ionice -c 3 cp tempfile ~/
```
Скопировали tempfile в домашний каталог в режиме idle. По идее, это то, что нужно. На практике этот приоритет не работает. Провёл разные тесты и убедился в том, что в Debian 12 ionice не работает вообще. Стал копать, почему так.
В Linux системах существуют разные планировщики процессов в отношении ввода-вывода. Раньше использовался Cfq, и ionice работает только с ним. В современных системах используется более эффективный планировщик Deadline. Проверить планировщик можно так:
```
# cat /sys/block/sda/queue/scheduler
[none] mq-deadline
```
Принципиальная разница этих планировщиков в том, что cfq равномерно распределяет процессы с операциями ввода-вывода, и это нормально подходит для hdd, а deadline отдаёт приоритет чтению в ущерб записи, что в целом уменьшает отклик для ssd дисков. С ними использовать его более рационально. Можно заставить работать ionice, но тогда придётся вернуть планировщик cfq, что не хочется делать, если у вас ssd диски.
Для планировщика deadline не смог найти простого и наглядного решения приоритизации процессов записи на диск. Стандартным решением по ограничению скорости, по типу того, что делает pv, является использование параметров systemd:
- **IOReadBandwidthMax** - объём данных, который сервису разрешается прочитать с блочных устройств за одну секунду;
- **IOWriteBandwidthMax** - объём данных, который сервису разрешается записать на блочные устройства за одну секунду.
Причём у него есть также параметр IODeviceWeight, что является примерно тем же самым, что и приоритет. Но работает он тоже только с cfq.
Для того, чтобы ограничить скорость записи на диск с помощью systemd, необходимо создать юнит для этого. Покажу на примере создания тестового файла с помощью dd с ограничением скорости записи в 20 мегабайт в секунду.
```
[Unit]
Description=Create file with dd
[Service]
IOWriteBandwidthMax=/dev/sda 20M
ExecStart=/usr/bin/dd if=/dev/zero of=/tempfile bs=1M count=1000 oflag=sync
[Install]
WantedBy=multi-user.target
```
Запускаем:
```
# systemctl start createfile.service
```
Проверяем:
```
# systemctl status createfile.service
systemd[1]: Started createfile.service - Create file with dd.
dd[1423]: 1000+0 records in
dd[1423]: 1000+0 records out
dd[1423]: 1048576000 bytes (1.0 GB, 1000 MiB) copied, 52.417 s, 20.0 MB/s
systemd[1]: createfile.service: Deactivated successfully.
```
Это можно использовать как заготовку для реального задания. Если хочется потестировать в консоли, то запускайте так:
```
# systemd-run --scope -p IOWriteBandwidthMax='/dev/sda 20M' dd status=progress if=/dev/zero of=/tempfile bs=1M count=1000 oflag=sync
```
Простое рабочее решение без использования дополнительных утилит. Обращаю внимание, что если сработает кэширование записи, то визуально ограничение можно не увидеть. Я это наблюдал. И только с флагом sync её хорошо сразу же видно.
![disk-limit.png](/sysadmin/img/disk-limit.png)

View File

@ -0,0 +1,81 @@
---
title: Ограничение потребления памяти процессу
description:
published: true
date: 2024-08-09T07:34:35.655Z
tags: memory, limit
editor: markdown
dateCreated: 2024-08-09T07:34:35.655Z
---
Если вам нужно ограничить процессу потребление памяти, то с systemd это сделать очень просто. Причём там есть гибкие варианты настройки. Вообще, все варианты ограничения ресурсов с помощью systemd описаны в [документации](https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html). Там внушительный список. Покажу на примере памяти, какие настройки за что отвечают.
MemoryAccounting=1
Включение подсчёта памяти (Turn on process and kernel memory accounting for this unit)
MemoryHigh=16G
Это основной механизм ограничения потребления памяти (This is the main mechanism to control memory usage of a unit). Указанный лимит может быть превышен, если это необходимо, но процесс при этом будет замедляться, а память у него активно забираться назад.
MemoryMax=20G
Жёсткий лимит по потреблению памяти. Если процесс до него дойдет, то он будет завершён OOM Killer. В общем случае этот лимит лучше не использовать, только в крайних случаях, чтобы сохранить работоспособность системы.
MemorySwapMax=3G
Ограничение по использованию swap.
Restart=on-abnormal
Параметр не имеет отношения к потреблению памяти, но добавил сюда для справки. Если хотите, чтобы процесс перезапускался автоматически после того, как его прибьют по превышению MemoryMax, то используйте этот параметр.
OOMPolicy=stop
Тоже косвенный параметр, который устанавливает то, как OOM Killer будет останавливать процесс. Либо это будет попытка корректно остановить процесс через stop, либо он его просто прибьёт через kill. Выбирайте в зависимости от того, что ограничиваете. Если у процесса жор памяти означает, что он завис и его надо прибить, то ставьте kill. А если он ещё живой и может быть остановлен, тогда stop.
Параметры эти описываются в секции юнита [Service] примерно так:
```
[Unit]
Description=Python Script
After=network.target
[Service]
WorkingDirectory=/opt/run
ExecStart=/opt/run/scrape.py
Restart=on-abnormal
MemoryAccounting=1
MemoryHigh=16G
MemoryMax=20G
MemorySwapMax=3G
OOMPolicy=stop
[Install]
WantedBy=multi-user.target
```
Потестировать лимиты можно в консоли. Для примера возьмём python и съедим гигабайт памяти:
```
# python3 -c 'a="a"*1024**3; input()'
```
Команда будет висеть без ошибок, по По ps или free -m будет видно, что скушала 1G оперативы.
Теперь зажимаем её:
```
# systemd-run --scope -p MemoryMax=256M -p MemoryHigh=200M python3 -c 'a="a"*1024**3; input()'
```
Процесс работает, но потребляет разрешённые ему 200M. На практике чуть меньше. Смотрим через pmap:
```
# ps ax | grep python
  767 pts/0  S+   0:00 /usr/bin/python3 -c a="a"*1024**3; input()
# pmap 767 -x | grep total
total kB     1065048 173992 168284
```
Значения в килобайтах. Первое - виртуальная память (VSZ), сколько процесс запросил, столько получил. Занял весь гигабайт. Второе значение - RSS, что условно соответствует реальному потреблению физической памяти, и тут уже работает лимит. Реальной памяти процесс потребляет не больше лимита.
RSS можно ещё вот так быстро глянуть:
```
# ps -e -o rss,args --sort -rss
```
Вообще, с памятью у Linux всё непросто. Кому интересно, я как-то пытался в этом разобраться и [рассказать простым языком] (https://t.me/srv_admin/2859).
Systemd удобный инструмент в плане управления лимитами процессов. Легко настраивать и управлять.
Считаю, что эта заметка достойна того, чтобы быть сохранённой в избранном.
![memory-limit.png](/sysadmin/img/memory-limit.png)

BIN
sysadmin/img/disk-limit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 KiB