如何在 Docker 上安装 MySQL 读写分离

mysql 主从的机制主要是通过从服务器订阅主服务器的 binlog 日志实现,这里以一主双从的形式演示。

解释

这三个 mysql 创建一个 docker 的局域网用于通信使用,因为各个容器之间是互不影响的,所以他们的启动端口都可以是 3306,对于宿主机映射的端口分别是 6606,6607,6608。

1 准备

1.1 docker-compose

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

|

version: ‘3.7’

services:

  mysql-master:

    image: mysql/mysql-server:5.7

    container_name: mysql_master

    ports:

    - 6606:3306

    volumes:

      - /volume/mysql-master:/var/lib/mysql

      - /volume/conf/mysql-ms/mysqld-master.cnf:/etc/my.cnf

    command:

      - “–user=root”

    environment:

      MYSQL_ROOT_PASSWORD: Yu20200416_

      MYSQL_DATABASE: spark

      MYSQL_USER: admin

      MYSQL_PASSWORD: Yu20200416_

    restart: unless-stopped

    networks:

      mysql-ms-network:

        ipv4_address: 172.25.0.101

  mysql-slave1:

    image: mysql/mysql-server:5.7

    container_name: mysql_slave1

    ports:

    - 6607:3306

    command:

      - “–user=root”

    volumes:

      - /volume/mysql-slave1:/var/lib/mysql

      - /volume/conf/mysql-ms/mysqld-slave1.cnf:/etc/my.cnf

    environment:

      MYSQL_ROOT_PASSWORD: Yu20200416_

      MYSQL_DATABASE: spark

      MYSQL_USER: admin

    restart: unless-stopped

    networks:

      mysql-ms-network:

        ipv4_address: 172.25.0.102

  mysql-slave2:

    image: mysql/mysql-server:5.7

    container_name: mysql_slave2

    ports:

      - 6608:3306

    command:

      - “–user=root”

    volumes:

      - /volume/mysql-slave2:/var/lib/mysql

      - /volume/conf/mysql-ms/mysqld-slave2.cnf:/etc/my.cnf

    environment:

      MYSQL_ROOT_PASSWORD: Yu20200416_

      MYSQL_DATABASE: spark

      MYSQL_USER: admin

    restart: unless-stopped

    networks:

      mysql-ms-network:

        ipv4_address: 172.25.0.103

networks:

  mysql-ms-network:

    driver: bridge

    ipam:

      config:

        - subnet: 172.25.0.0/24

|

1.2 准备 my.cnf 文件

1.2.1 mysql-master.cnf

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

|

[mysqld]

#主数据库端 ID 号

server_id = 1

#开启二进制日志                

log-bin = mysql-bin

#需要复制的数据库名,如果复制多个数据库,重复设置这个选项即可                

binlog-do-db = spark

#将从服务器从主服务器收到的更新记入到从服务器自己的二进制日志文件中                

log-slave-updates

#控制 binlog 的写入频率。每执行多少次事务写入一次 (这个参数性能消耗很大,但可减小 MySQL 崩溃造成的损失)

sync_binlog = 1

#这个参数一般用在主主同步中,用来错开自增值, 防止键值冲突

auto_increment_offset = 1

#这个参数一般用在主主同步中,用来错开自增值, 防止键值冲突

auto_increment_increment = 1

#二进制日志自动删除的天数,默认值为 0, 表示“没有自动删除”,启动时和二进制日志循环时可能删除

expire_logs_days = 7

#将函数复制到 slave

log_bin_trust_function_creators = 1

|

1.2.2 mysqld-slave1.cnf

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

|

[mysqld]

从数据库端 ID 号

server_id = 2

log-bin = mysql-bin

log-slave-updates

sync_binlog = 0

#log buffer 将每秒一次地写入 log file 中,并且 log file 的 flush(刷到磁盘) 操作同时进行。该模式下在事务提交的时候,不会主动触发写入磁盘的操作

innodb_flush_log_at_trx_commit = 0

