基于MyCat实现的Mysql数据库的读写分离

1、数据切分

1.1、原因

  在传统的业务场景中,数据量不大、并发量不高,所以单机的数据库服务基本上就可以满足了业务需要。而在互联网时代,数据爆发式增加,数据量和并发量都急剧增加,这对单机数据库就带来许多的挑战。为了解决单机数据库的瓶颈问题,我们就需要对数据库进行切分,把大库变成多个小库。

1.2、数据切换

  为了实现大库变成多个小库,就需要对数据库进行数据切分。数据切分,就是通过一些规则,将原来存储在单机数据库的数据,分散到多个数据库(一般都多主机)中,从而达到降低单台数据库负载的压力。数据切分,一般分为垂直切分和水平切分两种。

1.2.1、垂直切分

  垂直切分就是按照不同的表或者Schema切分到不同的数据库中。垂直切分的特点就是规则简单,易于实施,可以根据业务模块进行划分,各个业务之间耦合性低,相互影响也较小。

垂直切分的优点:

  • 拆分后业务清晰,拆分规则明确;
  • 系统之间容易扩展和整合;
  • 数据维护简单

垂直切分的缺点:

  • 跨库的数据没有办法进行关联查询,只能通过接口调用,提升了系统的复杂度;
  • 跨库事务需要处理;
  • 垂直切分后,大表仍然存在单体性能瓶颈;
1.2.2、水平切分

  水平切分,主要是将一个表中的数据,根据某种规则拆分到不同的数据库的表中,相比垂直切分,更为复杂。

水平切分的优点:

  • 解决了单库大数据、高并发的性能瓶颈;
  • 拆分规则封装好,对应用端几乎透明,开发人员无需关心拆分细节;
  • 提高了系统的稳定性和负载能力;

水平切分的缺点:

  • 拆分规则很难抽象;
  • 跨库的数据没有办法进行关联查询
  • 分片事务一致性难以解决;
  • 二次扩展时,数据迁移、维护难度大。

2、读写分离

  大多数互联网业务,往往读多写少,这时候,数据库的读操作往往会首先称为数据库的瓶颈,这时,如果我们希望能够线性的提升数据库的读性能,消除读写锁冲突从而提升数据库的写性能,那么就可以使用读写分离的架构。

  读写分离一般都采用数据库的双机热备功能实现,即第一台数据库服务器,是对外提供增删改业务的服务;第二台数据库主要进行读的操作。·

  将大量的读操作从数据库中剥离,让读操作从专用的读数据库中读取数据,大大缓解了数据库的访问压力,也使得读取数据的响应速度得到了大大的提升。读写分离就是解决数据库性能瓶颈的“银弹”吗?如果主从数据库之间的同步出现延迟、甚至宕掉了该怎么办呢?这就是读写分离的弊端,当主从间的数据同步挂掉,或者同步延迟比较大时,写库和读库的数据不一致,对于实时要求比较高的系统,用户可能无法接受这个数据的不一致问题。

3、 MyCat概述

  MyCat 是什么?从定义和分类来看,它是一个开源的分布式数据库系统,前端的用户可以把它看成一个数据库代理,用MySql客户端和命令行工具都可以访问,而其后端则是用MySql原生的协议与多个MySql服务之间进行通信。MyCat的核心功能是分库分表,即将一个大表水平切分成N个小表,然后存放在后端的MySql数据当中。

  MyCat发展到目前的版本,已经不是一个单纯的MySql代理了,它的后端支持MySql,Oracle,SqlServer,DB2等主流的数据库,也支持MongoDB这种NoSql数据库。而对于前端的用户来说,无论后端采用哪一种数据库,在MyCat里都是一个传统的数据库,支持标准的SQL语句,对于前端的开发人员来说,可以大大地降低开发难度,提升开发速度。

  • 对于DBA来说,可以这样理解MyCat:
    MyCat就是MySql,而MyCat后面连接的MySql,可以理解为MySql中的存储引擎,比如:MyISAM、InnoDB等。所以,MyCat本身不存储数据,数据都是存储在MyCat后面连接的MySql上,数据的可靠性和事务都是MySql保证的。
  • 对于开发人员,可以这样理解MyCat:
    MyCat就是一个近似等于MySql的数据库库服务,你可以使用连接MySql的方式连接MyCat。绝大多数情况,你也可以使用常用的ORM框架连接MyCat,但是,对于分片的表,还是建议使用标准SQL语句,这样能够达到最佳的性能。
  • 对于架构师来说,可以这样理解MyCat:
    MyCat是一个强大的数据库中间件,不仅仅可以用作读写分离、分库分表,还可以用于容灾备份,云平台建设等,让你的架构具备很强的适应性和灵活性。

