数据库的双机热备与读写分离

2022-10-27 16:18:05 浏览数 (2)

三范式和反三范式

代码语言:javascript复制
第一范式:所以字段不可再分(关系型数据库天生支持)
第二范式:所有非主键字段必须完全依赖主键字段,不能
出现部分依赖。
第三范式:在二范式的基础上消除传递依赖
互联网初期,没有什么高并发的概念,而且硬件非常昂贵
所以在数据库的设计上几乎都是选取时间换空间的三范式
表结构以及使用单机数据库。

但是时代在进步,社会在发展,高并发和分布式的概念也越来越火热,单机版的数据库已经不能满足如今的互联网,所以就有了mysql的读写分离和主从复制。

mysql主从复制的原理

代码语言:javascript复制
#当前mysql在集群中的编号不能重复
server-id=
#开启mysql binlog日志
log-bin=mysql-log

在mysql的配置文件中添加上面两行配置(window系统为mysql数据存储路径下的my.in文件,linux系统在 etc 里面的my.cnf文件)。配置完成之后,主节点就开启binlog日志,在从节点的配置中只需要指定从节点在集群中的编号即可,在从节点中会开前io和sql两个线程,io线程负责登陆主节点监控和抓取主节点的binlog日志信息到当前节点的relay中继日志中,sql线程负责执行中继日志中抓取到的sql语句,从而实现mysql的主从复制。

主从复制的具体实现

登陆主节点查看主节点信息

代码语言:javascript复制
mysql> show master statusG;
*************************** 1. row ***************************
             File: mysql-log.000005 二进制文件名称
         Position:   binlog日志指针位置
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
 row in set (0.00 sec)

登陆从节点挂载到主节点上

代码语言:javascript复制
CHANGE MASTER TO
MASTER_HOST='10.9.104.184', --> 主节点ip地址
MASTER_PORT=, -->主节点mysql端口号
MASTER_USER='root',
MASTER_PASSWORD='root',
MASTER_LOG_FILE='mysql-log.000002',-->主节点二进制文件名称
MASTER_LOG_POS=主节点指针位置

最后不要忘了在从节点上执行如下sql,开启从节点角色

代码语言:javascript复制
start slave

mysql的双机热备

其实就是让两个mysql互为主从,上述操作在两个mysql中换着操作一下就好

mysql的读写分离

在一个mysql集群中读写在不同的节点上操作,会大大的提升当前mysql集群的工作效率。但是这非常考验中间件的计算能力,下面介绍一下常用的中间件。

数据库常见的中间件

Cobar

阿里 b2b 团队开发和开源的,属于 proxy 层方案,就是介于应用服务器和数据库服务器之间。应用程序通过 JDBC 驱动访问 Cobar 集群,Cobar 根据 SQL 和分库规则对 SQL 做分解,然后分发到 MySQL 集群不同的数据库实例上执行。早些年还可以用,但是最近几年都没更新了,基本没啥人用,差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨库 join 和分页等操作。

TDDL

淘宝团队开发的,属于 client 层方案。支持基本的 crud 语法和读写分离,但不支持 join、多表查询等语法。目前使用的也不多,因为还依赖淘宝的 diamond 配置管理系统。

Atlas

360 开源的,属于 proxy 层方案,以前是有一些公司在用的,但是确实有一个很大的问题就是社区最新的维护都在 5 年前了。所以,现在用的公司基本也很少了。

Sharding-jdbc

当当开源的,属于 client 层方案,目前已经更名为 ShardingSphere(后文所提到的 Sharding-jdbc,等同于 ShardingSphere)。确实之前用的还比较多一些,因为 SQL 语法支持也比较多,没有太多限制,而且截至 2019.4,已经推出到了 4.0.0-RC1 版本,支持分库分表、读写分离、分布式 id 生成、柔性事务(最大努力送达型事务、TCC 事务)。而且确实之前使用的公司会比较多一些(这个在官网有登记使用的公司,可以看到从 2017 年一直到现在,是有不少公司在用的),目前社区也还一直在开发和维护,还算是比较活跃,个人认为算是一个现在也可以选择的方案。

