MySQL的主从复制
主从复制概述
在我们日常的数据库运维中,经常会因为各种原因需要停止数据库,比如MySQL版本升级,服务器硬件升级等,如果没有备份的话很容易造成数据丢失,且可用性降低。MySQL的主备可以提高数据库的可用性。
MySQL几乎所有的高可用架构,都直接依赖于binlog。虽然这些高可用架构已经呈现出越来越复杂的趋势,但都是从最基本的一主一备演化过来的。
主从复制原理
主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。
- binlog 线程 :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
- I/O 线程 :负责从主服务器上读取二进制日志,并写入从服务器的中继日志(Relay log)。
- SQL 线程 :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中执行。
一个完整的流程:
备库B跟主库A之间维持了一个长连接。主库A内部有一个线程,专门用于服务备库B的这个长连接。一个事务日志同步的完整过程是这样的:
- 在备库B上通过change master命令,设置主库A的IP、端口、用户名、密码,以及要从哪个位置开始请求binlog,这个位置包含文件名和日志偏移量。
- 在备库B上执行start slave命令,这时候备库会启动两个线程,就是图中的io_thread和sql_thread。其中io_thread负责与主库建立连接。
- 主库A校验完用户名、密码后,开始按照备库B传过来的位置,从本地读取binlog,发给B。
- 备库B拿到binlog后,写到本地文件,称为中转日志(relay log)。
- sql_thread读取中转日志,解析出日志里的命令,并执行。
binlog有三种格式,一种是statement(记录执行的SQL语句),一种是row(具体记录对某一行的具体操作),另一种是前两种的混合mixed。
注:MySQL的主从复制是从接入点开始同步的
配置方法
step1:修改主库my.ini(windows)配置文件
[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
[mysqld]
#设置3306端口
port = 3306
# 设置mysql的安装目录
# 设置mysql数据库的数据的存放目录
# 允许最大连接数
max_connections=200
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
#=========主从复制关键配置=====================
server_id=1 #主库和从库需要不一致,配一个唯一的ID编号,1至32。 手动设定
log-bin=mysql-bin #二进制文件存放路径,存放在根目录data
binlog-do-db=test #需要复制的库,多个库用逗号隔开,如果此项不配置所有主库都参与复制
binlog-ignore-db=mysql #不需要复制的库,和上项同理
binlog_format = ROW
#=========主从复制关键配置=====================
保存,重启主库。
step2:修改从库my.cnf(Linux)配置文件
#=========主从复制关键配置=====================
server_id=1 #主库和从库需要不一致,配一个唯一的ID编号,1至32。 手动设定
relay-log=mysql-relay #中继文件存放路径
binlog-do-db=test #需要复制的库,多个库用逗号隔开,如果此项不配置所有主库都参与复制
binlog-ignore-db=mysql #不需要复制的库,和上项同理
#=========主从复制关键配置=====================
保存,重启主库,sudo service mysql restart
step3:主库上创建用户
在主库中建立一个用户(专门用给从库连接的,注意这是在主库里面建立的)
grant replication slave, reload, super on *.* to myslave@localhost identified by 'myslavepassword';
myslave是用户名,myslave密码是用户对应的密码,localhost也可以写ip。
step4:在主库找到日志偏移量
show master status;
找到File 和 Position 的值记录下来。
step5:在从库中执行代码
change master to master_host='127.0.0.1',
master_user='myslave',
master_password='myslave',
master_log_file='binlog.000078', master_log_pos=155;
启动从服务器复制功能start slave
,配置完成。
主备切换
主备切换的可靠性优先策略:
- 判断备库B现在的seconds_behind_master,如果小于某个值(比如5秒)继续下一步,否则持续重试这一步;
- 把主库A改成只读状态,即把readonly设置为true;
- 判断备库B的seconds_behind_master的值,直到这个值变成0为止;
- 把备库B改成可读写状态,也就是把readonly 设置为false;
- 把业务请求切到备库B。
还可以采用可用性优先策略,seconds_behind_master大于0时及切换主备,可能会产生数据不一致的现象。
读写分离
读写分离概述
主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。
读写分离能提高性能的原因在于:
- 主从服务器负责各自的读和写,极大程度缓解了锁的争用;
- 一般读请求比写请求多得多;
- 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销;
- 增加冗余,提高可用性。
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
p.s. 必须先使用MySQL实现主从复制,再用数据库中间件实现读写分离。
主从延迟问题
由于主从可能存在延迟,客户端执行完一个更新事务后马上发起查询,如果查询选择的是从库的话,就有可能读到刚刚的事务更新之前的状态,解决的方案有:
- 强制走主库方案:对于必须要拿到最新结果的请求,强制将其发到主库上。比如,在一个交易平台上,卖家发布商品以后,马上要返回主页面,看商品是否发布成功。那么,这个请求需要拿到最新的结果,就必须走主库。
利用Mycat加注解即可实现:/*#mycat:db_type=master*/ SELECT * FROM tb_item ;
- sleep 方案:主库更新后,读从库之前先sleep一下。这个方案的假设是,大多数情况下主备延迟在1秒之内,做一个sleep可以有很大概率拿到最新的数据。
- 判断主备无延迟方案:先判断seconds_behind_master是否已经等于0,如果还不等于0 ,那就必须等到这个参数变为0才能执行查询请求;或对比位点确保主备无延迟。
- 配合semi-sync:如果启用了semi-sync,就表示所有给客户端发送过确认的事务,都确保了备库已经收到了这个日志。
- 等主库位点方案:trx1事务更新完成后,马上执行
show master status
得到当前主库执行到的File和Position;选定一个从库执行查询语句,在从库上执行select master_pos_wait(File, Position, 1);
,如果返回值是>=0的正整数,则在这个从库执行查询语句;否则,到主库执行查询语句。
Mycat
Mycat概述
MycAT是支持MySQL集群的数据库中间件产品,,提供高可用性数据分片集群。可以像使用mysql一样使用Mycat,对于开发人员来说根本感觉不到Mycat的存在。
Mycat是基于阿里开源的 cobar 演变而来,对 cobar 的代码进行了彻底的重构,使用 NIO 重构了网络模块,并且优化了 Buffer 内核,增强了聚合,Join 等基本特性,同时兼容绝大多数数据库成为通用的数据库中间件。
作用:
- 读写分离
- 数据分片
- 多数据源整合(MySQL、ORACLE、MongoDB)
Mycat原理:
Mycat主要是通过对SQL的拦截,然后经过一定规则的分片解析、路由分析、读写分离分析、缓存分析等,然后将SQL发给后端真实的数据块,并将返回的结果做适当处理返回给客户端。
安装并运行
MyCat的官方网站:http://www.mycat.org.cn/
下载地址:https://github.com/MyCATApache/Mycat-download
第一步:将Mycat-server-1.6-release-20161028204710-linux.tar.gz上传至服务器
第二步:将压缩包解压缩,建议将mycat放到/usr/local/mycat目录下:
tar -xzvf Mycat-server-1.6-release-20161028204710-linux.tar.gz
mv mycat /usr/local
第三步:进入mycat目录的bin目录,启动mycat
./mycat start
停止:
./mycat stop
Mycat的默认端口号为:8066
配置文件
schema.xml作为Mycat中重要的配置文件之一,管理着MycCat的逻辑库、逻辑表以及对应的分片规则、DataNode以及DataSource。
schema标签用于定义Mycat实例中的逻辑库;
table标签定义了Mycat中的逻辑表,rule用于指定分片规则,auto-sharding-long的分片规则是按ID值的范围进行分片 1-5000000 为第1片、5000001-10000000 为第2片…。
dataNode标签定义了Mycat中的数据节点,也就是我们通常说所的数据分片;
dataHost标签在Mycat逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句。
在服务器上创建3个数据库,分别是db1、db2、db3:
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="tb_test" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
</schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost1" database="db2" />
<dataNode name="dn3" dataHost="localhost1" database="db3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="3"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="10.20.32.23:3306" user="root"
password="123456">
<readHost host="hostS1" url="10.20.32.24:3306" user="myuser" password="xxxxxx" />
</writeHost>
</dataHost>
</mycat:schema>
对于读写分离的核心参数为balance,负载均衡类型,目前的取值有4 种:
- “0”:不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上。
- “1”:全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且 M1 与 M2 互为主备),正常情况下,M2,S1,S2都参与 select 语句的负载均衡。
- “2”:所有读操作都随机的在 writeHost、readhost 上分发。
- “3”:所有读请求随机的分发到 wiriterHost 对应的 readhost 执行,writerHost 不负担读压力。
server.xml几乎保存了所有mycat需要的系统配置信息,最常用的是在此配置用户名、密码及权限.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="useSqlStat">0</property>
<property name="useGlobleTableCheck">0</property>
<property name="sequnceHandlerType">2</property>
<property name="processorBufferPoolType">0</property>
<property name="handleDistributedTransactions">0</property>
<property name="useOffHeapForMerge">1</property>
<property name="memoryPageSize">1m</property>
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<property name="systemReserveMemorySize">384m</property>
<property name="useZKSwitch">true</property>
</system>
<user name="user">
<property name="password">user</property>
<property name="schemas">TESTDB</property>
</user>
</mycat:server>
分库与分表
关系型数据库本身比较容易成为系统瓶颈(单表500万,单库5000万),单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库、优化索引,做很多操作时性能仍下降严重。此时就要考虑对其进行切分了,切分的目的就在于减少数据库的负担,缩短查询时间。
垂直切分
垂直切分常见有垂直分库和垂直分表两种。
垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。做法与大系统拆分为多个小系统类似,按业务分类进行独立划分。与"微服务治理"的做法相似,每个微服务使用单独的一个数据库。如图:
操作可参考:https://blog.csdn.net/weixin_38319645/article/details/81537849
垂直切分的优点:
- 解决业务系统层面的耦合,业务清晰;
- 与微服务的治理类似,也能对不同业务的数据进行分级管理、维护、监控、扩展等;
- 高并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈。
垂直切分的缺点:
- 部分表无法join,只能通过接口聚合方式解决,提升了开发的复杂度;
- 分布式事务处理复杂;
- 依然存在单表数据量过大的问题(需要水平切分)。
水平切分
当一个应用难以再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了。
水平切分分为库内分表和分库分表,是根据表内数据内在的逻辑关系,将同一个表按不同的条件分散到多个数据库或多个表中,每个表中只包含一部分数据,从而使得单个表的数据量变小,达到分布式的效果。如图所示:
按行散列的方式有多种,如果采用根据数值范围,会出现热点数据频繁访问的问题,采用根据数值取模方式较好。
配置rule.xml,采用求模法:
<tableRule name="mod-long">
<rule>
<columns>user_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
一致性哈希:一致性哈希的算法简单而巧妙,很容易做到数据均分布,其单调性也保证了扩缩容的数据迁移是比较少的。
跨节点关联查询join
切分之前,系统中很多列表和详情页所需的数据可以通过sql join来完成。而切分之后,数据可能分布在不同的节点上,此时join带来的问题就比较麻烦了,考虑到性能,尽量避免使用join查询。
解决办法有:
全局表
全局表,也可看做是"数据字典表",就是系统中所有模块都可能依赖的一些表,为了避免跨库join查询,可以将这类表在每个数据库中都保存一份。这些数据通常很少会进行修改,所以也不担心一致性的问题。
ER分片
ER分片表:子表的记录与所关联的父表记录存放在同一个数据分片上,避免数据Join跨库操作,以order与order_detail例子为例,schema.xml中定义合适的分片配置,order,order_detail 根据order_id迕行数据切分,保证相同order_id的数据分到同一个分片上,在进行数据插入操作时,Mycat会获取order所在的分片,然后将order_detail也插入到order所在的分片。
<table name="ORDER1" dataNode="dn21,dn22" rule="mod-long">
<childTable name="ORDER_DETAIL" primaryKey="ID" joinKey="ORDER_ID" parentKey="ID"/> </table>
数据组装
在系统层面,分两次查询,第一次查询的结果集中找出关联数据id,然后根据id发起第二次请求得到关联数据。最后将获得到的数据进行字段拼装。
参考:https://zhuanlan.zhihu.com/p/93724977
转载:https://blog.csdn.net/TJtulong/article/details/105718669