上述内容来至于慕课网的Java架构师课程的教学笔记。

MyCat中的基本概念
  • 逻辑库(Schema)
    数据库中间件可以被看做是一个或者多个数据库集群构成的逻辑库。对于开发人员不需要知道数据库中间件的存在,开发人员只需要有数据库的概念就可以了。
  • 逻辑表(table)
    对于应用系统来说,读写数据的表,就是逻辑表。而逻辑表中的数据,则是被水平切分后,分布在不同的分片库中。对于开发人员来说,只需要操作逻辑表即可,后续的分片细节对开发人员来说是透明的。
  • 分片表
    针对数据量非常大,需要我们进行数据水平切分的表,我们把它叫做分片表。没有切分的叫非分片表。
  • 全局表
    在实际业务中,有大量的字典表存在,为了避免跨库查询,我们会把这些不需要分片的表,通过数据冗余的方式复制到所有的分片库中的表,叫做全局表。
  • 分片节点(dataNode)
    数据被切分后,一张大表被分到不同的分片数据库上面,每个分片表所在的数据库就叫做分片节点。
  • 节点主机(dataHost)
    数据切分后,每一个分片节点不一定都会占用一个真正的物理主机,会存在多个分片节点在同一个物理主机上的情况,这些分片节点所在的主机就叫做节点主机。为了避免单节点并发数的限制,尽量将读写压力高的分片节点放在不同的节点主机上。
  • 分片规则(rule)
    一个大表被拆分成多个分片表,就需要一定的规则,按照某种业务逻辑,将数据分到一个确定的分片当中,这个规则就叫做分片规则。
  • 全局序列号(sequence),即分布式全局ID
    在数据进行水平切分后,我们需要保证每个分片上的数据记录的ID都是唯一的,这个时候使用库表的自增规则肯定是无法满足要求的,这时,我们需要借助外部的机制保证数据的唯一标识,这种保证数据唯一标识的机制,我们叫做全局序列号。

4、基于MyCat实现读写分离

4.1、环境准备

  基于MyCat实现读写分离,需要准备MySQl的主从环境,具体搭建方式,请参考《MySql5.7 数据库安装及主从同步配置》

4.2、下载MyCat

MyCat下载地址:http://dl.mycat.org.cn/1.6.7.4/Mycat-server-1.6.7.4-release/

或者通过wget命令下载:

wget http://dl.mycat.org.cn/1.6.7.4/Mycat-server-1.6.7.4-release/Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz
4.3、解压
tar -zxvf Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz

解压后的目录:
在这里插入图片描述

4.4、配置server.xml

  修改该文件,主要用来配置MyCat账号密码和数据库名。

<mycat:server xmlns:mycat="http://io.mycat/">
	<system>
		 <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
		<property name="nonePasswordLogin">0</property>
		<!--省略了其他的属性配置,详细请参考server.xml配置文件--->
	</system>
	
	<!-- 全局SQL防火墙设置 -->
	<!--白名单可以使用通配符%或着*-->
	<!--例如<host host="127.0.0.*" user="root"/>-->
	<!--例如<host host="127.0.*" user="root"/>-->
	<!--例如<host host="127.*" user="root"/>-->
	<!--例如<host host="1*7.*" user="root"/>-->
	<!--这些配置情况下对于127.0.0.1都能以root账户登录-->
	<firewall>
	   <whitehost>
	      <host host="1*7.0.0.*" user="root"/>
		  <host host="*" user="root" />
	   </whitehost>
       <blacklist check="false">
       </blacklist>
	</firewall>
	<!--配置了写操作用户,其中name为用户名,password为用户密码,schemas为逻辑库名称-->
	<user name="root" defaultAccount="true">
		<property name="password">123456</property>
		<property name="schemas">db_test</property>
		<property name="defaultSchema">db_test</property>
		<!--No MyCAT Database selected 错误前会尝试使用该schema作为schema,不设置则为null,报错 -->
		
		<!-- 表级 DML 权限设置 -->
		<!-- 		
		<privileges check="false">
			<schema name="TESTDB" dml="0110" >
				<table name="tb01" dml="0000"></table>
				<table name="tb02" dml="1111"></table>
			</schema>
		</privileges>		
		 -->
	</user>
	<!--配置了user用户,设置readOnly=true,表示该用户是用来读操作的-->
	<user name="user">
		<property name="password">123456</property>
		<property name="schemas">db_test</property>
		<property name="readOnly">true</property>
		<property name="defaultSchema">db_test</property>
	</user>