mycat

Mycat 基于 Cobar 改造的,属于 proxy 层方案,支持的功能非常完善,而且目前应该是非常火的而且不断流行的数据库中间件,社区很活跃,也有一些公司开始在用了。但是确实相比于 Sharding jdbc 来说,年轻一些,经历的锤炼少一些。 主要介绍一下mycat是如何实现数据库的故障转移,和读写分离的

基于mycat的一些配置

进入mycat的conf目录下会有一些mycat的配置文件,下面我来一 一解读

server.xml
代码语言:javascript复制
[root@10-42-99-103 conf]# vim server.xml

                <!--<property name="processorExecutor">16</property>-->
                <!-- 
                        <property name="mutiNodeLimitType">1</property> 0:开启小数量级(默认) ;1:开启亿级数
据排序
                <property name="mutiNodePatchSize">100</property> 亿级数量排序批量
                        <property name="processors">32</property> <property name="processorExecutor">32</property> 
                        <property name="serverPort">8066</property> <property name="managerPort">9066</property> 
                        <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property> 
                        <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
        </system>
        <user name="root">
                <property name="password">root</property>
                <property name="schemas">mycatdb</property>
        </user>

        <!--<user name="user">
                <property name="password">user</property>
                <property name="schemas">TESTDB</property>
                <property name="readOnly">true</property>
        </user>-->
        <!-- 
        <quarantine> 
           <whitehost>
              <host host="127.0.0.1" user="mycat"/>
              <host host="127.0.0.2" user="mycat"/>
           </whitehost>
       <blacklist check="false"></blacklist>
        </quarantine>
        -->

</mycat:server>
代码语言:javascript复制
配置mycat作为服务器的一些资源配置,端口占用,线程数量
连接数量,登录用户,权限设置。
<system> 
包含了mycat作为一个软件需要配置的所以系统信息
<property name="defaultSqlParser">druidparser</property>
默认的sql语句拦截器阿里的德鲁伊拦截器,maycat作为一个数据库
的中间件,需要对前端连接的sql语句进行拦截。
<property name="useCompression">1</property><!--1为开启mysql压缩协议-->
<user>
定义了可以访问登陆mycat的用户信息和权限
<quarantine> 
mycat的防火墙可以进行安全级别的配置
<whitehost>
访问mycat的白名单(ip地址 和用户名)
<blacklist check="false"></blacklist>
sql语句的黑名单
可以定义什么sql语句可以被执行,什么样的sql语句不能被执行
schema.xml
代码语言:javascript复制
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/" >

        <schema name="mycatdb" checkSQLschema="true" sqlMaxLimit="100">
                <!--mstest.user demo01-->
               <table name="t_order" primaryKey="order_id" dataNode="dn1,dn2"
                rule="easymall-order">
                        <childTable name="t_order_item"
                                primaryKey="ID" joinKey="order_id" parentKey="order_id"/>
                </table>
        </schema>
        <!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743" 
                                     /> -->
        <dataNode name="dn1" dataHost="localhost1" database="easydb" />
        <dataNode name="dn2" dataHost="localhost2" database="easydb" />

        <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
                writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <!--hostM1 HOSTM1S1 HOSTM1S2 HOSTM1S3
                                                             HOSTM2 HOSTM2S1 HOSTM2S2-->
                <writeHost host="hostM2" url="10.42.167.114:3306" user="root"
                        password="root">
                </writeHost>
        </dataHost>

        <dataHost name="localhost2" maxCon="1000" minCon="10" balance="1"
                writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostM1" url="10.42.99.103:3306" user="root"
                        password="root">
                </writeHost>
        </dataHost>
