Урок 02

Установка и настройка

Способы установки

Три варианта:

  • Apt / yum — из репозитория ОС.
  • Официальный репозиторий MySQL — свежая версия.
  • Docker — изолированно, быстро.

Apt (Ubuntu)

Из репозитория ОС:

sudo apt update
sudo apt install mysql-server
sudo systemctl enable mysql
sudo systemctl start mysql

Версия в Ubuntu 22.04 — MySQL 8.0.

Официальный репозиторий

Для свежей версии:

wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.32-1_all.deb
sudo apt update
sudo apt install mysql-server

Что даёт: последняя стабильная версия.

Docker

Простой вариант:

docker run -d \
    --name mysql \
    -e MYSQL_ROOT_PASSWORD=secret \
    -e MYSQL_DATABASE=myapp \
    -e MYSQL_USER=app \
    -e MYSQL_PASSWORD=secret \
    -p 3306:3306 \
    -v mysql_data:/var/lib/mysql \
    mysql:8.0

Docker Compose:

services:
  mysql:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: myapp
      MYSQL_USER: app
      MYSQL_PASSWORD: secret
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 5s

volumes:
  mysql_data:

⚠️ Обязательно volume, иначе данные пропадут при пересоздании контейнера.

Запуск и автозапуск

sudo systemctl status mysql
sudo systemctl start mysql
sudo systemctl enable mysql
sudo systemctl restart mysql

Логи:

sudo journalctl -u mysql -f
sudo tail -f /var/log/mysql/error.log

Первичная настройка

mysql_secure_installation:

sudo mysql_secure_installation

Интерактивно:

  1. Пароль root — установить.
  2. caching_sha2_password vs mysql_native_password — обычно первое.
  3. Удалить анонимных — да.
  4. Запретить root удалённо — да.
  5. Удалить тестовую БД — да.
  6. Перезагрузить таблицы привилегий — да.

Аутентификация

MySQL 8 по умолчанию: caching_sha2_password.

Проблема: старые клиенты (PHP < 7.4) не понимают.

Решение — для конкретного пользователя:

ALTER USER 'app'@'localhost'
IDENTIFIED WITH mysql_native_password BY 'secret';

Или в my.cnf:

[mysqld]
default_authentication_plugin = mysql_native_password

⚠️ mysql_native_password слабее, но совместимее.

Файлы конфигурации

