当单台 MYSQL 服务器无法满足当前网站流量时的优化方案。需要搭建 mysql 集群技术。
复制方式:
- 主–从复制(读写分离)主–主复制 (都可进行读写)
同步方式
- 异步(mysql默认方式)同步(不推荐,很耗性能)半同步(介于同步和异步之间)
异步复制
MySQL复制默认是异步复制,Master将事件写入binlog,提交事务,自身并不知道slave是否接收是否处理;
缺点:不能保证所有事务都被所有slave接收,数据上可能会发生不一致问题
同步复制
Master提交事务,直到事务在所有slave都已提交,才会返回客户端事务执行完毕信息;
缺点:完成一个事务可能造成延迟,导致性能损失严重,但是保证了数据的一致性,
半同步复制
当Master上开启半同步复制功能时,至少有一个slave开启其功能。当Master向slave提交事务,且事务已写入relay-log中并刷新到磁盘上,slave才会告知Master已收到;若Master提交事务受到阻塞,出现等待超时,在一定时间内Master 没被告知已收到,此时Master自动转换为异步复制机制;
注:这种方式也不是一定的数据就不丢失只是比异步复制好多了, 性能方面也不会损失太多.
复制原理:
Mysql 中有一种日志叫做 bin 日志(二进制日志)。这个日志会记录下所有修改了数据库的SQL 语句(insert,update,delete,create/alter/drop table, grant 等等)。
主从复制的原理其实就是把主服务器上的 bin 日志复制到从服务器上执行一遍,这样从服务器上的数据就和主服务器上的数据相同了。
复制过程:
- 主节点必须启用二进制日志,记录任何修改了数据库数据的事件。从节点开启一个线程(I/O Thread)把自己扮演成 mysql 的客户端,通过 mysql 协议,请求主节点的二进制日志文件中的事件主节点启动一个线程(dump Thread),检查自己二进制日志中的事件,跟对方请求的位置对比,如果不带请求位置参数,则主节点就会从第一个日志文件中的第一个事件一个一个发送给从节点。从节点接收到主节点发送过来的数据把它放置到中继日志(Relay log)文件中。并记录该次请求到主节点的具体哪一个二进制日志文件内部的哪一个位置(主节点中的二进制文件会有多个,在后面详细讲解)。从节点启动另外一个线程(sql Thread ),把 Relay log 中的事件读取出来,并在本地再执行一次。
虽然我这里使用的是docker方式,但是普通模式的mysql一样的操作
环境:主节点:192.168.0.196从节点:192.168.0.198mysql版本:mysql8.0.16linux:centos8docekr: 20.10.8 主节点
进入mysql容器里
docker exec -it mysql8.0.16 /bin/bash
肯能没有vi命令这个自行安装
vi /etc/mysql/my.cnf
server_id=1 log_bin=master_log
退出docker 容器
exit
重启MySql (dcoekr)
docker restart mysql8.0.16
然后在进入mysql容器里,之后连接mysql
mysql -u root -p
创建子节点连接主节点的账户
create user 'myslave'@'192.168.0.198' identified by 'myslave'; GRANT ALL ON *.* TO 'myslave'@'192.168.0.198'; flush privileges;
'myslave'@'192.168.0.198'这句话的意思就是只能是192.168.0.198这个ip通过myslave账户才能登录此mysql`
然后查看状态
show master status;
注意: 上面的File 和Position后面需要用到
查询server_id
show variables like 'server_id';从节点
进入mysql容器里
docker exec -it mysql8.0.16 /bin/bash
修改配置
vi /etc/mysql/my.cnf
server_id=2
重启MySql (dcoekr)
docker restart mysql8.0.16
然后在进入mysql容器里,之后连接mysql
mysql -u root -p
然后先关闭子节点同步,然后添加主节点配置
stop slave
添加主节点配置
CHANGE MASTER TO MASTER_HOST='192.168.42.146', MASTER_USER='myslave', MASTER_PASSWORD='myslave', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=3796;
注意:MASTER_LOG_FILE 为上图查询出来的,MASTER_LOG_POS 为上图的 position 查出来的
启动子节点同步
start slave;
在slave上查看主从同步状态
show slave statusG;
开启主从之后,如果状态如上图所示,那么说明主从信息就已经配置好了,
mysql是虚拟机克隆的话那么会报错
The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be diff
解决办法: mv /usr/mysql/data/auto.cnf /usr/mysql/data/auto.cnf.bk 然后重启mysql
测试同步情况 主主配置演示: 环境:节点1:
主节点:192.168.0.196 server-id=1
从节点:192.168.0.197 server-id=2
节点2:
主节点:192.168.0.198 server-id=3
从节点:192.168.0.199 server-id=4
注意: 所有节点的server-id不能重复,包括子节点,
mysql版本:mysql8.0.16linux:centos8docekr: 20.10.8
假设我们已经搭建好了2个主从节点了,那么此刻有两种模式提供选择
- 主备(当主节点宕机后,可以及时切换到备用节点)双写(就是2个节点任意一个节点进行写的操作都会相互同步数据)
就是两台M节点都要进行写入,网上都说调整auto_increment_increment和offset那两个参数可以达到双写不冲突的作用,但是这个做法有前提条件的,
- 主键必须是自增列必须只有insert操作,如果一个事务中有insert又有update,那么双写是不行的,会有问题,更何况还有唯一索引的问题。
那么有解决双写的问题吗?,可以分库分表,然用业务逻辑进行关联处理就行了.规则需要自己进行定义
修改双主的配置文件进入docker ->mysql里->vi /etc/mysql/my.cnf
第一个主(192.168.0.196)
#任意自然数,保证两台MySQL主机不重复 server-id=1 #开启二进制日志 log-bin=mysql-bin #步进值auto_imcrement。一般有n台主MySQL就填n auto_increment_increment=2 #起始值。一般填第n台主MySQL。此时为第一台主MySQL auto_increment_offset=1
配置完毕重启mysql
第二个主(192.168.0.198)
#任意自然数,保证两台MySQL主机不重复 server-id=2 #开启二进制日志 log-bin=mysql-bin #步进值auto_imcrement。一般有n台主MySQL就填n auto_increment_increment=2 #起始值。一般填第n台主MySQL。 auto_increment_offset=2
配置完毕重启mysql
查询双主的bin文件信息进入docker ->mysql里
SHOW MASTER STATUS;创建登录用户
在第一个主节点(192.168.0.196) 里创建账号用于第二个主节点(192.168.0.198)登录使用
create user 'myMaster1'@'192.168.0.198' identified by 'myMaster1'; GRANT ALL ON *.* TO 'myMaster1'@'192.168.0.198'; flush privileges;
'myMaster1'@'192.168.0.198' 这句话的意思就是只能是192.168.0.198这个ip通过myMaster1账户才能登录此mysql
在第二个主节点(192.168.0.198)里创建账号用于第一个主节点(192.168.0.196)登录使用
create user 'myMaster2'@'192.168.0.196' identified by 'myMaster2'; GRANT ALL ON *.* TO 'myMaster2'@'192.168.0.196'; flush privileges;双主(主备)
在第二个节点(192.168.0.198)进行下面操作,将第二个主节点作为子节点,关联到第一个主节点中进行数据同步
注意: LOG_FILE和MASTER_LOG_POS填写第一个主节点查询出来的bin文件信息
# 先关闭子同步 stop slave; # 在配置从子同步 CHANGE MASTER TO MASTER_HOST='192.168.0.196', MASTER_USER='myMaster1', MASTER_PASSWORD='myMaster1', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=1129; # 打开子同步 start slave; # 查看状态 show slave statusG;
看到上面两个yes那么就代表配置成功了,我们可以在主节点数据库操作看看子节点变化没
注意: 不能在子节点进行操作,否则会导致同步失败
开启主备后我们还需要使用keepalived或者haproxy来实现高可用才行…
双主(双写)在主备的基础上双向开启同步就行了,在上面主备中我们已经完成了第二个主节点监听第一个主节点的同步了,那么我们只需要将第一个主节点监听第二个主节点,这样就形成双向通道了
在第一个节点(192.168.0.196)进行下面操作,将第一个主节点作为子节点,关联到第二个主节点中进行数据同步
注意: LOG_FILE和MASTER_LOG_POS填写第二个主节点查询出来的bin文件信息
# 先关闭子同步 stop slave; # 在配置从子同步 CHANGE MASTER TO MASTER_HOST='192.168.0.198', MASTER_USER='myMaster2', MASTER_PASSWORD='myMaster2', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=1129; # 打开子同步 start slave; # 查看状态 show slave statusG;
如果双主节点的状态都是下面yes那么就完成了
然后我们就在各自的数据库中操作下看看对方有没有发生变化
其实Mysql半同步复制并不是严格意义上的半同步复制。当半同步复制发生超时时(由rpl_semi_sync_master_timeout参数控制,单位是毫秒,默认为10000,即10s),会暂时关闭半同步复制,转而使用异步复制。当master dump线程发送完一个事务的所有事件之后,如果在rpl_semi_sync_master_timeout内,收到了从库的响应,则主从又重新恢复为半同步复制。
配置方式: 需要在主从配置的基础上进行配置
先检测子节点的同步状态show slave statusG;
然后修改主配置文件添加下面参数
server-id=1 log-bin=mysql-bin plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so" rpl_semi_sync_master_enabled = 1
然后修改从配置文件添加下面参数
server-id=2 plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so" rpl_semi_sync_slave_enabled = 1
之后重启主从数据库,然后查询主从节点的半同步状态
主节点查询: show status like 'Rpl_semi_sync_master_status';
从节点查询: show status like 'Rpl_semi_sync_slave_status';
重启从同步
先查询主的binlog信息show master status;
然后在从上输入下面命令
STOP SLAVE; RESET SLAVE; CHANGE MASTER TO MASTER_HOST='192.168.42.146', MASTER_USER='myslave', MASTER_PASSWORD='myslave', MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=155; START SLAVE; # 重启从数据库上的IO线程(必须的,不然没法使用) STOP SLAVE IO_THREAD; START SLAVE IO_THREAD; show slave statusG;
然后自己试试在主数据库中修改那么从数据库也会发生变化
使用主从模式,永远都要是主写,子读,如果子进行写的话,那么就会报错,然后同步就会卡主了,一直报错
当然以上只是一种情况,比如数据库宕机了,…其他异常情况,都会发送同步失败…以下是通用解决方法
遇到同步失败的情况解决办法:
将主和从数据结构保持一致(可以使用navicat进行数据结构同步)
关闭子同步stop slave;
重置子同步 reset slave;
查询主信息
重新配置子
然后查询子状态


![Mysql-[主从-主主(主备,双写)-半同步]之(Docker版) Mysql-[主从-主主(主备,双写)-半同步]之(Docker版)](http://www.mshxw.com/aiimages/31/748639.png)
