Mycat(一)——基本概念和使用


在介绍mycat前,先看一下数据库拆分的几种常见的方式:
数据库拆分

就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果

垂直拆分

在这里插入图片描述

优点

◆ 数据库的拆分简单明了,拆分规则明确;

◆ 应用程序模块清晰明确,整合容易;

◆ 数据维护方便易行,容易定位;

缺点

◆ 部分表关联无法在数据库级别完成,需要在程序中完成,存在跨库join的问题,对于这类的表,就需要去做平衡,是数据库让步业务,共用一个数据源,还是分成多个库,业务之间通过接口来做调用;在系统初期,数据量比较少,或者资源有限的情况下,会选择共用数据源,但是当数据发展到了一定的规模,负载很大的情况,就需要必须去做分割。

◆ 对于访问极其频繁且数据量超大的表仍然存在性能瓶颈,不一定能满足要求;

◆ 事务处理相对更为复杂;

◆ 切分达到一定程度之后,扩展性会遇到限制;

◆ 过多切分可能会带来系统过渡复杂而难以维护。

水平拆分

相对于垂直拆分,水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。
可以将数据的水平切分理解为是按照数据行的切分,就是将表中的某些行切分到一个数据库,而另外的某些行又切分到其他的数据库中
在这里插入图片描述

优点

  • 表关联基本能够在数据库端全部完成;

  • 不会存在某些超大型数据量和高负载的表遇到瓶颈的问题;

  • 应用程序端整体架构改动相对较少;

  • 事务处理相对简单;

  • 只要切分规则能够定义好,基本上较难遇到扩展性限制;

缺点

切分规则相对更为复杂,很难抽象出一个能够满足整个数据库的切分规则;

后期数据的维护难度有所增加,人为手工定位数据更困难;

应用系统各模块耦合度较高,可能会对后面数据的迁移拆分造成一定的困难。

节点合并排序分页问题;

多数据源管理问题。

常见的分片规则

  1. 按照用户ID求模,将数据分散到不同的数据库,具有相同数据用户的数据都被分散到一个库中。

  2. 按照日期,将不同月甚至日的数据分散到不同的库中。

  3. 按照某个特定的字段求摸,或者根据特定范围段分散到不同的库中。

几个原则

  • 能不切分尽量不要切分。
  • 如果要切分一定要选择合适的切分规则,提前规划好。
  • 数据切分尽量通过数据冗余或表分组(Table Group)来降低跨库Join的可能。
  • 由于数据库中间件对数据Join实现的优劣难以把握,而且实现高性能难度极大,业务读取尽量少使用多表Join。

数据切分带来的问题

  • 引入分布式事务的问题;

  • 跨节点 Join 的问题;

  • 跨节点合并排序分页问题;

Mycat

是一个数据库代理

MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储

Mycat并不存储数据,只做数据路由。其会拦截用户发送过来的SQL语句,对SQL语句做一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。

因此,mycat中存在一些逻辑XX性的概念,如逻辑库,逻辑表。

逻辑库(schema)

存在在mycat里面的虚拟库,我们可以通过直接操作逻辑库,而具体的分片、分表还是分库,由我们配置后,交给mycat自动处理。

逻辑表(table)

存在在mycat里面的虚拟表【简单了解下,后面讲用的时候再细讲】

分片表

分片表,是指那些原有的很大数据的表,需要切分到多个数据库的表,这样,每个分片都有一部分数据,所有分片构成了完整的数据

ER表

子表的记录与所关联的父表记录存放在同一个数据分片上,即子表依赖于父表,通过表分组(Table Group)保证数据Join不会跨库操作。

表分组(Table Group)是解决跨分片数据join的一种很好的思路,也是数据切分规划的重要一条规则

全局表

例如字典表,每一个数据分片节点上有保存了一份字典表数据

数据冗余是解决跨分片数据join的一种很好的思路,也是数据切分规划的另外一条重要规则

分片节点(dataNode)

数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点。
在dataNode中可以指定对应的dataHost

节点主机(dataHost)

