MyCat简介
什么是MyCat
MyCat 是目前最流行的基于 java 语言编写的数据库中间件,是一个实现了 MySQL 协议的服务器,前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和命令行访问,而其后端可以用 MySQL 原生协议与多个 MySQL 服务器通信,也可以用 JDBC 协议与大多数主流数据库服务器通信,其核心功能是分库分表。配合数据库的主从模式还可实现读写分离。
MyCat 是基于阿里开源的 Cobar 产品而研发,Cobar 的稳定性、可靠性、优秀的架构和性能以及众多成熟的使用案例使得 MyCat 变得非常的强大。
MyCat 发展到目前的版本,已经不是一个单纯的 MySQL 代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL 等主流数据库,也支持 MongoDB 这种新型NoSQL 方式的存储,未来还会支持更多类型的存储。而在最终用户看来,无论是那种存储方式,在 MyCat 里,都是一个传统的数据库表,支持标准的 SQL 语句进行数据的操作,这样一来,对前端业务系统来说,可以大幅降低开发难度,提升开发速度。
MyCat 官网:http://mycat.org.cn/
使用MyCat后的结构图
使用MyCat的优势
数据量级
单一的MySQL其数据存储量级和操作量级有限。MyCat可以管理若干MySQL数据库,同时实现数据的存储和操作。
开源性质
Mycat 是 java 编写的中间件. 开源,免费。
有非常多的人和组织对 Mycat 实行开发,维护,管理,更新。
Mycat 版本提升较快,可以跟随环境发展.如果有问题,可以快速解决。
Mycat 有开源网站和开源社区.且有官方发布的电子书籍。
Mycat 是阿里原应用 corba 转型而来的。
市场应用
2015年左右MyCat在互联网应用中占比非常高
MyCat中的概念
切分
逻辑上的切分,在物理层面,是使用多库[database],多表[table]实现的切分
纵向切分/垂直切分
就是把原本存储于一个库的数据存储到多个库上。
由于对数据库的读写都是对同一个库进行操作,所以单库并不能解决大规模并发写入的问题。
例如,我们会建立定义数据库 workDB、商品数据库 payDB、用户数据库 userDB、日志数据库 logDB 等,分别用于存储项目数据定义表、商品定义表、用户数据表、日志数据表等。
优点:
- 减少增量数据写入时的锁(共享锁,更新锁,排他锁等,如果上了排他锁时,那么写入数据时不能查询)对查询的影响。
- 由于单表数量下降,常见的查询操作由于减少了需要扫描的记录,使得单表单次查询所需的检索行数变少,减少了磁盘 IO,时延变短
缺点:无法解决单表数据量太大的问题。
横向切分/水平切分
把原本存储于一个表的数据分块存储到多个表上。当一个表中的数据量过大时,我们可以把该表的数据按照某种规则,进行划分,然后存储到多个结构相同的表,和不同的库上。
例如,我们 userDB 中的 userTable 中数据量很大,那么可以把 userDB 切分为结构相同的多个 userDB:part0DB、part1DB 等,再将 userDB 上的 userTable,切分为很多 userTable:userTable0、userTable1 等,然后将这些表按照一定的规则存储到多个 userDB 上。
优点:
- 单表的并发能力提高了,磁盘 I/O 性能也提高了。
- 如果出现高并发的话,总表可以根据不同的查询,将并发压力分到不同的小表里面。
缺点:无法实现表连接查询
逻辑库-Schema
MyCat中定义的database是逻辑上存在的,但是物理上是不存在的。主要是针对纵向切分提供的概念。
逻辑表-table
MyCat中定义的table是逻辑上存在,物理上是不存在的。主要是针对横向切分提供的概念。
默认端口
MySQL
的默认端口是3306
MyCat
默认端口是8066
Tomcat
默认端口是 8080
Oracle
默认端口是 1521
nginx
默认端口是 80
http
协议默认端口 80
redis
默认端口 6379
数据主机-dataHost
物理MySQL存放的主机地址,可以使用主机名,IP,域名定义。
数据节点-dataNode
配置物理的database,数据保存的物理节点就是database.
分片规则
当控制数据的时候,如何访问物理 database 和 table。
就是访问 dataHost 和 dataNode 的算法。
在 Mycat 处理具体的数据 CRUD 的时候,如何访问 dataHost 和 dataNode 的算法.如:哈希算法,crc32 算法等。
MyCat的使用
读写分离
原理:需要搭建主从模式,让主数据库(master)处理事务性增、删、改操作(INSERT、UPDATE、DELETE),而从数据库(slave)处理查询( SELECT )操作。
Mycat 配合数据库本身的复制功能,可以解决读写分离的问题。
主从备份概念
什么是主从备份: 就是一种主备模式的数据库应用。
主库(Master)数据与备库(Slave)数据完全一致。
实现数据的多重备份, 保证数据的安全。
可以在 Master[InnoDB支持事务]和 Slave[MyISAM不支持事务](查询效率高)中使用不同的数据库引擎,实现读写的分离。
MySQL5.5, 5.6 版本后本身支持主从备份
在老旧版本的 MySQL 数据库系统中,不支持主从备份,需要安装额外的 RPM 包.如果需要安装 RPM,只能在一个位置节点安装。
主从备份目的
实现主备模式
保证数据的安全,尽量避免数据丢失的可能。
实现读写分离
使用不同的数据库引擎,实现读写分离,提高所有的操作效率。
InnoDB(支持事务)使用DML语法操作,MyISAM(不支持事务)使用DQL语法操作。
主从备份效果
主库操作同步到备库
所有对 Master 的操作,都会同步到 Slave 中.
如果 Master和 Salve 天生上环境不同,那么对 Master 的操作,可能会在 Slave中出现错误
如:在创建主从模式之前,Master有 database : db1, db2, db3. Slave有 database: db1,db2.
创建主从模式现在的情况Master和Slave天生不同。
主从模式创建成功后,在 Master中 drop database db3. Slave中抛出数据库 SQL异常后续所有的命令不能同步。
一旦出现错误. 只能重新实现主从模式。
主从模式下的逻辑图
MySQL的主从模式搭建
安装MYSQL(参考文章)
已安装
主库IP(master):192.168.43.181
从库IP(slave):192.168.43.238
Mater[主库]配置
修改Master配置文件
打开mysql的配置文件
路径:/etc/my.cnf
1 | vi /etc/my.cnf |
添加server_id
本环境中 server_id
是1
MySQL服务唯一标识
配置要求:
server_id
任意配置,只要是数字即可。server_id
Master 唯一标识数数字必须小于Slave唯一标识数字。
添加log_bin
本环境 log_bin
值:master_log 开启日志功能以及日志文件命名,log_bin=master_log;
变量的值就是日志文件名称,是日志文件名称的主题。
MySQL数据库自动增加文件名后缀和文件类型
重启MySQL
1 | service mysqld restart |
配置Master
登录MySQL
1 | mysql -u root -proot |
创建用户
在MySQL数据库中,为不存在的用户授权,就是同步创建用户并授权。此用户是从库访问主库使用的用户
IP 地址不能写为%,因为主从备份中,当前创建的用户是给从库slave访问主库master使用的,用户必须有指定的访问地址,不是通用地址。
格式:grant all privileges on *.* to 'username'@'ip' identified by 'password' with grant option;
刷新flush privileges;
为我的从库slave授权访问主库权限
1 | grant all privileges on *.* to myslave@'192.168.43.238' identified by 'root' with grant option; |
1 | flush privileges; |
查看用户
1 | use mysql; |
1 | select host,user from user; |
查看Master信息
1 | show master status; |
我们可以找到二进制文件:master_log.000002
(000002是自动生成的编号)日志所在的地方,master_log.index
是配置master_log.000002的位置的。
关闭防火墙或者开启3306端口Centos7
关闭防火墙
1
systemctl stop firewalld
开启3306端口
1
firewall-cmd --zone=public --add-port=3306/tcp --permanent
1
systemctl restart firewalld
Slave[从库]配置
修改Slave配置文件
1 | vi /etc/my.cnf |
重启MySQL服务
1 | service mysqld restart |
配置Slave
登录mysql
1 | mysql -u root -proot |
停止Slave功能(默认是开启的)
1 | stop slave; |
配置主库信息
需要修改的数据是依据Master信息修改的,ip
是Master所在物理机的ip
,用户名和密码是Master提供的Slave访问用户名和密码,日志文件是在Master中查看的主库信息提供的,在之前的Master中使用命令show master status;
查看了日志文件名称。
格式:change master to master_host='ip', master_user='username', master_password='password', master_port=3306,master_log_file='log_file_name',master_log_pos=查出来的position值;
1 | change master to master_host='192.168.43.181',master_user='myslave',master_password='root',master_port=3306,master_log_file='master_log.000002',master_log_pos=154; |
启动Salve功能
1 | start slave; |
查看Slave配置
1 | show slave status \G; |
1 | mysql> show slave status \G; |
常见问题
当
Slave_IO_Running:Connecting
时检查主库的端口是否放行,防火墙是否关闭。
当
Slave_IO_Running:No
时先执行
stop slave;
,然后reset slave;
、最后start slave;
测试主从库
先在主库中新建一个数据库
1 | create database mytest default character set utf8; |
然后在主库和从库中的mysql里可以看到两个都要mytest
这个库了
1 | show databases; |
同理,在主库新建表和插入数据后,同样可以在从表看到。
1 | CREATE TABLE `t_users` ( |
1 | insert into t_users values(1,'admin') |
安装MyCat
安装环境
MyCat(虚拟机):192.168.43.182
我们先下载MyCat1.6
然后将Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz上传至服务器。
将压缩包解解压。建议将mycat放到/usr/local/目录下。
1
tar -zxvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
1
mv mycat /usr/local
MyCat目录介绍
bin 目录里是启动脚本
conf 目录里是配置文件
catlet 为 Mycat 的一个扩展功能
lib 目录里是 Mycat 和它的依赖 jar
logs 目录里是 console.log 用来保存控制台日志,和 mycat.log 用来保存 mycat 的 log4j日志
安装JDK
我们这里直接yum 安装jdk8,安装时一直同意下去。安装完成后输入java -version
检查安装。
1 | yum install java-1.8.0-openjdk* -y |
MyCat配置文件
Mycat 的架构其实很好理解,Mycat 是代理,Mycat 后面就是物理数据库。和 Web 服务器的 Nginx 类似。对于使用者来说,访问的都是 Mycat,不会接触到后端的数据库。我们现在做一个主从、读写分离。结构如下:
Mycat 的配置文件都在 conf 目录里面,这里介绍几个常用的文件
文件 | 说明 |
---|---|
server.xml | MyCat的配置文件,设置账号、参数等 |
schema.xml | MyCat 对应的物理数据库和数据库表的配置 |
rule.xml | MyCat 分片(分库分表)规则 |
server.xml逻辑库配置
常见修改内内容:
1 | <property name="serverPort">8066</property> <!-- Mycat 服务端口号 --> |
配置Mycat服务信息
如: Mycat 中的用户,用户可以访问的逻辑库,可以访问的逻辑表,服务的端口号等
user | 用户配置的节点 |
---|---|
–name | 登录的用户名,也就是连接 Mycat 的用户名 |
–password | 登录的密码,也就是连接 Mycat 的密码 |
–schemas | 逻辑库名,这里会和 schema.xml 中的配置关联,多个用逗号分开, 例如需要这个用户管理两个数据库db1、db2,则配置db1、db2。 |
–privileges | 配置用户针对表的增删改查的权限 |
默认配置了一个账号 root 密码也是 123456,针对数据库 TESTDB,读写权限都有,没有针对表做任何特殊的权限。
配置权限
参数 | 说明 | 事例(禁止增删改查) |
---|---|---|
dml | insert、update、select、dalete | 0000 |
schemea.xml
schema.xml 是最主要的配置文件,首先看默认的配置文件
1 |
|
用于定义逻辑库和逻辑表的配置文件
在配置文件中可以定义读写分离,逻辑库,逻辑表,dataHost,dataNode等信息
schema | 配置逻辑库,name 与 server.xml 中 schema 对应 |
dataHost | 物理数据库,真正存储数据的数据库 |
dataNode | 定义数据节点的标签,也就是分库相关配置 |
节点与属性介绍
标签 schema
配置逻辑库的标签
属性 name
逻辑库名称
属性 checkSQLschema
是否检测 SQL 语法中的 schema 信息。
如: Mycat 逻辑库名称 A, dataNode 名称 B
SQL : select * from A.table;
checkSQLschema 值是 true, Mycat 发送到数据库的 SQL 是 select * from table;
checkSQLschema 只是 false,Mycat 发送的数据库的 SQL 是 select * from A.table;
sqlMaxLimit
Mycat 在执行 SQL 的时候,如果 SQL 语句中没有 limit 子句.自动增加 limit 子句. 避免一次性得到过多的数据,影响效率. limit 子句的限制数量默认配置为 100.如果 SQL 中有具体的 limit子句,当前属性失效。
1
select * from table
mycat 解析后:
1
select * from table limit 100
下面这种mycat 不做任何操作修改。
1
select * from table limit 10
标签 table
定义逻辑表的标签
属性 | 含义 |
---|---|
name | 逻辑表名 |
dataHost | 数据节点名称。即物理数据库中的 database 名称。多个名称使用逗号分隔。 |
rule | 分片规则名称。具体的规则名称参考 rule.xml 配置文件。 |
标签 dataNode
定义数据节点的标签
属性 | 含义 |
---|---|
name | 数据节点名称, 是定义的逻辑名称,对应具体的物理数据库 database |
dataHost | 引用 dataHost 标签的 name 值,代表使用的物理数据库所在位置和配置信息 |
database | 在dataHost 物理机中,具体的物理数据库 database 名称 |
标签 dataHost
定义数据主机的标签
属性 | 含义 |
---|---|
name | 定义逻辑上的数据主机名称 |
maxCon minCon | 最大连接数, max connections 最小连接数, min connections |
dbType | 数据库类型:mysql数据库 |
dbDriver | 数据库驱动类型, native,使用 mycat 提供的本地驱动。 |
dataHost 子标签 writeHost
写数据的数据库定义标签. 实现读写分离操作。
属性 | 含义 |
---|---|
host | 数据库命名 |
url | 数据库访问路径 |
user | 数据库访问用户名 |
password | 数据库访问用户密码 |
writeHost子标签readHost
属性 | 含义 |
---|---|
host | 数据库命名 |
url | 数据库访问路径 |
user | 数据库访问用户名 |
password | 数据库访问用户密码 |
rule.xml
用于定义分片规则的配置文件. mycat 默认的分片规则:
以 500 万为单位,实现分片规则。
逻辑库 A 对应 dataNode - db1 和 db2. 1-500 万保存在 db1 中, 500 万零 1 到 1000 万保存在 db2 中,1000 万零 1 到 1500 万保存在 db1 中.依次类推。
1 | <tableRule name="rule1"> |
tableRule
name | 属性指定唯一的名字,用于标识不同的分片规则。 内嵌的rule标签则指定对物理表中的哪一列进行拆分和使用什么分片算法。 |
columns | 指定要拆分的列名字 |
algorithm | 使用 function 标签中的 name 属性。连接表规则和具体分片算法。table标签内使用。 让逻辑表使用这个规则进行分片。 |
function
1 | <function name="func1" class="io.mycat.route.function.PartitionByLong"> |
name | 指定算法的名字 |
class | 制定分片算法具体的类名字 |
property | 为具体算法需要用到的一些属性 |
实现读写分离
配置读写分离
Schema.xml
1 |
|
当Mycat查表报错find no Route:select * from 'test'.'t_users' limit 0, 100
时,你需要修改schema.xml
的 checkSQLschema=“false”
,改为true
即可。
当该值为true时,例如我们执行语句select * from TESTDB.company 。mycat会把语句修改为 select * from company 去掉TESTDB。
Server.xml
1 | <user name="root"> <!--配置mycat的用户名和密码--> |
测试读写分离
记住放行端口8066和管理端口9066
先进入mycat的bin目录下
1 | cd /usr/local/mycat/bin |
启动MyCat命令
1 | ./mycat start |
停止MyCat命令
1 | ./mycat stop |
重启MyCat命令
1 | ./mycat restart |
查看MyCat状态
1 | ./mycat status |
查看MyCat日志
日志中记录的是所有的 mycat 操作. 查看的时候主要看异常信息 caused by 信息。
1 | cat /usr/local/mycat/logs/wrapper.log |
balance
balance=”0”, 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上
balance=”1”,全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡
balance=”2”,所有读操作都随机的在 writeHost、 readhost 上分发。
balance=”3”, 所有读请求随机的分发到 writeHost 对应的 readhost 执行,writerHost不负担读压力
在从库中加入一条数据,这时候主库中是没有的,因为从库同步主库,但主库不会同步从库,我们在mycat中查询所有用户发现没有从库中新添加的数据
这时候就要修改schema.xml中的balance的值
修改完记得重启MyCat
测试访问方式
我这里用的是Navicat软件连接MyCat和MySQL
MyCat分库
MyCat允许我们在mysql中定义多个库,允许数据按照分片规则分散存储到多个库中,可以降低每个数据库的压力
分片规则
auto-sharding-long 范围约定
1 | <tableRule name="auto-sharding-long"> |
以 500 万为单位,实现分片规则。
逻辑库 A 对应 dataNode - db1 和 db2. 1-500 万保存在 db1 中, 500 万零 1 到 1000 万保存在 db2 中,1000 万零 1 到 1500 万保存在 db1 中.依次类推。
crc32slot规则
在 CRUD 操作时,根据具体数据的 crc32 算法计算,数据应该保存在哪一个 dataNode 中
在mycat的rule.xml中全是由分片规则tableRule和分片函数function 标签组成。
1 | <tableRule name="crc32slot"> |
配置分片规则需要注意的地方
id 中推荐配置主键列所有的 tableRule 只能使用一次。如果需要为多个表配置相同的分片规则,那么需要在rule.xml中向下复制一份该规则,让其name值不同即可。
在 crc32Slot 算法中的分片数量一旦给定,MyCat 会将该分片数量和 Slot 的取值范围
1
2
3
4
5<function name="crc32slot"
class="io.mycat.route.function.PartitionByCRC32PreSlot">
<property name="count">2</property>
<!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
</function>这个数量2对应schema.xml中节点的数量
保存到文件中。再次修改分片数量时是不会生效的,需要将该文件删除。文件位置位于 conf目录中的 ruledata 目录中(删除它)。
配置分库
需求
- 在master中创建3个数据库
- 在MyCat中配置分库
创建数据库
1 | create database demo1 default character set utf8; |
创建相同的t_users
表
1 | CREATE TABLE `t_users` ( |
修改Schema.xml
1 |
|
修改rule.xml
1 | <function name="crc32slot" |
配置好了分库分表,使用mycat创建表,插入数据即可(库还是得手动创建),数据会写入master,查询时根据配置的balance规则。
测试
schema.xml
1 |
|
rule.xml
1 | <tableRule name="auto-sharding-long"> |
在MyCat中
1 | use test;#切换库 |
使用MyCat的全局自增(MYCATSEQ_GLOBAL)
#全局自增序列是个字符串
1 | select next value for MYCATSEQ_GLOBAL; |
schema.xml中加上primaryKey中的值得大写
1 | <table name="persen" dataNode="dn1,dn2,dn3" autoIncrement="true" primaryKey="PID" type="global" rule="auto-sharding-long"/> |
把表的pid
修改为vachar
类型
1 | create table persen( |
1 | insert into persen (pid,pname,pwd) values(next value for MYCATSEQ_GLOBAL,'株洲8','123'); |
注意:
- 使用 MyCat 实现分库时,先在 MyCat 中定义逻辑库与逻辑表,然后在 MyCat 的链接中执行创建表的命令必须要在 MyCat 中运行。因为 MyCat 在创建表时,会在表中添加一个新的列,列名为_slot。
- 使用 MyCat 插入数据时,语句中必须要指定所有的列。即便是一个完全项插入也不允许省略列名。