目录
在一主多从的数据库体系中,多个从服务器采用异步的方式更新主数据库的变化,业务服务器在执行写或者相关修改数据库的操作是在主服务器上进行的,读操作则是在各从服务器上进行。如果配置了多个从服务器或者多个主服务器又涉及到相应的负载均衡问题,关于负载均衡具体的技术细节还没有研究过,今天就先简单的实现一主一从的主从复制功能。
本文是根据这篇博客自己动手实现的:https://blog.csdn.net/why15732625998/article/details/80463041
首先我们要知道,主从复制是指同步数据的方式,我们是在主从复制的基础上通过读写分离来提升数据库的并发负载能力的。
MySQL的主从复制是一个异步的复制过程(虽然一般情况下感觉是实时的),数据将从一个MySQL数据库(Master)复制到另一个MySQL数据库(Slave),在Master和Slave之间实现整个主从复制的过程是由三个线程参与完成的。其中两个线程(SQL线程和IO线程)在Slave端,另一个线程(I/O线程)在Master端。
要实现MySQL的主从复制,首先必须打开Master端的binlog记录功能,否则就无法实现。binlog: binary log,是主库中保存所有更新事件日志的二进制文件。因为整个复制过程实际上就是Slave从Master端获取binlog日志,然后在Slave上以相同顺序执行获取的binlog日志中的记录的各种SQL操作。
我们根据上图来分析一下整个主从复制的过程:
(1)在Slave服务器上执行start slave命令开启主从复制开关,开始进行主从复制。
(2)此时,Slave服务器的IO线程会通过在master上已经授权的复制用户权限请求连接Master服务器,并请求从执行binlog日志文件中的指定位置(日志文件名和位置就是在配置主从复制服务时执行change master命令指定的)之后开始发送binlog日志内容。
(3)Master服务器接收来自Slave服务器的IO线程的请求后,其上负责复制的IO线程会根据Slave服务器的IO线程请求的信息分批读取指定binlog日志文件指定位置之后的binlog日志信息,然后返回给Slave端的IO线程。返回的信息中除了binlog日志内容外,还有在Master服务器端记录的IO线程。返回的信息中除了binlog中的下一个指定更新位置。
(4)当Slave服务器的IO线程获取到Master服务器上IO线程发送的日志内容、日志文件及位置点后,会将binlog日志内容依次写到Slave端自身的Relay Log(即中继日志)文件(Mysql-relay-bin.xxx)的最末端,并将新的binlog文件名和位置记录到master-info文件中,以便下一次读取master端新binlog日志时能告诉Master服务器从新binlog日志的指定文件及位置开始读取新的binlog日志内容
(5)Slave服务器端的SQL线程会实时检测本地Relay Log 中IO线程新增的日志内容,然后及时把Relay LOG 文件中的内容解析成sql语句,并在自身Slave服务器上按解析SQL语句的位置顺序执行应用这样sql语句,并在relay-log.info中记录当前应用中继日志的文件名和位置点
每个Slave只有一个Master
每个Slave只能有一个唯一的服务ID
每个Master可以有多个Slave
延时
主从同步延迟原理和解决方案: https://www.cnblogs.com/cnmenglang/p/6393769.html
注意:MySQL版本号最好一致,为了方便学习测试,建议关闭防火墙
MySQL的主从复制并不完美,存在着几个由来已久的问题,首先一个问题是复制方式:
SBR的优点
SBR的缺点:
RBR的优点
RBR 的缺点:
混合方式就是有mysql自动选择RBR方式和SBR方式,能够充分发挥两种方式的优点,一般情况下都使用该种方式实现主从复制
这种方式虽然能够大大提高主从复制的效率,减小主从复制的延时,但也存在问题,具体请参看下面的博客。
https://blog.csdn.net/guotao521/article/details/45483833
http://hamilton.duapp.com/detail?articleId=47
主服务器Master
开启二进制日志 binlog 配置唯一的server-id 获得master二进制文件名及位置 创建一个用于slave和master通信的用户账号
配置唯一的server-id 使用master分配的用户账号读取master二进制日志 启动slave服务
主数据库
的配置文件my.cnf(或者my.ini),我的在/etc/my.cnf,在[mysqld]部分插入如下:[mysqld] #开启二进制日志 log-bin=mysql-bin #设置server-id,建议使用ip最后3位 server-id=140
从数据库
的配置文件my.cnf(或者my.ini),我的在/etc/my.cnf,在[mysqld]部分插入如下:#开启中继日志 relay-log=mysql-relay #设置server-id,建议使用ip最后3位 server-id=141
systemctl restart mysqld.service
GRANT REPLICATION SLAVE ON *.* TO 'mysql141'@'192.168.131.141' IDENTIFIED BY 'mysql141'; flush privileges; --查询master的状态 show master status\G
记录上图结果中File和Position的值。
注意:执行完此步骤后不要再操作主服务器MySQL,防止主服务器状态发生状态值变化。
这里要根据上面主服务器的状态来填写,不要直接用下面的SQL,需要根据实际值修改。
CHANGE MASTER TO master_host = '192.168.131.140', master_user = 'mysql141', master_password = 'mysql141', master_log_file = 'mysql-bin.000001', master_log_pos = 120;
//开启复制 start slave; //查看主从复制是否配置成功 SHOW SLAVE STATUS\G
当看到Slave_IO_State:Waiting for master ot send event 、Slave_IO_Running: YES、Slave_SQL_Running: YES才表明状态正常。
注:如果Slave_IO_Running:connnecting,可能是防火墙没关,我就遇到这个情况了。关闭一下,然后关闭slave重新连接:
systemctl stop firewalld.service
Master中和Slave中执行SQL
SHOW DATABASES; //在Master中创建数据库并创建数据表并插入一条数据 create database haha; use haha; create table tab1(id int auto_increment,name varchar(10),primary key(id)); insert into tab1(id,name) values (1,'test');
成了,MySQL主从复制就实现了。
show master status: 查看master的状态,尤其是当前的日志及位置 show slave status 查看slave的状态 reset slave 重置slave状态 start slave 启动slave状态 stop slave 暂停slave状态
绝大多数的企业的应用场景对于数据库来说都是读多写少,比如微博,明星发一条微博,上千万人读。所以为了分担数据库压力,做负载均衡,首先考虑到的就是读写分离,读写分离基于上面实现的主从复制,使用主库作为写库,从库为读库,提高数据库性能,提高IO性能。
为了实现读写分离,出现了很多解决方案,其中比较流行的是采用中间件做为Proxy,保持应用层代码不随数据库的变动而发生变化,这里包括Amoeba、Atlas、Cobar、Mycat、MySQL Proxy等,而Mycat是目前开源的数据库中间件中比较成熟的解决方案。可以说Mycat真的非常强大,但是建议慎重考虑使用,具体原因请自行百度mycat发起人和Mycat社区现状。
但我们以学习的目的进行使用还是非常好的,Mycat确实非常强大,我们可以学习他的思想和技术。所以我们使用Mycat中间件作为读写分离的实现方式。
《Mycat权威指南》和《分布式数据库架构及企业实践-基于mycat中间件》两本书都介绍的非常详细。
原文链接:https://www.cnblogs.com/joylee/p/7513038.html
Mycat官网:http://www.mycat.io/ 可以了解下Mycat的背景和应用情况,这样使用起来比较有信心。
Mycat下载地址:http://dl.mycat.io/ 官网有个文档,属于详细的介绍,初次入门,看起来比较花时间。
下载: 建议大家选择 1.6-RELEASE 版本,毕竟是比较稳定的版本。
安装: 根据不同的系统选择不同的版本。包括linux、windows、mac,作者考虑还是非常周全的,当然,也有源码版的。
Mycat的安装其实只要解压下载的目录就可以了,非常简单。
安装完成后,目录如下:
配置
Mycat的配置文件都在conf目录里面,这里介绍几个常用的文件:
我们现在做一个主从、读写分离,简单分表的示例。结构如下图:
Mycat作为主数据库中间件,肯定是与代码弱关联的,所以代码是不用修改的,使用Mycat后,连接数据库是不变的,默认端口是8066。连接方式和普通数据库一样,如:jdbc:mysql://192.168.0.2:8066/。
我们只针对mycat实现简单的读写分离,更多其他特性如分库分表切片的功能请参看上面推荐的书,这里只针对简单的读写分离的配置。
我们真实的物理数据库名称为 itoo_cloud,包含一个表 ta_user,以免大家对后面的配置不明白。
server.xml
<user name="root"> <property name="password">root</property> <property name="schemas">itoo</property> <property name="readOnly">false</property> <!-- 表级 DML 权限设置 --> <!-- <privileges check="false"> <schema name="TESTDB" dml="0110" > <table name="tb01" dml="0000"></table> <table name="tb02" dml="1111"></table> </schema> </privileges> --> </user>
重点关注下面这段,其他默认即可
我这里配置了一个账号root密码也是root,针对逻辑数据库itoo(自己定义别名,不是真实的物理数据库),读写权限都有,没有针对表做任何特殊的权限。
<?xml version="1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="itoo" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"/> <dataNode name="dn1" dataHost="auth" database="itoo_cloud" /> <dataHost name="auth" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <writeHost host="hostM" url="192.168.131.140:3306" user="root" password="root"> <readHost host="hostS1" url="192.168.131.141:3306" user="test" password="test" /> </writeHost> </dataHost> </mycat:schema>
注意:读库的用户test是添加的mysql用户,只具有读权限的用户:
GRANT Select ON *.* TO 'test'@'%' IDENTIFIED BY "test"
下面是关于每个节点的配置说明;
Mycat的启动也非常简单,进入到bin目录下:
##启动 ./mycat start ##停止 ./mycat stop ##重启 ./mycat restart
如果在启动时发现异常,在logs目录中查看日志。
wrapper.log 为程序启动的日志,启动时的问题看这个
mycat.log 为脚本执行时的日志,SQL脚本执行报错后的具体错误内容,查看这个文件。mycat.log是最新的错误日志,历史日志会根据时间生成目录保存。
mycat启动后,执行命令不成功,可能实际上配置有错误,导致后面的命令没有很好的执行。
使用navicat连接mycat,如下图所示,注意端口为8066。
测试写,插入一条数据,查看是否成功,查看从库是否数据已经同步过去