dataHost,就可以指定我们真实的物理主机的信息。当然,做mycat高可用时,也可以指定某个mycat节点作为“真实主机”。

数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)

分片规则(rule)

前面讲了数据切分,一个大表被分成若干个分片表,就需要一定的规则,这样按照某种业务规则把数据分到某个分片的规则就是分片规则。
如:取模、按天/月分区、固定hash、一致性hash等。

全局序列号(sequence)

数据切分后,原有的关系数据库中的主键约束在分布式条件下将无法使用,因此需要引入外部机制保证数据唯一性标识,这种保证全局性的数据唯一标识的机制就是全局序列号(sequence)。
mycat中有几种实现全局序列号的方式,后面会具体讲。

接下来看看mycat的基础使用:

下载

源码地址:

mycat源码地址

打开后配置启动:
在这里插入图片描述

VM参数:

 -DMYCAT_HOME=${换成源码路径}\src\main
    -XX:MaxDirectMemorySize=512M

首先先简单演示下,不做任何分表分库的操作:

server.xml中添加一个访问mycat逻辑库schemas的用户:

 <user name="cat">
    		<property name="password">123456</property>
    		<property name="schemas">mycatDB</property>
    	</user>

该配置信息为:添加一个name为cat的用户,密码为123456,对应的逻辑库为mycatDB

接着在schema.xml配置:

scheme标签中就是一个逻辑库的配置。

  • scheme:

    name:逻辑库的名字

    sqlMaxLimit=“100” :查询时不会进行分表,会添加limit分页

    dataNode:指定数据节点,与下面的dataNode标签的name对应。

  • dataNode

    一个数据节点。

    name:数据节点的名字(唯一)

    dataHost:与下面的dataHost标签的name对应

    database:物理库的名字

  • dataHost

    一个数据host

    在里面的writeHost,url和user、password为我们实际物理库的连接信息。

  • table:

    table标签共有九个属性:

    • name:对应Mysql中的表名
    • dataNode:逻辑表所在的分片,该属性值需要和dataNode标签的name属性对应,
    • rule:逻辑表使用的分片规则名称,规则在conf/rule.xml中配置,该属性值必须与 tableRule标签中的name属性对应
    • ruleRequired:是否绑定分片规则,如果为true的话,就一定要配置rule,否则会报错
    • primaryKey:逻辑表对应真实表的主键
      type:逻辑表类型,分为全局表和普通表
    • autoIncrement:是否启用自增主键,对应Mysql自增主键,默认时禁用的
    • subTable:分表
    • needAddLimit:是否允许自动添加schema标签中设置的limit,默认为true
<schema name="mycatDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="localdn">
		<!--mycat中的逻辑表-->
		<table name="t_order" dataNode="DN1" primaryKey="orderId" >
		</table>
	</schema>


	<dataNode name="DN1" dataHost="H1" database="consult" />

	<dataHost name="H1" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<!-- can have multi write hosts -->
		<writeHost host="hostM1" url="jdbc:mysql://localhost:3306?useSSL=false" user="root"
				   password="123456">
		</writeHost>
	</dataHost>

配置完成后我们启动mycat工程。

接着搭建一个Springboot工程,我们可以直接连接mycat的逻辑库:

spring.druid.jdbcUrl=jdbc:mysql://localhost:8066/mycatDB?useCompression=true
spring.druid.username=cat
spring.druid.password=123456
spring.druid.driver-class-name=com.mysql.jdbc.Driver

mycat端口号默认为8066,mycatDB就是我们配置的逻辑库的名字,下面的用户名和密码就是逻辑库配置的用户名和密码。

接着写一个单元测试:

 @Test
    public void test1() {
        Area area = new Area ();
        area.setAreaCode("wml");
        area.setAreaName("wml");
        area.setState(1);
        commonMapper.addArea(area);
    }

向consult库中的一个表中插入一条数据。

在这里插入图片描述

插入成功。

分表

