基于Docker搭建MySQL主从复制架构实践

深夜程猿

共 5432字,需浏览 11分钟

 · 2021-03-06

下面,直接进入主题,如果还没接触过Docker的朋友,建议先去学习一下Docker。Docker对于个人开发者来说也是一大神器,会大大降低我们很多学习成本,比如搭建各种组件环境等。

创建网段

因为是搭建一个主从复制架构,master和slave数据库都需要进行网络通信,所以需要保证master和slave的网络是通的。

我们可以基于Docker模拟一个内网网段。如下,创建mysql-replication网络:

  1. docker network create mysql-replication

查看刚才创建的网络:

  1. docker network inspect mysql-replication

输出内容如下:

  1. [

  2. {

  3. "Name":"mysql-replication",

  4. "Id":"8e0e22b80aff26987986959c2814fa90a2b390f2de36020f7c245d79a308bc91",

  5. "Created":"2021-02-20T10:08:28.364053029+08:00",

  6. "Scope":"local",

  7. "Driver":"bridge",

  8. "EnableIPv6":false,

  9. "IPAM":{

  10. "Driver":"default",

  11. "Options":{},

  12. "Config":[

  13. {

  14. "Subnet":"172.29.0.0/16",

  15. "Gateway":"172.29.0.1"

  16. }

  17. ]

  18. },

  19. "Internal":false,

  20. "Attachable":false,

  21. "Ingress":false,

  22. "ConfigFrom":{

  23. "Network":""

  24. },

  25. "ConfigOnly":false,

  26. "Containers":{},

  27. "Options":{},

  28. "Labels":{}

  29. }

  30. ]

这样我们就创建好了网络,模拟了一个内网网段。

创建mysql容器

1.拉取mysql镜像

这里我们以拉去5.7版本为例

  1. docker pull mysql:5.7

2.启动两个mysql容器

启动mysql容器,命名为mysql-a

  1. docker run -d \

  2. --network=mysql-replication \

  3. --name=mysql-a \

  4. -p 3308:3306 \

  5. -v /root/mysql-replication-test/mysql-a/data:/var/lib/mysql \

  6. -e MYSQL_ROOT_PASSWORD=root mysql:5.7

启动mysql容器,命名为mysql-b

  1. docker run -d \

  2. --network=mysql-replication \

  3. --name=mysql-b \

  4. -p 3309:3306 \

  5. -v /root/mysql-replication-test/mysql-b/data:/var/lib/mysql \

  6. -e MYSQL_ROOT_PASSWORD=root mysql:5.7

这样,我们就启动了两个mysql容器了,并且都处于mysql-replication这个网络下。

搭建主从

我们让mysql-a担任Master角色

数据准备

查看mysql-a、mysql-b的ip

  1. docker inspect mysql-a | grep "IPAddress"

  2. docker inspect mysql-b | grep "IPAddress"

mysql-a的ip=172.29.0.2,mysql-b的ip=172.29.0.3

修改master数据库配置

进入mysql容器修改配置

  1. docker exec-ti mysql-a bash

然后修改配置:

  • 设置mysql id

  • 开启binlog日志

  1. vim /etc/mysql/mysql.conf.d/mysqld.cnf

  1. [mysqld]

  2. pid-file =/var/run/mysqld/mysqld.pid

  3. socket =/var/run/mysqld/mysqld.sock

  4. datadir =/var/lib/mysql

  5. #log-error = /var/log/mysql/error.log

  6. # By default we only accept connections from localhost

  7. #bind-address = 127.0.0.1

  8. # Disabling symbolic-links is recommended to prevent assorted security risks

  9. symbolic-links=0


  10. ### 配置mysql id,要确保主从的id不同

  11. server-id=100

  12. ### 开启binlog日志

  13. log-bin=mysql-bin

重启mysql-a容器,让配置生效

  1. docker restart mysql-a

重新登录mysql-a的mysql,执行show master status查看当前状态,后面配置slave mysql需要用到,这里我们查到:

我们后面会用到File和Position字段的值d87618675a93756ae096672dc2b2604b.webp

master数据库创建同步用户

在master mysql上面,创建一个用户,用于同步数据。

  1. # 创建用户slave_01,密码是salve_01,允许ip为172.29.0.*的机器同步数据

  2. create user 'slave_01'@'172.29.0.%' identified by'slave_01';

  3. # 授权

  4. grant replication slave on *.* to 'slave_01'@'172.29.0.%';

  5. # 生效

  6. flush privileges;

备份master数据库到slave数据库

如果master数据库没有需要同步备份到从数据库的数据,这一步可以不处理。

在mysql-a容器里,执行命令:

  1. mysqldump --single-transaction -uroot -p --master-data=2-A>dump.sql

这样在当前目录就可以看到了dump.sql,把dump.sql文件移动到和宿主机共享的目录:

  1. mv dump.sql /var/lib/mysql

退出mysql-a容器,到dump.sql目录拷贝dump.sql到容器mysql-b:

  1. docker cp dump.sql b2a06688fe70:/

