MySQL主从复制架构
mysql的主从复制,是一个老牌技术了,发展了很多年,也运用了很多年
主从、也就是有一个master机器、以及一个、或者多个slave机器,用于数据的同步、备份。
MySQL数据库的主从复制技术与使用scp/rsync等命令进行的异机文件级别复制类似,都是数据的远程传输,只不过MySQL的主从复制技术是其软件自身携带的功能,无须借助第三方工具
并且,MySQL的主从复制并不是直接复制数据库磁盘上的文件,而是将逻辑的记录数据库更新的binlog日志发送到需要同步的数据库服务器本地,然后再由本地的数据库线程读取日志中的SQL语句并重新应用到MySQL数据库中,从而即可实现数据库的主从复制。
MySQL主从复制介绍
MySQL数据库支持单向、双向、链式级联、环状等不同业务场景的主从复制。
在复制过程中,一台服务器(严格来讲是实例)作为主数据库(Master),接收来自用户的、对其内容的更新,而一个或多个其他的服务器则作为从服务器(Slave),接收来自主服务器binlog文件的日志内容,然后将该日志内容解析出的SQL语句重新应用到其他从服务器中,使得主从服务器数据达到一致。
如果设置了链式级联复制,那么,从服务器本身除了作为从服务器之外,也会同时作为其下面从服务器的主数据库服务器。链式级联复制形式类似于A==>B==>C。
双主、双向同步(互为主从)
双向主、主的复制架构,可以在master1或者master2都可以写入数据,也可以同时写入数据(需要额外配置)
线性级联、单向双主复制
环状级联、单向多主复制
官网mysql复制架构图
在当前的生产工作环境中,MySQL主从复制默认都是异步的复制方式,即不是严格实时的数据同步,但是在正常情况下带给用户的体验几乎都是实时的(延迟的情况见后文讲解)。
为什么用主从复制
MySQL主从复制集群技术使得MySQL数据库支持大规模高并发的读写操作成为可能,同时又能有效地解决物理服务器宕机场景的数据备份和进行快速业务切换的问题。
对于企业生产环境来说,MySQL主从复制主要有以下几个重要的应用场景。
salve作为master实时数据备份
主从服务器架构的设计,可以大大加强MySQL数据库架构的健壮性。例如,当主服务器出现问题时,我们可以人工切换或设置成自动切换到从服务器继续提供服务,此时从服务器的数据和宕机时的主数据库几乎是一致的。
这有些类似于NFS存储数据通过inotify+rsync将数据同步到备份的NFS服务器,只不过MySQL的复制方案是其自带的工具,实现的方式是逻辑的复制,而非文件层级的复制。
缺点
利用MySQL的主从复制技术进行数据备份,在硬件故障、软件故障、人为在数据库外误操作的场景下,该数据备份是有效的;但对于人为地在数据库中执行drop、delete等语句删除数据的情况,从库的备份功能就没有用了,因为从服务器也会执行删除的语句。
slave与master实现读写分离
MySQL主从服务器架构可通过程序(PHP、Java等)或代理软件(maxscale、atlas)实现对用户(客户端)的请求按读和写进行分离访问,
即让从服务器仅仅处理用户的select(查询)请求,以降低用户查询的响应时间及同时在主服务器上读写所带来的访问压力。
对于更新的数据(例如update、insert、delete语句)仍然会交给主服务器处理,以确保主服务器和从服务器保持实时同步。
百度、淘宝、新浪等绝大多数的网站都是用户浏览的页面多于用户发布内容的页面,因此通过在从服务器上接收只读请求,就可以很好地减轻主库的读压力
且从服务器可以很容易地扩展为多台,使用LVS进行负载均衡(读写分离软件自身大多也有负载均衡的功能),效果就非常棒了,这就是传说中的数据库读写分离架构。
读写分离架构
通过程序代码,可以通过设置多个连接文件,实现对数据库的读写分离
逻辑
- 当关键字是select,读取slave从库
- 当update、insert、delete,连接master库,写入
读写分离,是程序代码,对整体程序架构改造实现
mysql自身无法直接实现读写分离
能够实现读写分离的一些工具
有如下开源软件可以实现
- Maxscale
- Atlas
- Mycat
可以实现mysql的读写分离,且支持负载均衡
读写分离原理图
主从复制原理
MySQL的主从复制是一个异步的复制过程(虽然一般情况下感觉是实时的),数据将从一个MySQL数据库(我们称之为Master)复制到另一个MySQL数据库(我们称之为Slave),在Master与Slave之间实现整个主从复制的过程是由三个线程
参与完成的。
其中有两个线程(SQL线程和IO线程)在Slave端,另外一个线程(binlog dump线程)在Master端(MySQL 5及以前是3个线程完成复制,从MySQL 6起SQL线程可以是多个)。
要实现MySQL的主从复制功能,首先必须打开Master端的binlog日志功能。
因为整个复制过程实际上就是Slave从Master端获取binlog日志,然后再在Slave上以相同的顺序执行获取的binlog日志中所记录的各种SQL操作,从而实现主从数据一致的功能。
配置文件如下
[mysqld]
user=mysql
port=3307
socket=/data/3307/mysql.sock
basedir=/application/mysql-5.6.40-linux-glibc2.12-x86_64/
datadir=/data/3307/data
log-bin=/data/3307/mysql-bin # 这里是定义二进制日志文件,用于复制
server-id=6
secure_file_priv= ''
#general_log=on
#general_log_file=/data/3307/data/mysql-server56.log
# slow-log
slow-query-log = ON #<==慢查询开启开关
long_query_time = 2 #<==记录大于2秒的SQL语句。
log_queries_not_using_indexes = ON #<==没有使用到索引的SQL语句。
slow-query-log-file = /data/3307/slow.log #<==记录SQL语句的文件。
min_examined_row_limit = 800 #<==记录结果集大于800行的SQL语句。
# 编码
character-set-server=utf8
详细原理过程
-
slave机器
start slave
,开启主从复制 -
slave机器的I/O线程会通过在master上已授权的复制用户,连接master服务器
- 通过该用户再从指定的binlog日志文件的指定位置,发送binlog日志的内容
- (binglog文件名,pos值,都通过change master命令指定了)
-
Master服务器接收到slave的I/O线程请求之后,负责复制的binlog dump线程会根据slave服务器的I/O线程的请求信息,进行读取binlog,以及pos值之后的日志信息
- 然后返回给slave的I/O线程
- 返回的信息除了binlog日志内容以外,以及master服务端新的binlog文件,以及POS值
-
slave此时的I/O线程接收到master发来的日志信息后,将binlog日志内容,写入到slave本身的
relay-log中继日志中,如mysql-relay-bin.xxxxxx
的末端
- 并且记录新的binlog文件信息,名字、pos值,写入master-info文件中,用于下一次读取binlog数据时,可以明确知道数据读取的起点
-
slave服务器的SQL线程会实时监测本地的Relay Log新增的日志内容,然后将Reloy Log文件中的内容,解析为SQL语句,且在自身slave按顺序执行这些SQL。
经过这些,就可以确保,master和slave执行了同样的SQL。
在复制状态正常
的情况下,master和slave的数据是完全一样的。
复制小结
- 主从复制是异步的进行SQL语句的复制
- 复制时,主库有一个
binlog dump 线程
,从库有2个线程I/O线程
、SQL线程
- 在MySQL5.6之后,slave的SQL线程有多个
- 实现主从复制的必要条件、主库开启binlog,基于binlog复制
- 用于复制的所有mysql节点,server-id不能相同
- binlog文件只记录数据库有
更改
的SQL,(主数据库有变化),对select、show
以及未修改数据库的语句不会记录
主从复制实践
mysql主从复制、机器数量可以是
- 单机、单数据库多实例
- 多台服务器、每个机器单独部署数据库
于超老师这里使用2台linux虚拟机
环境
master 10.211.55.12 3306
slave1 10.211.55.9 3306
分别安装启动好mysql,配置参考超哥前面的笔记
检查数据库状态
# 参考超哥安装笔记
http://127.0.0.1:4000/DBA/MySQL%E5%A4%9A%E5%AE%9E%E4%BE%8B%E7%AE%A1%E7%90%86.html#%E5%AE%89%E8%A3%85%E6%B5%81%E7%A8%8B
确认两个服务器,是否正确启动了mysql,
master
root
yuchao668
[root@mysql-server56 3306]# clear
[root@mysql-server56 3306]# netstat -tunlp|grep mysql
tcp6 0 0 :::3306 :::* LISTEN 3015/mysqld
[root@mysql-server56 3306]#
slave
root 空密码
[root@chaoge_slave1 3306]#
[root@chaoge_slave1 3306]# netstat -tunlp|grep mysql
tcp6 0 0 :::3306 :::* LISTEN 19802/mysqld
[root@chaoge_slave1 3306]#
master主库操作
master复制操作,必须开启binlog
[root@mysql-server56 3306]# cat /data/3306/my.cnf
[client]
port=3306
socket=/data/3306/mysql.sock
[mysqld]
user=mysql
port=3306
socket=/data/3306/mysql.sock
basedir=/application/mysql-5.6.40-linux-glibc2.12-x86_64/
datadir=/data/3306/data
log-bin=/data/3306/mysql-bin # 这里必须开启
server-id=5 # 这里必须不一样
[mysqld_safe]
log-error=/data/3306/mysql_3306_error.log
pid-file=/data/3306/mysqld_3306.pid
检查主库binlog状态
[root@mysql-server56 3306]# mysql -p -S /data/3306/mysql.sock -e "show variables like 'log_bin'"
Enter password:
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+--