scheme.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!--	分表-->
	<schema name="mycatDB" checkSQLschema="true" dataNode="localdn">
		<!--mycat中的逻辑表-->
		<!--
		primaryKey:该逻辑表对应真实表的主键,例如:分片的规则是使用非主键进行分片的,那么在使用主键查询的时候,就会发送查询语句到所有配置的DN上,如果使用该属性配置真实表的主键。难么MyCat会缓存主键与具体DN的信息,那么再次使用非主键进行查询的时候就不会进行广播式的查询,就会直接发送语句给具体的DN,但是尽管配置该属性,如果缓存并没有命中的话,还是会发送语句给具体的DN,来获得数据
		type:全局表:global  每一个dn都会保存一份全局表,普通表:不指定该值为globla的所有表
		-->
		<table name="t_order" dataNode="localdn" autoIncrement="true" subTables="t_order$1-3" primaryKey="order_id" rule="mod-long">
		</table>
	</schema>

	<dataNode name="localdn" dataHost="localhost1" database="consult" />
	
	<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
		<!--heartbeat标签
		MYSQL可以使用select user()
		Oracle可以使用select 1 from dual
		-->
		<heartbeat>select user()</heartbeat>
		<connectionInitSql></connectionInitSql>
		<!-- can have multi write hosts -->
		<!--
		如果writeHost指定的后端数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去
		-->
		<writeHost host="hostM1" url="jdbc:mysql://localhost:3306" user="root"
				   password="123456">
		</writeHost>
	</dataHost>
</mycat:schema>

table标签中有两个属性说明下:

  • subTables
    指定子表,该属性指定主表的子表,t_order$1-3就是t_order1、t_order2、t_order3的缩写。当然也可以用逗号分隔多个表
  • rule:
    指定分片规则,该值与rule.xml中的tableRule的name属性一致:
   <tableRule name="mod-long">
      		<rule>
      			<columns>order_id</columns>
      			<algorithm>mod-long</algorithm>
      		</rule>
      	</tableRule>

columns指定分片操作的列。
algorithm指定分片规则,与rule.xml中的function标签的name属性一致。

<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
      		<property name="count">3</property>
      	</function>

count中指定dataNode的个数

接着测试一下:

首先准备三个分表:

    CREATE TABLE `t_order1` (
      `order_id` int(11) NOT NULL,
      `content` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`order_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    --另外两个t_order2和t_order3一样的,换一个表名即可。

测试插入:

       public void test() {
            for (int i = 0; i < 1000; i++) {
                Order order = new Order();
                order.setOrderId(i);
                order.setContent("wml" + i);
                orderMapper.addOrder(order);
            }
        }
    
    @Insert("insert into t_order(order_id,content) values(#{order_id},#{order_content})")
        int addOrder(Order order);

在这里插入图片描述

可以看到成功插入到三张表中。

再测试查询:

   @Test
        public void test() {
            Order order= orderMapper.querOrderById(877);
            System.out.println(order);
        }

我们根据id查询,id为877,按照规则,877%3=1,mycat应该从t_order2进行查询。

启动后查看mycat日志:

  2020-08-06 22:00:40,661 [DEBUG][$_NIOREACTOR-0-RW] SQLRouteCache add cache ,key:mycatDBselect * from t_order where order_id=877 value:select * from t_order where order_id=877, route={
       1 -> localdn{SELECT *
    FROM t_order2
    WHERE order_id = 877}
    }  (io.mycat.cache.impl.EnchachePool:EnchachePool.java:60) 
    2020-08-06 22:00:40,661 [DEBUG][$_NIOREACTOR-0-RW] ServerConnection [id=36, schema=mycatDB, host=127.0.0.1, user=cat,txIsolation=3, autocommit=true, schema=mycatDB, executeSql=select * from t_order where order_id=877]select * from t_order where order_id=877, route={
       1 -> localdn{SELECT *
    FROM t_order2
    WHERE order_id = 877}
    } rrs   (io.mycat.server.NonBlockingSession:NonBlockingSession.java:126) 

可以看到,会根据id进行hash,直接从第二张表查询。在这之前,会先从缓存中进行查询,缓存没有再从数据库查询。

而如果直接select * from ,就会进行全表查询,发出三个查询语句分别查询三个库进行汇总。

或者可以直接在本地数据库工具连接mycat:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值