## 创建目录及配置文件
创建目录结构如下,之后用于挂载数据卷:
```shell
├── master
│ ├── conf
│ └── data
├── slaver0
│ ├── conf
│ └── data
└── slaver1
├── conf
└── data
```
进入`./master/conf`目录,创建文件`vi my.cnf`,内容如下:
```shell
[mysqld]
# 集群服务器id,不可重复
server-id = 1
# 同步(binlog)文件名称
log-bin = mysql-bin
# 1055异常处理
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO"
```
进入`./slaver0/conf`目录,创建文件`vi my.cnf`,内容如下:
```shell
[mysqld]
# 集群服务器id,不可重复
server-id = 11
# 1055异常处理
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO"
```
进入`./slaver1/conf`目录,创建文件`vi my.cnf`,内容如下:
```shell
[mysqld]
# 集群服务器id,不可重复
server-id = 12
# 1055异常处理
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO"
```
## docker-compose.yml
创建`docker-compose.yml`文件,内容如下:
```yaml
version: '3'
services:
# 主库
mysql-master:
image: "mysql:5.7"
restart: always
ports:
- "3306:3306"
container_name: mysql-master
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- ./master/conf/my.cnf:/etc/mysql/conf.d/mysql.cnf
- ./master/data:/var/lib/mysql
# 从库0
mysql-slaver0:
image: "mysql:5.7"
restart: always
ports:
- "3307:3306"
container_name: mysql-slaver0
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- ./slaver0/conf/my.cnf:/etc/mysql/conf.d/mysql.cnf
- ./slaver0/data:/var/lib/mysql
# 从库1
mysql-slaver1:
image: "mysql:5.7"
restart: always
ports:
- "3308:3306"
container_name: mysql-slaver1
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- ./slaver1/conf/my.cnf:/etc/mysql/conf.d/mysql.cnf
- ./slaver1/data:/var/lib/mysql
```
运行`docker-compose up -d`启动容器。
## 配置步骤
### 主库
`docker exec -it mysql-master bash`进入主库,`mysql -u root -p 123456`进入`mysql`:
创建用户 `slaver`作为从库同步主库数据时的用户:
```shell
create user 'slaver'@'%' identified by '123456';
```
授予权限:
```shell
grant replication slave on *.* to 'slaver'@'%';
```
刷新权限:
```shell
flush privileges;
```
查看`binlog`相关配置:
```shell
show global variables like 'binlog%';
```
```shell
mysql> show global variables like 'binlog%';
+--------------------------------------------+--------------+
| Variable_name | Value |
+--------------------------------------------+--------------+
| binlog_cache_size | 32768 |
| binlog_checksum | CRC32 |
| binlog_direct_non_transactional_updates | OFF |
| binlog_error_action | ABORT_SERVER |
| binlog_format | ROW |
| binlog_group_commit_sync_delay | 0 |
| binlog_group_commit_sync_no_delay_count | 0 |
| binlog_gtid_simple_recovery | ON |
| binlog_max_flush_queue_time | 0 |
| binlog_order_commits | ON |
| binlog_row_image | FULL |
| binlog_rows_query_log_events | OFF |
| binlog_stmt_cache_size | 32768 |
| binlog_transaction_dependency_history_size | 25000 |
| binlog_transaction_dependency_tracking | COMMIT_ORDER |
+--------------------------------------------+--------------+
15 rows in set (0.01 sec)
```
查看 `server` 相关配置:
```shell
show global variables like 'server%';
```
```shell
mysql> show global variables like 'server%';
+----------------+--------------------------------------+
| Variable_name | Value |
+----------------+--------------------------------------+
| server_id | 1 |
| server_id_bits | 32 |
| server_uuid | 25410417-5643-11eb-9ef1-0242ac130005 |
+----------------+--------------------------------------+
3 rows in set (0.00 sec)
```
查看主库状态:
```shell
show master status;
```
```shell
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
```
### 从库
连接从库`mysql-slaver0`:
```sql
# 设置 master 连接参数
change master to
master_host='mysql-master', # 主库的IP,由于docker的原因,可以使用容器名来当主机名
master_user='slaver', # 主库同步的用户
master_password='123456', # 密码
master_port=3306, # 主库的端口
master_log_file='mysql-bin.000001', # 同步的文件 通过show master status来获取
master_log_pos=154; # 开始从第几行同步 通过show master status来获取
# 启动同步
start slave;
# 查看 slave 状态
show slave status; # 看到 Slave_IO_Running 和 Slave_SQL_Running 都为 Yes 即为配置成功
```
对从库`mysql-slaver1`做相同操作。
还可以使用`stop slave;`停止同步。
## binlog 模式
前面通过`show global variables like 'binlog%';`命令可以看到`binlog_format `为`ROW`。
`binlog`有以下三种模式:
- `ROW`:每条记录的修改都会被记录。
优点:不存在数据不一致的情况。
缺点:一旦修改表结构( alter table) 会出现 binlog 暴涨现象。
- `STATEMENT`:每执行一条导致值变化的 sql 就会记录到 binlog 中。
优点: 仅仅记录了SQL,不会记录执行结果,减少了 binlog 日志量,节约了 IO,提高了性能
缺点:会出现数据不一致的情况。
- `MIXED`:以上两种模式混合使用。
我们可以通过编辑`./master/conf/my.cnf`文件,添加一行`binlog_format = MIXED`来修改`binlog`模式。
## MySQL 主从同步原理
主从同步原理图:

MySQL 默认的复制方式是`异步`的,主库把日志发送给从库后不关心从库是否已经处理,这样会产生一个问题就是假设主库挂了,从库处理失败了,这时候从库升为主库后,日志就丢失了。可以根据情况调整同步策略:
- 全同步复制:主库写入 binlog 后强制同步日志到从库,`所有的从库`都执行完成后才返回给客户端。性能会受到严重影响。
- 半同步复制:从库写入日志成功后返回 ACK 确认给主库,主库收到至少一个从库的确认就认为写操作完成。
> 主从延迟:主库与从库之间数据同步肯定是有延时的(网络)。解决方案是:部分查询强制走主库,主库肯定是最新的数据。

docker-compose部署MySQL主从