MySQL主从复制
目录
内容概述
1.什么是主从复制?
2.为什么要做主从?
3.主从复制原理
4.主从复制的日志格式
5.主从复制的方式
内容详细
1.什么是主从复制?
将主服务器的binlog日志复制到从服务器上执行一便,达到主从数据的一致状态,称之为主从复制
# 一句话来讲述就是,主数据做什么,从数据库就跟着做什么
2.为什么要做主从?
1)为实现读写分离做铺垫
1.什么是读写分离?
有了主从保持数据一致作为大前提,我们便可以可以分离读写操作,其中Master负责写操作的负载,也就是说一切写的操作都在Master上进行,而读的操作则分摊到Slave上进行。
2.读写分离有什么意义?
读写分离可以大大提高读取的效率
我们经过一些调查得出结论,读/写的比例大概在 10:1 左右 ,也就是说写操作非常少,大量的数据操作是集中在读的操作。
此时我们可以制作一主多从,因为写操作很少,所以由一个主库负责即可,而大量的读操作则分配给多个从库,这样占据比例最大的读操作的压力就被负载均衡了,因此读效率会得到了极大的提升。
3.具体做法
方案一:就是主库写,从库读
方案二:主库负责写,还有部分读,从库只负责读,而且是读操作的主力
即当主服务器比较忙时,部分查询请求会自动发送到从服务器中,以降低主服务器的工作负荷
2)通过复制实现数据的异地备份,保障数据安全
1.可以定期的将数据从主服务器上复制到从服务器上,这实现了数据的异地备份.
2.异地备份的好处是不会降低主服务器的性能,并且不会因为主服务器发生意外而造成数据丢失,保证了数据安全。
3)提高数据库系统的可用性
1.数据库复制功能实现了主服务器与从服务器之间数据的同步,增加了数据库系统的可用性。
2.从库临时取代主库,只用来读
主服务器故障之后,虽然从服务器取代了主服务器的位置,但是对于主服务器可以采取的操作仍然做了一些限制,例如仍然只能够进行数据的查询,而不能够进行数据的更新、删除等操作。这主要是基于从数据的安全性考虑。
3.从库永久取代主库,负责读和写
从服务器真正变成了主服务器。当从服务器切换为主服务器之后,其地位完全与原先的主服务器相同。此时可以实现对数据的查询、更新、删除等操作。为此就需要做好数据的安全性工作。即数据的安全策略,要与原先的主服务器完全相同。否则的话,就可能会留下一定的安全隐患.
3.主从复制原理
一般来说,主从复制有三个步骤
1.配置、准备好主数据库服务器
2.配置、准备好从服务器
3.在从库上进行主从复制
1) master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events)。
2) slave的io线程将master的binary log events拷贝到它的中继日志(relay log)。
3) slave的sql线程解析中继日志中的事件并在从库执行,保持与主库一致。
复制过程有一个很重要的限制——复制在slave上是串行化的,也就是说master上的并行更新操作不能在slave上并行操作。
4.主从复制的日志格式
这里的日志格式就是指二进制日志的三种格式
binlog_format=statement
binlog_format=row
binlog_format=mixed
其中基于row的复制方式更能保证主从库数据的一致性,但日志量较大,在设置时考虑磁盘的空间问题
5.主从复制的方式
MySQL的主从复制有两种复制方式,分别是异步复制和半同步复制
异步复制
原理
异步复制,即客户端线程提交一个写操作,写入主库的binlog日志后就立即返回,并不需要等待从库完成同步操作,而主库的dump线程会监测binlog日志的变量然后主动将更新推送给从库。
MySQL 主从复制默认是异步的模式。
异步复制部署
# 主库准备
1.首先要保证主从库上安装的MySQL版本一致
2.我们选择一台纯净linux主机二进制安装MySQL5.7,ip:192.168.174.52 # 生产环境中MySQL数据库时无论如何不能暴露在公网中的,切记!
3.我们在主库上创建一个账号专门用来进行主从复制,并赋予replication slave权限,这里必须 是*.* ,不能指定库授权,因为 replication slave 是全局的。
mysql> grant replication slave on *.* to 'lty'@'%' identified by '123';
mysql> flush privileges;
4.我们配置好主库的配置文件,并设置server-id # server-id唯一
[mysqld]
# 节点ID,确保唯一
server-id = 1
#开启mysql的binlog日志功能
log-bin = mysql-bin
#控制数据库的binlog刷到磁盘上去 , 0 不控制,性能最好,1每次事物提交都会刷到日志文件中,性能最差,最安全
sync_binlog = 1
#binlog日志格式
binlog_format = row
#binlog过期清理时间
expire_logs_days = 7
#binlog每个日志文件大小
max_binlog_size = 100m
#binlog缓存大小
binlog_cache_size = 4m
#最大binlog缓存大小
max_binlog_cache_size= 512m
#不生成日志文件的数据库,多个忽略数据库可以用逗号拼接,或者 复制黏贴下述配置项,写多行
binlog-ignore-db=mysql
# 表中自增字段每次的偏移量
auto-increment-offset = 1
# 表中自增字段每次的自增量
auto-increment-increment = 1
#跳过从库错误
slave-skip-errors = all
5.重启主库,并备份主库的数据
systemctl restart mysqld
mysqldump -uroot -p -A -E -R --triggers --triggers --master-data=2 --single-transaction > /root/full.sql # 当然,我们也可以压缩
会提示输入密码,输入即可
6.将别分文件发送给从库即可
scp /root/full.sql root@192.168.174.53:/root
# 此时就没主库什么事了,我们该去准备从库了
# 从库准备
1.我们在纯净的linux主机中安装MySQL5.7
2.导入主库的数据
mysql -uroot -p < /root/full.sql
3.修改从库的配置文件,增加server-id,注意这个值是唯一的,要区别于主库和其他从库
[mysqld]
basedir=/usr/local/mysql
datadir=/mysql_data
port=3306
socket=/usr/local/mysql/mysql.sock
character-set-server=utf8mb4
log-error=/var/log/mysqld.log
pid-file=/tmp/mysqld.pid
server-id=3
# 中继日志
relay-log=mysql-relay-bin
replicate-wild-ignore-table=mysql.%
replicate-wild-ignore-table=test.%
replicate-wild-ignore-table=information_schema.%
[mysql]
socket=/usr/local/mysql/mysql.sock
[client]
socket=/usr/local/mysql/mysql.sock
# 从库也可以开启binlog,但通常关闭
4.重启从库
5.先去主库查看binlog日志名与位置
mysql> show master status;
mysql> show master status;
+-----------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------+----------+--------------+------------------+-------------------+
| mybinlog.000004 | 1965 | | mysql | |
+-----------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
6.配置主从复制
change master to
master_host='172.16.1.52',
master_port=3306,
master_user='lty',
master_password='123',
master_log_file='mybinlog.000004',
master_log_pos=1965;
# 开启主从复制
mysql> start slave;
# 查看主从复制结果
mysql> show slave status\G
结果如下图,即代表主从复制配置成功
异步复制存在的问题
MYSQL5.5之前版本的主从复制都是异步(asynchronous)的,而在异步复制中,主库执行完操作后,写入binlog日志后,就返回客户端,这一动作就结束了,主库并不会验证从库有没有收到binlog日志、以及收到的binlog是否完整,那如果主库提交一个事务并写入Binlog中后,当从库还没有从主库得到Binlog时,主库宕机了或因磁盘损坏等故障导致该事务的Binlog丢失了,那从库就不会得到这个事务,也就造成了从库与主库数据不一致的问题,我们也就无法使用备库来继续提供数据一致的服务了。而半同步复制可以解决该问题。
半同步复制
原理
1.一个事务操作的完成需要记完两份日志,即主从的binlog是同步的
半同步复制,当主库每提交一个事务后,不会立即返回,而是等待其中一个从库接收到Binlog并成功写入Relay-log中才返回客户端,所以这样就保证了一个事务至少有两份日志,一份保存在主库的Binlog,另一份保存在其中一个从库的Relay-log中,从而保证了数据的安全性和一致性。
2.半同步即并非完全同步
半同步复制的“半”体现在,虽然主从库的Binlog是同步的,但主库不会等待从库的sql线程执行完Relay-log后才返回,而是确认从库的io线程接收到Binlog,达到主从Binlog同步的目的后就返回了,所以从库的数据对于主库来说还是有延时的,这个延时就是从库sql线程执行Relay-log的时间。所以只能称为半同步。
3.半同步复制超时则会切换回异步复制,正常后则切回半同步复制
在半同步复制时,如果主库的一个事务提交成功了,在推送到从库的过程当中,从库宕机了或网络故障,导致从库并没有接收到这个事务的Binlog,此时主库会等待一段时间(这个时间由rpl_semi_sync_master_timeout的毫秒数决定),如果这个时间过后还无法推送到从库,那MySQL会自动从半同步复制切换为异步复制,当从库恢复正常连接到主库后,主库又会自动切换回半同步复制。
半同步复制开启方法
半同步模式是作为MySQL5.5的一个插件来实现的,主从库使用的插件不一样
1.先确认主从的MySQL服务器是否支持动态增加插件
mysql> select @@have_dynamic_loading;
+------------------------+
| @@have_dynamic_loading |
+------------------------+
| YES |
+------------------------+
1 row in set (0.00 sec)
2.分别在主从库上安装对应的插件
# 插件一般默认在MySQL安装目录/lib/plugin下,可以去查看一下是否存在
ls /usr/lib64/mysql/plugin/ | grep semisync
# 主库的插件是semisync_master.so,从库是semisync_slave.so
主库> install plugin rpl_semi_sync_master soname 'semisync_master.so';
从库> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
# 安装完成后,在plugin表(系统表)中查看一下
select * from mysql.plugin;
3.主库开启半同步复制
主库:
#启动插件
mysql> set global rpl_semi_sync_master_enabled=1;
#设置超时
mysql> set global rpl_semi_sync_master_timeout=30000;
#修改配置文件
[root@db01 ~]# vim /etc/my.cnf
#在[mysqld]标签下添加如下内容(不用重启库,因为上面已经开启了)
[mysqld]
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000
从库:
#启动插件
mysql> set global rpl_semi_sync_slave_enabled=1;
#重启io线程使其生效
mysql> stop slave io_thread;
mysql> start slave io_thread;
#编辑配置文件(不需要重启数据库)
[root@mysql-db02 ~]# vim /etc/my.cnf
#在[mysqld]标签下添加如下内容
[mysqld]
rpl_semi_sync_slave_enabled =1
4.查看半同步复制状态
-- 主库查看
mysql> show status like 'Rpl_semi_sync_master_status';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_status | ON |
+-----------------------------+-------+
1 row in set (0.00 sec)
-- 从库查看
mysql> show status like 'Rpl_semi_sync_slave_status';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
1 row in set (0.00 sec)