Mycat理论基础与配置详解
Mycat简介
Mycat是一个实现了MySQL协议的Server,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而后端可以用MySQL原生协议或JDBC协议与多个MySQL服务器通信,其核心功能是分库分表和读写分离,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或其他数据库里。
官网:http://www.mycat.org.cn/mycat1.html
Mycat核心概念
- 逻辑库
对数据进行分片处理之后,从原来的一个库,被切分为多个分片数据库,所有的分片数据库集群构成了整个完整的数据库存储。Mycat在操作时,使用逻辑库来代表数据库集群,便于对整个集群操作。
- 逻辑表
类似逻辑库
- 分片表
分片表,是指那些数据量很大,需要切分到多个数据库的表。每个分片都有一部分数据。如下mycat配置中的t_node就属于分片表,数据按照规则被分到dn1,dn2两个分片节点上。
<table name="t_node" primaryKey="vid" autoIncrement="true" dataNode="dn1,dn2"
rule="rule1" />
- 非分片表
就是那些不需要进行数据切分的表。如下配置t_node,只存在dn1分片节点上。
<table name="t_node" primaryKey="vid" autoIncrement="true" dataNode="dn1" />
- ER表
Mycat提出了基于E-R关系的数据分片策略,子表的记录与所关联的父表记录存放在同一个数据分片上,即子表依赖于父表,通过表分组保证数据join不会跨库操作。
- 全局表
一个真实的业务系统中,往往存在大量的类似字典表的表,这些表基本上很少变动,字典表具有下面几个特性:
- 变动不频繁
- 数据量总体变化不大
- 数据规模不大,很少超过数十万条记录
业务表与这些字典表之间的关联查询,会比较麻烦。所以Mycat通过数据冗余来解决,即所有分片都有一份字典表的拷贝,所有字典表或者符合字典表特性的一些表定义为全局表。
- 分片节点
数据分片后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点dataNode。
- 节点主机
数据切分后,每个分片节点不一定都会独占一台机器,同一个机器上面可以有多个分片数据库,这样一个或多个分片节点所在的机器就是节点主机,为了规避单节点主机并发数限制,尽量将读写压力高的分片节点均衡的放在不同的节点主机dataHost。
- 分片规则
数据在进行切分的时候需要一定的规则,这种按照业务规则把数据分到某个分片的规则就是分片规则。
配置文件解析
1. server.xml配置
server.xml主要是系统配置信息
1.1 user标签
这个标签主要定义登录mycat的用户和权限。例如下面的例子中,我们定义了一个用户,用户名为user,密码也为user,可访问的schema为lg_edu_order。
<user name="user">
<property name="password">user</property>
<property name="schemas">lg_edu_order</property>
<property name="readOnly">true</property>
<property name="defaultSchema">lg_edu_order</property>
</user>
1.2 firewall标签
<firewall>
<!-- ip白名单 用户对应的可以访问的 ip 地址 -->
<whitehost>
<host host="127.0.0.*" user="root"/>
<host host="127.0.*" user="root"/>
<host host="127.*" user="root"/>
<host host="1*7.*" user="root"/>
</whitehost>
<!-- 黑名单允许的 权限 后面为默认 -->
<blacklist check="true">
<property name="selelctAllow">false</property>
<property name="selelctIntoAllow">false</property>
<property name="updateAllow">false</property>
<property name="insertAllow">false</property>
<property name="deletetAllow">false</property>
<property name="dropAllow">false</property>
</blacklist>
</firewall>
1.3 全局序列号
在实现了分库分表的情况下,数据库自增主键无法保证主键的全局唯一。为此Mycat提供了全局sequence,并提供了包含本地配置和数据库配置等多种实现方式。
<system>
<property name="sequnceHandlerType">0</property>
</system>
0表示使用本地文件方式;1表示使用数据库方式生成;2表示使用本地时间戳方式;3表示基于ZK与本地配置的分布式ID生成器;4表示使用zookeeper递增方式生成
1.3.1 本地文件
此种方式Mycat将sequence配置到文件中,当使用到sequence中的配置后,Mycat会更新文件中的当前值。
#default global sequence
GLOBAL.HISIDS=
GLOBAL.MINID=10001
GLOBAL.MAXID=20000
GLOBAL.CURID=10000
# self define sequence
COMPANY.HISIDS=
COMPANY.MINID=1001
COMPANY.MAXID=2000
COMPANY.CURID=1000
ORDER.HISIDS=
ORDER.MINID=1001
ORDER.MAXID=2000
ORDER.CURID=1000
1.3.2 数据库方式
在数据库中建立一张表,存放sequence名称(name),sequence当前值(current_value),步长(increment) 等信息。
CREATE TABLE MYCAT_SEQUENCE
(
name VARCHAR(64) NOT NULL,
current_value BIGINT(20) NOT NULL,
increment INT NOT NULL DEFAULT 1,
PRIMARY KEY (name)
) ENGINE = InnoDB;
1.3.3 本地时间戳
ID为64位二进制,42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加)换算成十进制为18位数的long类型,每毫秒可以并发12位二进制的累加。
在Mycat下配置sequence_time_conf.properties文件
WORKID=0-31 任意整数
DATAACENTERID=0-31 任意整数
每个Mycat配置的WORKID、DATAACENTERID不同,组成唯一标识,总共支持32*32=1024种组合。
1.3.4 分布式ZK ID生成器
ZK的连接信息统一在myid.properties的zkURL属性中配置。基于ZK与本地配置的分布式ID生成器,InstanceID可以通过ZK自动获取,也可以通过配置文件配置。在sequence_distributed_conf.properties,只要配置INSTANCEID=ZK就表示从ZK上获取 InstanceID。
ID 最大为63位二进制,可以承受单机房单机器单线程 1000*(2^6)=640000 的并发。结构如下
- current time millis(微秒时间戳 38 位,可以使用 17 年)
- clusterId(机房或者 ZKid,通过配置文件配置,5 位)
- instanceId(实例 ID,可以通过 ZK 或者配置文件获取,5 位)
- threadId(线程 ID,9 位)
- increment(自增,6 位)
1.3.5 ZK递增方式
ZK的连接信息统一在myid.properties的zkURL属性中配置。需要配置sequence_conf.properties文件
- TABLE.MINID 某线程当前区间内最小值
- TABLE.MAXID 某线程当前区间内最大值
- TABLE.CURID 某线程当前区间内当前值
2. schema.xml配置
schema.xml作为Mycat中重要的配置文件之一,管理着Mycat的逻辑库、表、分片节点、主机等信息。
2.1 schema标签
schema标签用于定义Mycat实例中的逻辑库,Mycat可以有多个逻辑库,每个逻辑库都有自己相关配置。可以使用schema标签来划分这些不同的逻辑库。
<!-- 逻辑库 -->
<schema name="lg_edu_order" checkSQLschema="true" sqlMaxLimit="100"
dataNode="dn1"></schema>
属性名 | 类型 | 说明 |
---|---|---|
dataNode | String | 分片节点 |
sqlMaxLimit | Integer | 查询返回记录数限制 |
checkSQLschema | boolean | 是否去表库名 |
2.2 table标签
table标签定义了Mycat中的逻辑表,所有需要拆分的表都需要在这个标签中定义
<table name="b_order" dataNode="dn1,dn2" rule="b_order_rule" primaryKey="ID"
autoIncrement="true"/>
属性名 | 类型 | 说明 |
---|---|---|
name | String | 逻辑表名 |
dataNode | String | 分片节点 |
rule | String | 分片规则 |
ruleRequired | boolean | 是否强制绑定分片规则 |
primaryKey | String | 主键 |
type | String | 逻辑表类型,全局表、普通表 |
autoIncrement | boolean | 自增长主键 |
subTables | String | 分表 |
needAddLimit | boolean | 是否为查询SQL自动加limit限制 |
2.3 dataNode标签
dataNode标签定义了Mycat中的分片节点,也就是我们通常所说的数据分片。
<!-- 数据节点 -->
<dataNode name="dn1" dataHost="lg_edu_order_1" database="lg_edu_order_1" />
属性名 | 类型 | 说明 |
---|---|---|
name | String | 数据节点名称,这个名称需要是唯一的 |
dataHost | String | 用于定义分片属于哪个分片主机,属性值是引用 dataHost标签上定义的name属性。 |
database | String | 用于定义该分片节点属于哪个具体的库 |
2.4 dataHost标签
dataHost标签在Mycat逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句。
<dataHost name="lg_edu_order_1" maxCon="100" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1"
slaveThreshold="100">
</dataHost>
属性名 | 类型 | 说明 |
---|---|---|
name | String | 节点主机名 |
maxCon | Integer | 最大连接数 |
minCon | Integer | 最小连接数 |
balance | Integer | 读操作负载均衡类型,0:所有读操作发送到当前可用的writeHost;1:所有读操作发送到readHost和stand by writeHost;2:所有读操作发送到writeHost和readHost;3:所有读操作发送到writeHost对应的readHost上,但是writeHost不参与读 |
writeType | Integer | 写操作负载均衡类型,0:所有写操作发送到writeHost;1:所有写操作发送到readHost;2:所有写操作发送到readHost和writeHost |
dbType | String | 数据库类型 |
dbDriver | String | 数据库驱动 |
switchType | String | 主从切换类型,-1:表示不自动切换;1:表示自动切换;2:基于mysql主从同步状态决定是否切换;3:基于Mysql cluster集群切换机制 |
2.5 heartbeat标签
指明心跳检查的语句
<dataHost>
<heartbeat>select user()</heartbeat>
</dataHost>
2.6 writeHost和readHost标签
writeHost和readHost标签都指定后端数据库的相关配置给Mycat,用于实例化后端连接池。唯一不同的是,writeHost指定写实例、readHos指定读实例。在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去。
<writeHost host="M1" url="192.168.95.133:3306" user="root" password="1234">
</writeHost>
属性名 | 类型 | 说明 |
---|---|---|
host | String | 主机名 |
url | String | 连接字符串 |
password | String | 密码 |
user | String | 用户名 |
weight | String | 权重 |
usingDecrypt | String | 是否对密码加密,默认0 |
3. rule.xml配置
rule.xml用于定义分片规则
3.1 tableRule标签
<tableRule name="c_order_rule">
<rule>
<columns>user_id</columns>
<algorithm>partitionByOrderFunc</algorithm>
</rule>
</tableRule>
属性名 | 类型 | 说明 |
---|---|---|
name | String | 表规则名称 |
columns | String | 要拆分的列名 |
algorithm | String | 使用function标签中的name属性,连接表规则和具体路由算法 |
3.2 function标签
<function name="partitionByOrderFunc"
class="io.mycat.route.function.PartitionByMod">
<property name="count">2</property>
</function>
属性名 | 类型 | 说明 |
---|---|---|
name | String | 算法的名称 |
class | String | 指定路由算法具体的类名字 |
property | String | 具体算法中需要用到的一些属性 |