# MySQL

Описан процесс установки MySQL и настройка базовой репликации мастер -> слейв

- [MySQL](#mysql)
  - [Установка сервера MySQL 8 в Debian 12](#установка-сервера-mysql-8-в-debian-12)
  - [Создание тестовой БД и наполнение данными](#создание-тестовой-бд-и-наполнение-данными)
    - [Подключение к СУБД](#подключение-к-субд)
    - [Создание базы данных](#создание-базы-данных)
    - [Переключение на созданную базу данных](#переключение-на-созданную-базу-данных)
    - [Создание таблицы в базе данных](#создание-таблицы-в-базе-данных)
    - [Добавление записей в таблицу](#добавление-записей-в-таблицу)
    - [Выборка из таблицы](#выборка-из-таблицы)
  - [Репликация - общие настройки](#репликация---общие-настройки)
    - [Пользователь для выполнения задач репликации](#пользователь-для-выполнения-задач-репликации)
    - [Настройка мастера для репликации](#настройка-мастера-для-репликации)
  - [Репликация средствами mysqldump](#репликация-средствами-mysqldump)
    - [Дамп БД средствами mysqldump](#дамп-бд-средствами-mysqldump)
    - [Настройка репликации mysqldump](#настройка-репликации-mysqldump)
      - [Настройка слейва для репликации](#настройка-слейва-для-репликации)
    - [Запуск воспроизведения журнала ретрансляции, и проверка статуса репликации mysqldump](#запуск-воспроизведения-журнала-ретрансляции-и-проверка-статуса-репликации-mysqldump)
    - [Проверка репликации mysqldump](#проверка-репликации-mysqldump)
  - [Репликация - Percona XtraBackup](#репликация---percona-xtrabackup)
    - [Установка Percona XtraBackup](#установка-percona-xtrabackup)
    - [Настройка репликации xtrabackup](#настройка-репликации-xtrabackup)
    - [Подготовка резервной копии перед восстановлением](#подготовка-резервной-копии-перед-восстановлением)
    - [Копирование резервной копии на слейв](#копирование-резервной-копии-на-слейв)
    - [Восстановление БД на слейве](#восстановление-бд-на-слейве)
    - [Настройка репликации](#настройка-репликации)
    - [Проверка репликации xtrabackup](#проверка-репликации-xtrabackup)

## Установка сервера MySQL 8 в Debian 12

На сайте [MySQL в разделе Community](https://dev.mysql.com/downloads/mysql/) выбрать необходимую версию (8.4.3 LTS на момент написания заметки), в качестве ОС выбрать Debian.
После выбора ОС появится предложение выполнить установку используя репозиторий APT, нажимаем ссылку, будет предложено скачать пакет для настройки репозитория (mysql-apt-config_0.8.33-1_all.deb на момент написания заметки). Далее в консоли по документации - <https://dev.mysql.com/doc/refman/8.4/en/linux-installation-apt-repo.html>

```shell
su -

wget https://dev.mysql.com/get/mysql-apt-config_0.8.33-1_all.deb
apt install -y ./mysql-apt-config_0.8.33-1_all.deb
```

В появившемся окне выбрать - `Ok`

```shell
dpkg-reconfigure mysql-apt-config

apt update
apt install mysql-server
```

Можно также выполнить настройки безопасности

```shell
mysql_secure_installation
```

## Создание тестовой БД и наполнение данными

### Подключение к СУБД

```shell
mysql -u root -p
```

### Создание базы данных

```shell
CREATE DATABASE IF NOT EXISTS sape_test_db;
```

По ошибке была создана БД с именем - `sape_test_db.db`

При её удалении полачал ошибку

```shell
mysql> drop database 'sape_test_db.db';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''sape_test_db.db'' at line 1
```

Поиск причин привёл - <https://stackoverflow.com/questions/16135987/error-on-drop-default-database-error>

при использовании в названии зарезервированных слов, следует заключать имя БД в косые ковычки `

```shell
mysql> drop database `sape_test_db.db`;
Query OK, 0 rows affected (0,17 sec)
```

### Переключение на созданную базу данных

```shell
USE sape_test_db;
```

### Создание таблицы в базе данных

таблица будет содержать три столбца: id, name, surname, address. Первичным ключом будет id. В качестве движка явно укажем InnoDB.

```shell
CREATE TABLE admin_table
( id int NOT NULL AUTO_INCREMENT,
name char(20) NOT NULL,
surname char(20) NOT NULL,
city char(20) NULL,
PRIMARY KEY (id) )
ENGINE=InnoDB;
```

для удаления таблицы

```shell
DROP TABLE admin_table;
```

### Добавление записей в таблицу

```shell
INSERT admin_table(name, surname, city) VALUES ('Andrei', 'Ahmadulin', 'Ekaterinburg');
INSERT admin_table(name, surname, city) VALUES ('Kit', 'Root', 'Georgia');
INSERT admin_table(name, surname, city) VALUES ('Ilya', 'Paramonov', 'Moscow');
INSERT admin_table(name, surname, city) VALUES ('Andrei', 'Zharkov', 'Moscow');
INSERT admin_table(name, surname, city) VALUES ('Artem', 'Dolgiy', 'Zelenograd');
```

### Выборка из таблицы

```shell
SELECT * FROM admin_table;
```

## Репликация - общие настройки

Эти настройки выполняются вне зависимости от выбранного способа репликации

### Пользователь для выполнения задач репликации

Будет создан пользователь `repl_user` с паролем `repl_passwd`

```shell
mysql -u root -p
```

```shell
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'repl_passwd';
```

Если возникнет ошибка - `ERROR 1819 (HY000): Your password does not satisfy the current policy requirements` - <https://stackoverflow.com/questions/43094726/your-password-does-not-satisfy-the-current-policy-requirements>

кратко - достаточно изменить политику паролей

```shell
mysql> SHOW VARIABLES LIKE 'validate_password%';
+-------------------------------------------------+--------+
| Variable_name                                   | Value  |
+-------------------------------------------------+--------+
| validate_password.changed_characters_percentage | 0      |
| validate_password.check_user_name               | ON     |
| validate_password.dictionary_file               |        |
| validate_password.length                        | 8      |
| validate_password.mixed_case_count              | 1      |
| validate_password.number_count                  | 1      |
| validate_password.policy                        | MEDIUM |
| validate_password.special_char_count            | 1      |
+-------------------------------------------------+--------+
8 rows in set (0,03 sec)

mysql> SET GLOBAL validate_password.policy = LOW;
Query OK, 0 rows affected (0,00 sec)

mysql> 
```

Теперь пользователя можно будет создать с простым паролем - `'repl_passwd'`

Назначение привилегий для пользователя

```shell
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
```

### Настройка мастера для репликации

В файл `/etc/mysql/my.cnf` (или в `/etc/mysql/mysql.conf.d/mysqld.cnf`, в зависимости от настроек) в секции `[mysqld]` необходимо добавить следующие параметры:

```shell
server_id = 1 # назначает серверу уникальный целочисленный идентификатор
log_bin = mysql-bin # включает двоичный журнал и указывает его расположение
```

После изменения конфигурации необходимо перезагрузить СУБД

```shell
systemctl restart mysql.service
```

Стоит убедиться, что двоичный журнал включен

```shell
SHOW BINARY LOG STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000002 |      158 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0,00 sec)
```

В более ранних версиях используется команда - `SHOW MASTER STATUS;`

- <https://habr.com/ru/articles/532216/>
- <https://www.k-max.name/linux/replikaciya-mysql-master-slave/>

## Репликация средствами mysqldump

### Дамп БД средствами mysqldump

Для того, чтобы начать репликацию данных, необходимо “подтянуть” слейв до состояния мастера. Для этого, нужно временно заблокировать сам мастер, чтобы сделать слепок актуальных данных.

```shell
FLUSH TABLES WITH READ LOCK;
```

Далее, с помощью mysqldump сделать экспорт данных из базы.

```shell
mysqldump -u root -p sape_test_db > sape_test_db.db
```

После этого, необходимо еще раз выполнить команду `SHOW BINARY LOG STATUS;`, и запомнить или записать значения File и Position. Это, так называемые координаты двоичного журнала. Именно от них далее будет указано стартовать слейву.

Теперь мастер можно разблокировать.

```shell
UNLOCK TABLES;
```

Мастер настроен, и готов реплицироваться на другие сервера.

### Настройка репликации mysqldump

#### Настройка слейва для репликации

В первую очередь на слейв необходимо загрузить дамп, полученный с мастера

```shell
root@master:~# scp sape_test_db.db slave:/root
sape_test_db.db                                                                                                       100% 2169     2.5MB/s   00:00    
root@master:~# 
```

```shell
CREATE DATABASE `sape_test_db`;
```

```shell
mysql -u root -p sape_test_db < /root/sape_test_db.db
```

Изменить конфигурацию слейва `/etc/mysql/my.cnf` (или в `/etc/mysql/mysql.conf.d/mysqld.cnf`, в зависимости от настроек) в секции `[mysqld]`

```shell
log_bin = mysql-bin  # указываем слейву вести собственный двоичный журнал
server_id = 2  # указываем идентификатор сервера
relay-log = /var/lib/mysql/mysql-relay-bin # указываем расположение журнала ретрансляции
relay-log-index = /var/lib/mysql/mysql-relay-bin.index  # этот файл служит перечнем всех имеющихся журналов ретрансляции
read_only = 1  # переводим слейв в режим “только чтение”
```

После изменения конфигурации необходимо перезагрузить службу

```shell
systemctl restart mysql.service
```

Необходимо указать слейву, какой сервер будет являться для него мастером, и откуда начинать реплицировать данные. Вместо `MASTER_LOG_FILE` и `MASTER_LOG_POS` необходимо подставить значения, полученные из `SHOW BINARY LOG STATUS;` на мастере. Эти параметры вместе называются координатами двоичного журнала.

Адрес мастера указан в `hosts`, поэтому достаточно указать его имя

Начиная с MySQL 8.4+: `GET_SOURCE_PUBLIC_KEY` является обязательным параметром, который необходимо добавить - <https://stackoverflow.com/questions/69936021/error-002061-authentication-plugin-caching-sha2-password-reported-error-aut>

```shell
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='master',
  SOURCE_USER='repl_user',
  SOURCE_PASSWORD='repl_passwd',
  SOURCE_LOG_FILE='mysql-bin.000002',
  SOURCE_LOG_POS=158,
  GET_SOURCE_PUBLIC_KEY=1;
```

В более ранних версиях используется команда - `CHANGE MASTER TO...`

### Запуск воспроизведения журнала ретрансляции, и проверка статуса репликации mysqldump

```shell
start replica;
```

```shell
mysql> show replica status\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: master
                  Source_User: repl_user
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: mysql-bin.000002
          Read_Source_Log_Pos: 158
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 328
        Relay_Source_Log_File: mysql-bin.000002
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 158
              Relay_Log_Space: 539
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Source_SSL_Allowed: No
           Source_SSL_CA_File: 
           Source_SSL_CA_Path: 
              Source_SSL_Cert: 
            Source_SSL_Cipher: 
               Source_SSL_Key: 
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Source_Server_Id: 1
                  Source_UUID: 1337616f-ad64-11ef-ba97-bc2411fcdf96
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 10
                  Source_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Source_SSL_Crl: 
           Source_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Source_TLS_Version: 
       Source_public_key_path: 
        Get_Source_public_key: 0
            Network_Namespace: 
1 row in set (0,00 sec)
```

Если все прошло успешно, ваш статус должен иметь аналогичный вид. Ключевые параметры здесь:

`Replica_IO_State`, `Replica_SQL_Running_State` — состояние IO потока, принимающего двоичный журнал с мастера, и состояние потока, применяющего журнал ретрансляции соотвественно. Только наличие обоих потоков свидетельствует об успешном процессе репликации.  
`Read_Source_Log_Pos` — последняя позиция, прочитанная из журнала мастера.  
`Relay_Source_Log_File` — текущий файл журнала мастера.  
`Seconds_Behind_Source` — отставание слейва от мастера, в секундах.  
`Last_IO_Error`, `Last_SQL_Error` — ошибки репликации, если они есть.  

### Проверка репликации mysqldump

На мастере добавить данные и убедиться, что они появились на слейве

```shell
mysql -u root -p
use sape_test_db;

INSERT admin_table(name, surname, city) VALUES ('Nikita', 'Samoilov', 'Sankt-Petersburg');
```

```shell
mysql> select * from admin_table;
+----+--------+-----------+------------------+
| id | name   | surname   | city             |
+----+--------+-----------+------------------+
|  1 | Andrei | Ahmadulin | Ekaterinburg     |
|  2 | Kit    | Root      | Georgia          |
|  3 | Ilya   | Paramonov | Moscow           |
|  4 | Andrei | Zharkov   | Moscow           |
|  5 | Artem  | Dolgiy    | Zelenograd       |
|  6 | Nikita | Samoilov  | Sankt-Petersburg |
+----+--------+-----------+------------------+
6 rows in set (0,00 sec)
```

Проверить данные на слейве

```shell
mysql> select * from admin_table;
+----+--------+-----------+------------------+
| id | name   | surname   | city             |
+----+--------+-----------+------------------+
|  1 | Andrei | Ahmadulin | Ekaterinburg     |
|  2 | Kit    | Root      | Georgia          |
|  3 | Ilya   | Paramonov | Moscow           |
|  4 | Andrei | Zharkov   | Moscow           |
|  5 | Artem  | Dolgiy    | Zelenograd       |
|  6 | Nikita | Samoilov  | Sankt-Petersburg |
+----+--------+-----------+------------------+
6 rows in set (0,00 sec)
```

[вверх](#mysql)

***

## Репликация - Percona XtraBackup

### Установка Percona XtraBackup

Установка согласно [документации](https://docs.percona.com/percona-xtrabackup/8.4/installation.html)

Стоит иметь ввиду, что версии MySQL и Percona XtraBackup должны совпадать, иначе создание резервной копии может завершиться ошибкой или невозможностью восстановления.

Порядок установки:

- обновление индекса пакетов и установка вспомогательных утилит

```shell
su -
apt update && apt install -y curl gnupg2 lsb-release lz4 zstd
```

- установка репозитория percona с помощью пакета

```shell
curl -O https://repo.percona.com/apt/percona-release_latest.generic_all.deb
apt install ./percona-release_latest.generic_all.deb
```

общие репозитории percona будут прописаны после установки пакета

```shell
root@master:~# ls -l /etc/apt/sources.list.d/
total 16
-rw-r--r-- 1 root root 662 Jan 23 18:30 mysql.list
-rw-r--r-- 1 root root 294 Jan 23 18:34 percona-pmm2-client-release.list
-rw-r--r-- 1 root root 280 Jan 23 18:34 percona-prel-release.list
-rw-r--r-- 1 root root 290 Jan 23 18:34 percona-telemetry-release.list
```

- после установки общих репозиториев необходимо обновить индекс пакетов

```shell
apt update
```

- далее выбирается конкретный релиз, который будет использоваться

```shell
percona-release enable pxb-84-lts
```

в результате выполнения команды будет добавлен репозиторий выбранного релиза

```shell
root@master:~# ls -l /etc/apt/sources.list.d/
total 20
-rw-r--r-- 1 root root 662 Jan 23 18:30 mysql.list
-rw-r--r-- 1 root root 294 Jan 23 18:34 percona-pmm2-client-release.list
-rw-r--r-- 1 root root 280 Jan 23 18:34 percona-prel-release.list
-rw-r--r-- 1 root root 292 Jan 24 13:20 percona-pxb-84-lts-release.list
-rw-r--r-- 1 root root 290 Jan 23 18:34 percona-telemetry-release.list
```

- установка Percona XtraBackup

```shell
apt update && apt install percona-xtrabackup-84
```

```shell
root@master:~# xtrabackup --version
xtrabackup version 8.4.0-2 based on MySQL server 8.4.0 Linux (x86_64) (revision id: d4373834)
```

### Настройка репликации xtrabackup

<https://docs.percona.com/percona-xtrabackup/8.4/set-up-replication.html>

```shell
xtrabackup --backup --user=root --password --target-dir=/tmp/dump
```

параметров достаточно много, вот некоторые из них:

`--backup` - создание резервной копии;
`--compress` - сжатие резервной копии;
`--stream=xbstream` - собрать файлы резервной копии в единый архив;
`--datadir` - директория из которой будут копироваться данные. Если этот параметр не указан, будет использован путь по-умолчанию;
`--target-dir` - директория, в которую будет сохранена резервная копия

также могут использоваться дополнительные параметры, например

`--slave-info` - указывает, что нужно сохранить информацию о репликации (например, позицию бинарного лога) в резервной копии. Это полезно, если планируется использовать резервную копию для настройки реплики;
`--use-memory` - ограничения на использование памяти;
`--parallel` - использование нескольких ядер процессора для ускорения процесса создания резервной копии;
`--compress-threads` - сжатие в несколько потоков.

### Подготовка резервной копии перед восстановлением

```shell
xtrabackup --prepare --target-dir=/tmp/dump
```

### Копирование резервной копии на слейв

```shell
rsync -avpP -e ssh /tmp/dump slave:/tmp
```

### Восстановление БД на слейве

Остановить сервер БД и переместить имеющиеся данные на слейве

```shell
systemctl stop mysql

mkdir /root/mysql_old && mv /var/lib/mysql/* /root/mysql_old
```

Позднее, если не будет ошибок, перемещённые данные можно будет удалить

```shell
rm -rf /root/mysql_old
```

копирование дампа в целевой каталог слейва

```shell
xtrabackup --move-back --target-dir=/tmp/dump --datadir=/var/lib/mysql
```

установить корректные права

```shell
chown -R mysql:mysql /var/lib/mysql
```

### Настройка репликации

Изменить конфигурацию слейва `/etc/mysql/my.cnf`  
**!!! (из других конфиг.файлов конфигурация не применялась) !!!** в секции [mysqld]

```shell
[mysqld]
server_id = 2
```

Запустить сервер БД

```shell
systemctl start mysql
```

Убедиться в том, что нужные параметры применились можно запросом в БД

```shell
mysql> SHOW VARIABLES LIKE 'server_id';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 2     |
+---------------+-------+
1 row in set (0,00 sec)
```

Уточнить значение и позицию `bin-log` в каталоге, в который скопировали резервную копию с мастера, в данном примере - `/tmp/dump`

```shell
root@slave:~# cat /tmp/dump/xtrabackup_binlog_info
mysql-bin.000002        158
```

Команда для запуска репликации в консоли mysql

```shell
mysql -u root -p
```

```shell
CHANGE REPLICATION SOURCE TO
    SOURCE_HOST='master',
    SOURCE_USER='repl_user',
    SOURCE_PASSWORD='repl_passwd',
    SOURCE_LOG_FILE='mysql-bin.000002',
    SOURCE_LOG_POS=158,
    GET_SOURCE_PUBLIC_KEY=1;
```

```shell
START REPLICA;
```

```shell
SHOW REPLICA STATUS\G
```

на что обратить внимание в выводе:

```shell
mysql> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: master
                  Source_User: repl_user
...
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
...
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
...
```

### Проверка репликации xtrabackup

На мастере добавить данные и убедиться, что они появились на слейве

```shell
mysql -u root -p
use sape_test_db;

INSERT admin_table(name, surname, city) VALUES ('Nikita', 'Samoilov', 'Sankt-Petersburg');
```

```shell
mysql> select * from admin_table;
+----+--------+-----------+------------------+
| id | name   | surname   | city             |
+----+--------+-----------+------------------+
|  1 | Andrei | Ahmadulin | Ekaterinburg     |
|  2 | Kit    | Root      | Georgia          |
|  3 | Ilya   | Paramonov | Moscow           |
|  4 | Andrei | Zharkov   | Moscow           |
|  5 | Artem  | Dolgiy    | Zelenograd       |
|  6 | Nikita | Samoilov  | Sankt-Petersburg |
+----+--------+-----------+------------------+
6 rows in set (0,00 sec)
```

Проверить данные на слейве

```shell
mysql> select * from admin_table;
+----+--------+-----------+------------------+
| id | name   | surname   | city             |
+----+--------+-----------+------------------+
|  1 | Andrei | Ahmadulin | Ekaterinburg     |
|  2 | Kit    | Root      | Georgia          |
|  3 | Ilya   | Paramonov | Moscow           |
|  4 | Andrei | Zharkov   | Moscow           |
|  5 | Artem  | Dolgiy    | Zelenograd       |
|  6 | Nikita | Samoilov  | Sankt-Petersburg |
+----+--------+-----------+------------------+
6 rows in set (0,00 sec)
```

[вверх](#mysql)