</mycat:server>

4.5、配置schema.xml

  schema.xml文件主要是用来配置mycat逻辑库与真实的MySQL数据库的映射关系了。其中涉及到了一下几个元素:

  • schema mycat逻辑库配置,与server.xml中的数据库对应,然后通过dataNode管理对应的写操作数据节点
  • dataNode 数据节点,主要用来关联真实的数据节点dataHost的信息和对应的真实数据库名称。其中,name,用来设置节点名称,供schema 节点引用,dataHost表示真实数据库的配置信息,database真实的数据库名称。
  • dataHost 真实数据库的配置信息节点,包括数据读写策略的一些配置。其中还包括了heartbeat心跳节点、writeHost 写库配置信息等。
  • writeHost 写库配置信息。主要用来配置写库信息,dataHost 节点下可以有多个writeHost 写库配置。而writeHost 元素下又可以配置读库配置readHost 节点。
  • readHost 读库配置信息节点。

  其中,dataHost 节点中有几个属性balance、writeType、switchType,他们的含义如下:

balance属性:

  • balance=“0”, 不开启读写分离机制,所有读操作都发送到当前可用的writeHost 上。
  • balance=“1”,全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1 ->S1 , M2->S2,并且 M1 与 M2 互为主备),正常情况下, M2,S1,S2 都参与 select 语句的负载均衡。
  • balance=“2”,所有读操作都随机的在 writeHost、 readhost 上分发。
  • balance=“3”, 所有读请求随机的分发到 wiriterHost 对应的 readhost 执行,writerHost 不负担读压力,注意 balance=3 只在 1.4 及其以后版本有, 1.3 没有。

writeType属性:

  • writeType=“0”, 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个writeHost,重新启动后已切换后的为准,切换记录在配置文件中:dnindex.properties .
  • writeType=“1”,所有写操作都随机的发送到配置的 writeHost。
  • writeType=“2”,没实现。

switchType属性:

switchType=“-1”, 表示不自动切换
switchType=“1”, 默认值,自动切换
switchType=“2”, 基于MySQL 主从同步的状态决定是否切换

  我们这里主要为了实现读写分离,所以最后的配置如下:

<mycat:schema xmlns:mycat="http://io.mycat/">
	<!--name的值需要和servler.xml文件中的一致,然后需要添加dataNode属性-->
	<schema name="db_test" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1"></schema>
	<!--这里name值可以自定义,在schema中引用即可,dataHost对应dataHost 节点的name值,database对应真正需要操作的写库名称-->
	<dataNode name="dn1" dataHost="db_host" database="test" />
	<!--这里需要修改balance=3,这样所有读请求随机的分发到 wiriterHost 对应的 readhost 执行,writerHost 不负担读压力,不然,写库可能会用于读操作,不利于后面测试-->
	<dataHost name="db_host" maxCon="1000" minCon="10" balance="3"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<!-- 配置写库信息 -->
		<writeHost host="hostM1" url="192.168.1.8:3306" user="root" password="123456">
				   <!-- 配置读库信息 -->
			 <readHost host="hostS2" url="192.168.1.9:3306" user="root" password="123456" />
		</writeHost>
	</dataHost>
</mycat:schema>
4.6、启动Mycat

  在mycat的bin目录下,执行启动命令:

 ./mycat start
4.7、测试

  启动成功后,使用Navicat连接mycat,方式和连接MySQL一样,不过mycat的默认端口是8066。同时需要在server.xml配置上白名单,不然登录会被拒绝。

  分别使用root、user两个用户(前面在server.xml中配置的)建立连接,我们在主数据库192.168.1.8上,添加数据,这个时候两个连接看见的数据一样,如果我们在从数据库192.168.1.9上添加数据,这个时候就只有user用户的连接可以看到数据(主要为了验证读库操作,这里记得需要设置balance=“3”)。

5、总结

  在这一篇博文中,我们了解了mycat的一些基本知识和基于mycat实现的读写分离,初步了解了mycat的用法。后续在学习的过程中,我们会不断进行尝试和记录,分库分表等尝试将在后续进行。

猜你喜欢

转载自blog.csdn.net/hou_ge/article/details/112919428