#指定 slave 要复制哪个库

replicate-do-db = spark

#MySQL 主从复制的时候,当 Master 和 Slave 之间的网络中断,但是 Master 和 Slave 无法察觉的情况下(比如防火墙或者路由问题)。Slave 会等待 slave_net_timeout 设置的秒数后,才能认为网络出现故障,然后才会重连并且追赶这段时间主库的数据

slave-net-timeout = 60

log_bin_trust_function_creators = 1

1.2.3mysqld-slave1.cnf

[mysqld]

从数据库端 ID 号

server_id = 3

log-bin = mysql-bin

log-slave-updates

sync_binlog = 0

#log buffer 将每秒一次地写入 log file 中,并且 log file 的 flush(刷到磁盘) 操作同时进行。该模式下在事务提交的时候,不会主动触发写入磁盘的操作

innodb_flush_log_at_trx_commit = 0

#指定 slave 要复制哪个库

replicate-do-db = spark

#MySQL 主从复制的时候,当 Master 和 Slave 之间的网络中断,但是 Master 和 Slave 无法察觉的情况下(比如防火墙或者路由问题)。Slave 会等待 slave_net_timeout 设置的秒数后,才能认为网络出现故障,然后才会重连并且追赶这段时间主库的数据

slave-net-timeout = 60

log_bin_trust_function_creators = 1

|

【注意】
配置文件中的 server_id 要保证全局唯一。

2. 启动 mysql

2.1 将配置文件放置在指定目录

因为我们想将 mysql 的 my.cnf 文件映射到宿主机上(否则 docker 会将映射的文件作为路径处理导致报错),所以需要提前将准备好的配置文件放置在我们约定的指定位置中(这里我约定的路径为/volume/conf/mysql-ms/)

2.2 执行 docker-compose

第一次需要拉取 mysql 镜像,执行时间相对长一点。

|

1

|

docker-compose up -d

|

启动完成后,查看 mysql 状态

|

1

|

docker ps | grep mysql

|

3. 配置 mysql 读写分离

3.1 进入镜像,这里以 mysql-master 为例

|

1

|

docker-compose exec mysql-master bash

|

进入 mysql

|

1

|

mysql -uroot -p

|

开启远程访问权限

|

1

2

|

GRANT ALL PRIVILEGES ON . TO ‘root’@‘%’ IDENTIFIED BY ‘Yu20200416_’ WITH GRANT OPTION;

flush privileges;

|

两个 slave 的 mysql 也需要相同的操作开启远程访问权限

3.2 获取 mysql-master 的 binlog 开始主从复制的地址

|

1

|

show master status;

|

3.3mysql-slave 执行以下命令

  1. 重置 mysql-slave

|

1

|

reset slave;

|

2. 设置订阅的主服务器信息,这步很重要!!!
根据自己之前配置的信息编写对一个 mysql-master 的信息,这里的 master_log_file 和 master_log_pos 是刚刚查阅的 master 的 status 信息

|

1

|

change master to master_host=‘172.25.0.101’,master_user=‘root’,master_password=‘Yu20200416_’,master_port=3306,master_log_file=‘mysql-bin.000003’,master_log_pos=604;

|

3. 启动订阅线程

|

1

|

start slave;

|

4. 查看订阅状态

|

1

|

show slave status\G;

|

如果订阅成功,你的 Slave_IO_Running 和 Slave_SQL_Running 应该都是 Yes

5. 设置从服务器为只读(可以不设置)

为了避免开发人员误操作,我们最好将从服务器设置成只读模式

|

1

|

set global read_only=1;

|

安装过程中可能出现的问题

服务器间网络不通,我之前因为懒,没有设置局域网,想着直接使用宿主机的 ip+宿主机映射的 port 进行 mysql 之间的通信,结果是不好使的 :-||

没有编写 my.cnf 配置文件,docker 如果需要映射文件的话需要提前在宿主机的指定目录创建好映射的文件,否则 docker-compose 启动会报错