其中,b2a06688fe70是mysql-b容器的id。

登录mysql-b,导入备份数据:

  1. docker exec-ti mysql-b bash

  2. # 登录mysql

  3. mysql -u root -p

  4. # 登录上mysql后,执行备份sql

  5. source /dump.sql

这样,我们就把mysql-a的数据备份到mysql-b。

修改slave数据库配置

修改mysql配置文件:

  1. vim /etc/mysql/mysql.conf.d/mysqld.cnf

  1. [mysqld]

  2. pid-file =/var/run/mysqld/mysqld.pid

  3. socket =/var/run/mysqld/mysqld.sock

  4. datadir =/var/lib/mysql

  5. #log-error = /var/log/mysql/error.log

  6. # By default we only accept connections from localhost

  7. #bind-address = 127.0.0.1

  8. # Disabling symbolic-links is recommended to prevent assorted security risks

  9. symbolic-links=0


  10. # 设置salve mysql id,不和master重复

  11. server-id=101

  12. # 开启并配置slave的binlog文件名称

  13. log-bin=mysql-slave-bin

  14. # 配置binlog中继文件

  15. log-bin=mysql-slave-bin

重启mysql-b,让配置生效:

  1. docker restart mysql-b

配置从库从主库复制数据:

  1. change master to master_host='172.29.0.2',

  2. master_user='slave_01',

  3. master_password='slave_01',

  4. master_port=3306,

  5. master_log_file='mysql-bin.000001',

  6. master_log_pos=154,

  7. master_connect_retry=30

  • master_host:master的host

  • master_user:用于复制数据用的账号

  • master_password:用户复制数据用的账号密码

  • master_port:master的端口

  • masterlogfile:master的binlog的File名称,在show master status命令可以查出来

  • masterlogpost:master的binlog的Position,在show master status命令可以查出来

  • masterconnectretry:连接重试时间,单位:秒

开启主从复制:

  1. start slave;

查看开启状态:

  1. show slave status \G;

如果看到:

  • SlaveSQLRunning: YES

  • SlaveIORunning: YES

  • SlaveSQLRunning_State: Slave has read all relay log; waiting for more updates

那么主从复制就已经配置完成了。

验证是否完成主从复制

我们可以在mysql-a添加一条数据,然后到mysql-b上面看,是不是有新添加的数据。

有就表示主从复制已经完成,没有就表示主从复制没有完成。

半同步复制优化

我们到这里是搭建好了MySQL的主从复制,但是有个问题,它是异步复制的。在一些极端条件下会导致数据问题。比如master插入一条数据并成功提交事务了,这个时候binlog还没有同步到slave,master就宕机了。当主从发生切换后,新的master是没有旧的master新插入的那条数据的。

解决这个问题,业界有个方案:半同步。这里不展开说半同步的原理,只说怎么实现半同步主从复制。

安装半同步插件

在master上安装半同步插件:

  1. # 安装插件

  2. install plugin rpl_semi_sync_master soname 'semisync_master.so';

  3. # 开启插件

  4. setglobal rpl_semi_sync_master_enabled=1;

  5. # 查询是否开启了半同步,Rpl_semi_sync_master_status=ON表示半同步开启

  6. show status like 'Rpl%';

配置mysql重启后加载半同步插件:

vim /etc/mysql/mysql.conf.d/mysqld.cnf

  1. # 半同步插件加载

  2. plugin-load=rpl_semi_sync_master=semisync_master.so

  3. # 打开主的半同步

  4. rpl_semi_sync_master_enabled=1

在slave上安装半同步插件:

  1. # 安装插件

  2. install plugin rpl_semi_sync_slave soname 'semisync_slave.so'

  3. # 开启插件

  4. setglobal rpl_semi_sync_slave_enabled=1;

  5. # 重启同步线程

  6. stop slave io_thread;

  7. start slave_io_thread;

  8. # 查询是否开启了半同步,Rpl_semi_sync_slave_status=ON表示半同步开启

  9. show status like 'Rpl%';

配置mysql重启加载半同步插件:

vim /etc/mysql/mysql.conf.d/mysqld.cnf

  1. # 从库半同步插件加载

  2. plugin-load=rpl_semi_sync_slave=semisync_slave.so

  3. # 打开从的半同步

  4. rpl_semi_sync_slave_enabled=1

到这里就开启了半同步。

从库设置为只读

我们配置主从复制的时候,一般是不允许从库写入的,这样会导致数据不一致,因为从库数据无法同步给到主库。所以我们一般会把从库设置为只读。

  1. # 查看只读状态,read_only=ON是开启,OFF是关闭

  2. show global variables like "%read_only%";

  3. # 给所有表加上读锁

  4. flush tables with read lock;

  5. # 设置只读

  6. setglobal read_only=1;


  7. # 如果想解除只读,执行下面两行命令即可

  8. unlock tables;

  9. setglobal read_only=0;

注意点

我们安装的mysql容器,是没有vim工具的,需要我们自行安装,安装步骤:

  1. apt-get update

  2. apt-get install vim


浏览 31
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报