Иерархия чтения:

  1. /etc/my.cnf
  2. /etc/mysql/my.cnf
  3. /etc/mysql/conf.d/*.cnf
  4. /etc/mysql/mysql.conf.d/*.cnf

Последний прочитанный — приоритетный.

Основные параметры:

[mysqld]
user = mysql
bind-address = 127.0.0.1
port = 3306

# Кодировки
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

# Соединения
max_connections = 150
max_connect_errors = 1000
wait_timeout = 28800
interactive_timeout = 28800

# InnoDB
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1

# Логи
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_error = /var/log/mysql/error.log

innodb_buffer_pool_size

Самый важный параметр. Кеш страниц InnoDB.

Правило:

  • На выделенном сервере — 70–80% RAM.
  • На сервере с другими сервисами — 50%.
  • Минимум — 128 MB.

Проверить:

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW STATUS LIKE 'Innodb_buffer_pool%';

Использование:

SELECT
    ROUND(1 - (
        (SELECT VARIABLE_VALUE FROM performance_schema.global_status
         WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_free') /
        (SELECT VARIABLE_VALUE FROM performance_schema.global_status
         WHERE VARIABLE_NAME = 'Innodb_buffer_pool_pages_total')
    , 4) * 100 AS used_percent;

max_connections

По умолчанию: 151.

Проверить:

SHOW VARIABLES LIKE 'max_connections';
SHOW STATUS LIKE 'Max_used_connections';

Правило:

  • max_used_connections ~ 80% от max_connections — увеличить.
  • Приложению — пул соединений, не открывать на каждый запрос.

Ошибка:

ERROR 1040: Too many connections

wait_timeout

Через сколько секунд закрыть неактивное соединение.

По умолчанию: 28800 (8 часов).

Правило: для приложений — 300–600 секунд. Слишком долгий timeout — впустую держит соединения.

Логи

Виды:

  • Error log — ошибки сервера.
  • General query log — все запросы (для отладки).
  • Slow query log — медленные.
  • Binary log — для репликации и PITR.

Медленные запросы:

slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1

Проверить:

SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

Динамически:

SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 0.5;

Binlog

Для репликации и PITR:

log_bin = /var/log/mysql/mysql-bin.log
server_id = 1
binlog_format = ROW
binlog_row_image = minimal
expire_logs_days = 7
max_binlog_size = 512M

Проверить:

SHOW VARIABLES LIKE 'log_bin';
SHOW BINARY LOGS;

Очистить:

PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;

Удалённое подключение

В mysqld.cnf:

bind-address = 0.0.0.0   # слушать все интерфейсы

Пользователь с %:

CREATE USER 'app'@'%' IDENTIFIED BY 'secret';
GRANT ALL PRIVILEGES ON myapp.* TO 'app'@'%';
FLUSH PRIVILEGES;

Firewall:

sudo ufw allow from 10.0.0.0/8 to any port 3306

⚠️ Открывать 3306 в интернет — никогда. Только внутренняя сеть или SSH-туннель.

SSH-туннель

ssh -L 3307:localhost:3306 user@server

Теперь подключаетесь к 127.0.0.1:3307.

Проверка соединения

Сервер жив:

mysqladmin -h 127.0.0.1 -u app -p ping
# mysqld is alive

Проверка параметров:

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'max_connections';
SHOW VARIABLES LIKE 'character_set%';

Мониторинг

Активные соединения:

SHOW PROCESSLIST;
SELECT * FROM information_schema.processlist WHERE command != 'Sleep';

Статус:

SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Queries';
SHOW GLOBAL STATUS LIKE 'Uptime';
SHOW GLOBAL STATUS LIKE 'Innodb_rows%';

Размер БД:

SELECT
    table_schema,
    ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS mb
FROM information_schema.tables
WHERE table_schema = 'myapp'
GROUP BY table_schema;

Переменные: GLOBAL vs SESSION

GLOBAL — на весь сервер (нужен SUPER). SESSION — только для текущего соединения.

SET GLOBAL max_connections = 200;
SET SESSION sql_mode = 'STRICT_ALL_TABLES';

В my.cnf — применяется ко всем новым сессиям.

⚠️ SET GLOBAL не переживёт рестарт. Для персистентности — в конфиг.

Режим SQL (sql_mode)

Важно: влияет на строгость.

SELECT @@sql_mode;

Рекомендуемый:

sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

Что даёт:

  • STRICT_TRANS_TABLES — ошибка при вставке неверных данных.
  • NO_ZERO_DATE — запрет 0000-00-00.
  • ERROR_FOR_DIVISION_BY_ZERO — ошибка при делении на 0.

⚠️ Без strict MySQL молча обрежет данные. С ним — ошибка.

Частые ошибки

1. Can't connect to local MySQL server through socket:

mysql не запущен или сокет в другом месте

Решение: systemctl start mysql, ps aux | grep mysqld.

2. Пароль root после установки:

В Ubuntu root без пароля, доступ через sudo

Решение: sudo mysql, затем ALTER USER.

3. Кончилось место:

Binlog растёт без ограничения

Решение: expire_logs_days = 7.

4. Медленные запросы без slow-лога:

Непонятно, что тормозит

Решение: включить slow_query_log.

5. Кодировка в контейнере:

Все таблицы в latin1

Решение: указать --character-set-server=utf8mb4.

6. Пул соединений на стороне клиента:

Каждый запрос открывает новое соединение

Решение: pool на приложении (HikariCP, mysql2 pool, Laravel PDO).

7. Тюнинг без мониторинга:

Изменили innodb_buffer_pool_size без замеров

Решение: сначала baseline, потом менять.

Практика

1. Установите MySQL 8 или MariaDB.

2. Настройте my.cnf:

character-set-server = utf8mb4
max_connections = 200
innodb_buffer_pool_size = 512M
slow_query_log = 1
long_query_time = 1

3. Перезапустите, проверьте параметры.

4. Создайте пользователя, подключитесь по TCP.

5. Сделайте медленный запрос (с SLEEP(3)), проверьте slow-лог.

6. Посмотрите SHOW PROCESSLIST, SHOW STATUS.

Итог

  • Установка: apt, Docker, официальный репо.
  • Кодировка: utf8mb4.
  • innodb_buffer_pool_size — главный параметр.
  • max_connections — под нагрузку, но лучше пул.
  • Logs: slow, error, binlog.
  • sql_mode — строгий.
  • Удалённо — только через SSH-туннель.

Дальше — типы данных MySQL.