Выделенный сервер под базу данных: железо и настройка
База данных упирается в три вещи по порядку: объём памяти, задержку диска на fsync и частоту ядра. Рабочий набор данных должен помещаться в RAM, журнал транзакций — лежать на NVMe, а массив быть RAID1 или RAID10, но не RAID5. Память обязательно ECC: тихая ошибка в буферном пуле уходит на диск как повреждённая страница.
- Память важнее ядер: пока рабочий набор влезает в пул, база читает из RAM, а не с диска.
- NVMe против SATA SSD даёт разы на случайной записи 8–16 KB — это профиль журнала и страниц базы.
- RAID10 для записи, RAID1 для пары дисков; RAID5 платит чтением и двумя записями на каждый изменённый блок.
- ECC-память есть на всех тарифах ZevsHost; для базы это обязательное требование, а не опция.
- Половина «медленной базы» лечится индексами и innodb_buffer_pool_size, а не сменой сервера.
Что брать из железа
| Компонент | Почему он критичен | Ориентир |
|---|---|---|
| RAM | Буферный пул держит горячие страницы | 1,3–1,5 объёма горячих данных, минимум 16 GB |
| Диски | fsync журнала выполняется синхронно на каждом коммите | NVMe; SATA SSD только под небольшую нагрузку |
| CPU | Один запрос выполняется одним ядром | Частота выше числа ядер, если запросы тяжёлые |
| RAID | Отказ диска не должен останавливать базу | RAID1 на два диска, RAID10 на четыре |
| Память ECC | Битая страница из RAM записывается на диск как валидная | Обязательно, DDR4 ECC |
Разница между накопителями разобрана в статье про NVMe, SATA SSD и HDD, выбор уровня массива — в материале про уровни RAID. Под базу берут Pro (32 GB, 2×1 TB NVMe, RAID1) или Enterprise US (64 GB, 4×1 TB NVMe, RAID10); список — на странице выделенных серверов.
Настройка MySQL и MariaDB
Где кроме базы почти ничего нет, буферному пулу отдают 60–70% памяти. Остальное уходит соединениям, временным таблицам и кешу.
# /etc/mysql/mariadb.conf.d/60-tuning.cnf
[mysqld]
# 32 GB сервер: пул примерно 20 GB
innodb_buffer_pool_size = 20G
innodb_buffer_pool_instances = 8
# 1 = полная долговечность, транзакция не теряется
innodb_flush_log_at_trx_commit = 1
innodb_log_file_size = 2G
innodb_flush_method = O_DIRECT
# NVMe выдерживает намного больше, чем значение по умолчанию
innodb_io_capacity = 4000
innodb_io_capacity_max = 8000
max_connections = 300
tmp_table_size = 256M
max_heap_table_size = 256M
# восстановление дампа и проверка реального размера пула
systemctl restart mariadb
mysql -u root -p mydb < /backup/mydb.sql
mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
# доля попаданий в пул: смотрим Innodb_buffer_pool_reads против ..._read_requests
mysql -u root -p -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';" 2>&1 | tee pool.txt
Если Innodb_buffer_pool_reads растёт на установившейся нагрузке, горячие данные не помещаются в пул: добавляйте память или сокращайте выборки. Установка и права — в статье про настройку MariaDB.
Настройка PostgreSQL
PostgreSQL делит память иначе: shared_buffers берут около 25% RAM, а effective_cache_size выставляют в 60–75% как подсказку планировщику.
# postgresql.conf, сервер с 32 GB
shared_buffers = 8GB
effective_cache_size = 24GB
maintenance_work_mem = 2GB
work_mem = 32MB
wal_buffers = 64MB
max_wal_size = 8GB
checkpoint_completion_target = 0.9
# NVMe: случайное чтение почти не дороже последовательного
random_page_cost = 1.1
effective_io_concurrency = 200
synchronous_commit = on
# применяем и проверяем, что значения приняты
systemctl restart postgresql
sudo -u postgres psql -c "SHOW shared_buffers;" -c "SHOW random_page_cost;"
# восстановление из дампа
sudo -u postgres psql mydb < /backup/mydb.sql
sudo -u postgres pg_restore -d mydb -j 4 /backup/mydb.dump 2>&1 | tail -20
Соединения, аутентификация и автовакуум разобраны в статье про PostgreSQL на сервере.
Как проверить, что диск тянет базу
Тест должен повторять профиль базы: случайная запись блоками 16 KB с fsync, а не последовательное чтение.
# профиль, близкий к нагрузке InnoDB
fio --name=dbwrite --rw=randwrite --bs=16k --iodepth=32 --numjobs=4 \
--size=4G --runtime=120 --time_based --direct=1 --fsync=1 \
--filename=/var/lib/mysql/fiotest --group_reporting
# задержка коммита в микросекундах: критична именно она
fio --name=commit --rw=write --bs=4k --iodepth=1 --sync=1 \
--size=1G --runtime=60 --time_based --direct=1 \
--filename=/var/lib/mysql/fiotest 2>&1 | grep -E 'lat|IOPS'
Смотрите не на пиковые IOPS, а на задержку 99-го процентиля: именно она даёт «сайт иногда подвисает». Методика замера — в материале про бенчмарк сервера через fio и sysbench.
Соблазн выставить innodb_flush_log_at_trx_commit = 0 или synchronous_commit = off даёт заметный прирост записи, но означает ровно одно: при отказе питания или падении процесса вы теряете подтверждённые клиенту транзакции. Для платежей и складских остатков это недопустимо. Второе: не кладите базу на RAID5 ради ёмкости — каждая запись блока превращается в чтение и две записи. Проверяйте долговечность тестом: запустите нагрузку, снимите питание через IPMI, поднимите базу и сравните последнюю подтверждённую транзакцию с тем, что осталось в таблице.
Коротко
- Приоритеты: память под рабочий набор, затем NVMe под журнал, затем частота ядра.
- MySQL: пул 60–70% RAM, flush_log_at_trx_commit = 1, io_capacity под NVMe.
- PostgreSQL: shared_buffers около 25% RAM, effective_cache_size 60–75%, random_page_cost 1.1 на NVMe.
- Диск проверяют случайной записью 16 KB с fsync, смотрят задержку 99-го процентиля, а не пик IOPS.
- RAID1 или RAID10; отключение долговечности ради скорости стоит транзакций.