## mycat
---
`Mycat是java编写的!!!`
### 一、问题
* 目前有哪些好的开源分布式数据框架?
* 引入成本如何?
* 是否支持分布式事务?
* 是否支持动态修改配置项?
* 集群性能如何?
* 社区是否活跃?内部源码?
* mycat如何搭建读写分离?
* mycat如何做到主从切换?
* 支持哪些分片算法?
* 查询多张分表,支持结果集合并,如果涉及翻页或排序,需要对合并后的结果做二次加工处理。
### 二、数据相关
分布式数据库特性:
* 透明性。用户不需要了解内部结构,表现就象一个传统的单处理机系统。
* 扩展性。通过横向扩展使集群的整体性能提升。
* 可靠性。不允许单点,如果一台机器坏了,则其他机器能接替它进行工作。
数据分片:
* 水平切分。按分表键,将表的行数据拆分到多个节点库中。逻辑上单表,物理上多表。
* 垂直切分。一个数据库由很多表组成,每个表对应不同的业务。垂直切分,将表进行分类分布到不同的节点上。类似电商按商品线、交易线、会员线、店铺线等拆分到不同的DB。
技术点:
* 支持多数据源
* 主库、备库切换
* 分库
* 分表
* 支持千亿级别大表
* 事务、分布式事务
* 读写分离
* 数据合并
* 在线扩容
* 数据迁移
* 系统监控
### 三、Mycat核心组件及配置
#### 核心组件
* 逻辑库(Schema)
数据库中间件被当成作一个或多个数据库集群构成的逻辑库。
* 逻辑表(table)
逻辑表可以分布在一个或多个分片库中,也可以不分片。
```
```
t_user分片表,数据按照规则被切分到dn1、dn2两个节点。
```
```
t_node表,非分片表,只存在于节点dn1。
`primaryKey:逻辑表对应真实表的主键。对于分片规则使用非主键进行分表,如果使用主键查询会,会扫描所有分表,配置了该属性,mycat会缓存主键与dn的信息,避免所有表扫描,提升性能。但如果缓存没有命中,还是会把SQL发给所有的dn执行来获取数据。`
* 分片节点(dataNode)
```
```
一个大表被分到不同的分片数据库上,每个表分片所在的数据库就是分片节点
* 节点主机(dataHost)
```
show status like 'wsrep%'
```
同一台机器上可以有多个分片数据库。为了避免单节点主机并发数量的限制,尽量将读写压力高的分片节点均匀地放在不同的节点主机上。
`上面只列了几个核心参数,更多参数详细说明可参考《基于mycat中间件P22》`
#### 配置文件:
* server.xml
主要是配置系统信息,有两个重要标签 user、system
* schema.xml
主要是逻辑库、逻辑表、分片规则 、分片节点、数据源
* sequence
在分库分表的情况下,数据库的自增主键无法保证在集群中是全局唯一的主键,因此mycat提供了全局的sequence,并支持本地配置、数据库配置等多种实现方式。
* rule.xml
分片规则的配置文件,分片规则的具体一些参数信息单独存放为文件,也在这个目录下,配置文件修改需要重启MyCAT。
* log4j.xml
日志存放在logs/log中,每天一个文件,日志的配置是在conf/log4j.xml中,根据自己的需要可以调整输出级别为debug,debug级别下,会输出更多的信息,方便排查问题。
autopartition-long.txt,partition-hash-int.txt,sequence_conf.properties, sequence_db_conf.properties 分片相关的id分片规则配置文件
* lib
MyCAT自身的jar包或依赖的jar包的存放目录。
* logs
MyCAT日志的存放目录。日志存放在logs/log中,每天一个文件
#### 分片规则
* 取模分片(常用的方式)
对分表键id按总的分表数求模计算,比如模为0,放在第1张表,模为1,放在第2张表。
* 枚举分片
配置文件中配置可能的枚举id,指定数据分布到不同的物理节点上。本规则适用于按省份或县区来拆分数据。
* 范围分片
按分片字段的某个范围放入对应分片。比如0~1kw,放在第1张表,1kw~2kw,放在第2张表
* 范围求模算法
范围分片+取模分片的组合。先根据id找到对应的分片组,分片组内使用求模可以保证组内的数据分布比较均匀。事先规定好分片的数量,数据扩容时按分片组扩容,原有的分片组的数据不需要迁移。由于分片组的数据分布比较均匀,所以分片组内可以避免热点数据问题。
0~1kw=5 //表示该组有5个分片节点
* 固定分片hash算法
* 取模范围算法
* 字符串hash求模范围算法
与取模算法类似,该算法支持数字、符号、字母取模。截取长度为prefixLength的子串,再对子串中每个字符的ascii码求和得出sum,然后对sum进行求模运算。
* 一致性hash算法
有效解决分布式数据的扩容问题。`每个真实的数据库节点会被映射为N倍虚拟节点,默认是160倍`
* 按日期(天)分片
从开始时间算起,每隔sPartionDay天,对应一个数据分区。
* 按月单小时算法
* 自然月分片算法
* 日期范围hash算法
先根据日期的范围分组,再根据时间hash分到每组下对应的分片。
### 四、mycat优势
* 对Cobar代码进行了重构,使用NIO重构了网络模块,并优化了Buffer内核,增强了聚合、join等基本特性
* 支持绝大部分数据库,如oracle、mysql、sqlserver、db2、MongoDB 等,成为通用数据库中间件
* 支持透明的读写分离机制,减轻写库压力,提高数据库的并发查询能力
* 大表水平分片方式支持100亿级的数据存储
* 内建数据库集群故障切换机制,实现了自动切换
* 提供reload命令,例如更新了schema.xml文件后,不用重启即可进行配置文件更新。
### 五、源码分析
mycat前身Amoeba、Cobar。
[github 源码](https://github.com/MyCATApache/Mycat-Server)
Mycat核心是拦截用户发过来SQL语句,做一些分析,例如SQL解析、分片分析、路由分析、读写分离分析、缓存分析等,然后将SQL语句发往后端的真实数据库,并将返回的结果做适当处理,最终返回给用户。
**架构剖析**
* NIO架构
NIOAcceptor负责处理Accept事件,服务端接收客户端的连接事件,NIOAcceptor调用NIOReactor.postRegister进行注册
|事件名|对应值|
|----|----|
|服务端接收客户端连接事件|Selection.OP_ACCEPT|
|客户端连接服务端事件|Selection.OP_CONNECT|
|读事件|Selection.OP_READ|
|写事件|Selection.OP_WRITE|
* 多线程架构
维护一个线程池 NameableExecutor,继承自ThreadPoolExecutor。mycat内部有两大线程池:timerExectuor和businessExecutor。
```
timerExectuor:
定时更新任务、处理器定时检查任务,数据节点定时心跳检测,主要是后勤工作。
businessExecutor:
处理业务请求,比如执行SQL语句,SQL拦截,数据合并,查询结果
```
* 内存管理及缓存架构
缓冲区采用java.io.ByteBuffer,缓冲区分为直接缓冲区(操作系统内存)和非直接缓冲区(JVM内存)。
* 连接池
* 分布式事务
* sql路由实现
* 跨库join实现
* 数据汇聚、数据排序
### 六、Mycat安装
如何安装?
[https://github.com/MyCATApache/Mycat-Server](https://github.com/MyCATApache/Mycat-Server)
`下载文件直接解压。执行./mycat start 启动`
```
./mycat start 启动
./mycat stop 停止
./mycat console 前台运行
./mycat restart 重启服务
./mycat pause 暂停
./mycat status 查看启动状态
```
### 七、Mycat实战
* [入门指南、开发指南、生产部署、设计文档](https://github.com/MyCATApache/Mycat-doc)
#### 1.搭建读写分离
主数据提供写操作,从数据库提供读操作,有效减轻单台数据库的压力,主数据库进行写操作后,数据及时同步到所读的数据库,尽可能保证两边数据一致。
```
主(M1)<----> 备(M2)
|
|
从(S1)
```
* balance为0。不开启读写分离,所有的读全发送到M1
* balance为1。所有的读发送到S1和M2
* balance为2。所有的读发送到M1、M2和S1
* balance为3。所有的读发送到S1
#### 2.搭建主备切换
#### 3.mycat+percona+haproxy+keepalived
#### 4.mha+keepalived