代码语言:javascript复制
<schema>
定义mycat中作为服务器给客户端使用的逻辑库,逻辑库中的数据
可以来源于一个真是库,也可以来源于多个真实库。
<schema name="mycatdb" checkSQLschema="true" sqlMaxLimit="100">
checkSQLschema:是否自动添加库名作为表的前缀
sqlMaxLimit="100"每次查询最多查100条数据
<table>  定义逻辑库中的逻辑表,逻辑表的名字必须与真实表的名字保持一致
<table name="company" primaryKey="ID" dataNode="dn3,dn2,dn1" rule="mod-long"/>
name:逻辑表的名字
primaryKey:逻辑表的主键默认为ID(不区分大小写)
dataNode:定义当前逻辑表的数据分片来源
代码语言:javascript复制
使用mycat实现数据库读写分离,故障转移的高可用结构
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
	writeType="0" dbType="mysql" 
		dbDriver="native" switchType="1"  slaveThreshold="100">
switchType(默认为1)可以-1也可以1,为1时支持故障转移,当主节点
	发生故障宕机后会在writeHost中进行故障转移,实现数据库的高可用
writeType(默认为0)在当前dataHost的主从结构中,写操作只会在第一个writeHost中
进行。writeType=1:1.5版本后的mycat不推荐使用,因为在新版本中,读逻辑分离
开来由balance控制,如果writeType=1覆盖掉读逻辑,读写都随机在所有
的writeHost中完成,写操作会随机的在所有的writeHost中进行
读逻辑控制:(balance)
balance可以有0,1,2,3四个值当balance的值为0时(默认值也是0)不开启读的
分离,所有读操作都在第一个writeHost中进行。当balance的值为1时,开启读的分离
所有读操作大量分散在除第一个writeHost之外的所有writeHost和readHost中,当并发量
很大时,第一个writeHost也会分担一部分。当balance的值为2时读操作随机到所有的host
中执行。当balance的值为3时,所有的读操作都会分散到readHost中去,如果不存在readHost
则读操作会到第一个writeHost中去执行。
一般来讲,常见的读写分离配置为writeType=0,balance=1

使用mycat实现数据库的分布式结构(分片表格)
可以在schema.xml中的table标签中的dataNode属性中配置不同的数据分片
再根据rule属性配置相应的分片的匹配规则从而达到数据库的分布式的效果
rule.xml

为了实现mycat在不同数据分片中的数据一致性,mycat在rule.xml中定义了很多分片计算的规则。

全局表

因为mycat不支持跨分片查询,所以当有了多表联查的情景出现时 可能因为关联的表分散在两个不同的分片,可能出现数据丢失的 情况。当被关联的表的量不是很大,变化也不是很频繁的数据稳定 的情况下,可以把这张表放在所有的分片中,这张表就叫做全局表

全局表的特点

数据稳定,变化不大,量不大的工具字典表。

全局表的实现

在schema.xml的文件中定义逻辑表的时候不是用rule属性 改为 type="global"即可。

代码语言:javascript复制
<table name="cat_test" primaryKey="ID" type="global"
dataNode="dn1,dn2"/>

ER分片表

思考全局表的概念,如果被关联的的表的量很大,数据变动很大 怎么办被关联的表还能用作全局表吗,如果可以,那么我们将表 进行水平拆分放在不同的库还有什么意义?所以就有了ER分片表的 概念,连接ER分片表之前要先理解什么是主表,什么是子表,子表 的数据是基于主表而存在,假设有两张表,一张表是北京市的父亲表 (父亲id,父亲姓名),另外一张表是北京市的儿子表(儿子id,儿子姓名) 为了使两张表产生关联,父亲id作为主键放到儿子表中。这时候儿子 表是基于父亲表存在的,如果父亲表没有了,就没有了关联的意义, 父亲表就是主表,儿子表就是子表,在使用分片计算逻辑时,对父亲 id进行运算就OK了,这就是ER分片表的设计思路。

ER分片表的实现

在schema.xml文件中使用如下配置定义逻辑表即可

代码语言:javascript复制
<schema name="mycatdb" checkSQLschema="true" sqlMaxLimit="100">
           <!--mstest.user demo01-->
          <table name="father" primaryKey="father_id" dataNode="dn1,dn2"
           rule="father-child"> <!在rule.xml中将hash一致性算法的逻辑复置一份即可>
                   <childTable name="child"
                           primaryKey="ID" joinKey="father_id" parentKey="father_id"/>
           </table>
</schema>

0 人点赞