系统开发中, 数据库是非常重要的一个点. 除了程序的本身的优化, 如: SQL 语句优化, 代码优化, 数据库的处理本身优化也是非常重要的. 主从, 热备, 分表分库等都是系统发展迟早会遇到的技术问题问题. Mycat 是一个广受好评的数据库中间件, 已经在很多产品上进行使用了. 希望通过这篇文章的介绍, 能学会 Mycat 的使用.
安装
Mycat 官网: http://www.mycat.io/
可以了解下 Mycat 的背景和应用情况, 这样使用起来比较有信心.
Mycat 下载地址: http://dl.mycat.io/ http://www.mycat.io/
官网有个文档, 属于详细的介绍, 初次入门, 看起来比较花时间.
下载:
建议大家选择 1.6-RELEASE 版本, 毕竟是比较稳定的版本.
安装:
根据不同的系统选择不同的版本. 包括 Linux,Windows,Mac, 作者考虑还是非常周全的, 当然, 也有源码版的.(ps: 源码版的下载后, 只要配置正确, 就可以正常运行调试, 这个赞一下.)
Mycat 的安装其实只要解压下载的目录就可以了, 非常简单.
安装完成后, 目录如下:
目录 | 说明 |
---|---|
bin | mycat 命令,启动、重启、停止等 |
catlet | catlet 为 Mycat 的一个扩展功能 |
conf | Mycat 配置信息, 重点关注 |
lib | Mycat 引用的 jar 包,Mycat 是 java 开发的 |
logs | 日志文件,包括 Mycat 启动的日志和运行的日志。 |
配置
Mycat 的配置文件都在 conf 目录里面, 这里介绍几个常用的文件:
文件 | 说明 |
---|---|
server.xml | Mycat 的配置文件,设置账号、参数等 |
schema.xml | Mycat 对应的物理数据库和数据库表的配置 |
rule.xml | Mycat 分片(分库分表)规则 |
Mycat 的架构其实很好理解, Mycat 是代理, Mycat 后面就是物理数据库. 和 web 服务器的 Nginx 类似. 对于使用者来说, 访问的都是 Mycat, 不会接触到后端的数据库.
我们现在做一个主从, 读写分离, 简单分表的示例. 结构如下图:
服务器 | IP | 说明 |
---|---|---|
Mycat | 192.168.0.2 | mycat 服务器,连接数据库时,连接此服务器 |
database1 | 192.168.0.3 | 物理数据库 1,真正存储数据的数据库 |
database2 | 192.168.0.4 | 物理数据库 2,真正存储数据的数据库 |
Mycat 作为主数据库中间件, 肯定是与代码弱关联的, 所以代码是不用修改的, 使用 Mycat 后, 连接数据库是不变的, 默认端口是 8066. 连接方式和普通数据库一样, 如: jdbc:MySQL://192.168.0.2:8066/
server.xml
示例
- <user name="test">
- <property name="password">test</property>
- <property name="schemas">lunch</property>
- <property name="readOnly">false</property>
- <!-- 表级 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 | 用户配置节点 |
--name | 登录的用户名,也就是连接 Mycat 的用户名 |
--password | 登录的密码,也就是连接 Mycat 的密码 |
--schemas | 数据库名,这里会和 schema.xml 中的配置关联,多个用逗号分开,例如需要这个用户需要管理两个数据库 db1,db2,则配置 db1,dbs |
--privileges | 配置用户针对表的增删改查的权限,具体见文档吧 |
我这里配置了一个账号 test 密码也是 test, 针对数据库 lunch, 读写权限都有, 没有针对表做任何特殊的权限.
schema.xml
schema.xml 是最主要的配置项, 首先看我的配置文件.
<?xml version="1.0"?>
- <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
- <mycat:schema xmlns:mycat="http://io.mycat/">
- <!-- 数据库配置, 与 server.xml 中的数据库对应 -->
- <schema name="lunch" checkSQLschema="false" sqlMaxLimit="100">
- <table name="lunchmenu" dataNode="dn1" />
- <table name="restaurant" dataNode="dn1" />
- <table name="userlunch" dataNode="dn1" />
- <table name="users" dataNode="dn1" />
- <table name="dictionary" primaryKey="id" autoIncrement="true" dataNode="dn1,dn2" rule="mod-long" />
- </schema>
- <!-- 分片配置 -->
- <dataNode name="dn1" dataHost="test1" database="lunch" />
- <dataNode name="dn2" dataHost="test2" database="lunch" />
- <!-- 物理数据库配置 -->
- <dataHost name="test1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">
- <heartbeat>select user();</heartbeat>
- <writeHost host="hostM1" url="192.168.0.2:3306" user="root" password="123456">
- </writeHost>
- </dataHost>
- <dataHost name="test2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">
- <heartbeat>select user();</heartbeat>
- <writeHost host="hostS1" url="192.168.0.3:3306" user="root" password="123456">
- </writeHost>
- </dataHost>
- </mycat:schema>
参数 | 说明 |
---|---|
schema | 数据库设置,此数据库为逻辑数据库,name 与 server.xml 中 schema 对应 |
dataNode | 分片信息,也就是分库相关配置 |
dataHost | 物理数据库,真正存储数据的数据库 |
每个节点的属性逐一说明:
schema:
属性 | 说明 |
---|---|
name | 逻辑数据库名,与 server.xml 中的 schema 对应 |
checkSQLschema | 数据库前缀相关设置,建议看文档,这里暂时设为 folse |
sqlMaxLimit | select 时默认的 limit,避免查询全表 |
table:
属性 | 说明 |
---|---|
name | 表名,物理数据库中表名 |
dataNode | 表存储到哪些节点,多个节点用逗号分隔。节点为下文 dataNode 设置的 name |
primaryKey | 主键字段名,自动生成主键时需要设置 |
autoIncrement | 是否自增 |
rule | 分片规则名,具体规则下文 rule 详细介绍 |
dataNode
属性 | 说明 |
---|---|
name | 节点名,与 table 中 dataNode 对应 |
datahost | 物理数据库名,与 datahost 中 name 对应 |
database | 物理数据库中数据库名 |
dataHost
属性 | 说明 |
---|---|
name | 物理数据库名,与 dataNode 中 dataHost 对应 |
balance | 均衡负载的方式 |
writeType | 写入方式 |
dbType | 数据库类型 |
heartbeat | 心跳检测语句,注意语句结尾的分号要加。 |
应用场景
数据库分表分库
配置如下:
<?xml version="1.0"?>
- <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
- <mycat:schema xmlns:mycat="http://io.mycat/">
- <!-- 数据库配置, 与 server.xml 中的数据库对应 -->
- <schema name="lunch" checkSQLschema="false" sqlMaxLimit="100">
- <table name="lunchmenu" dataNode="dn1" />
- <table name="restaurant" dataNode="dn1" />
- <table name="userlunch" dataNode="dn1" />
- <table name="users" dataNode="dn1" />
- <table name="dictionary" primaryKey="id" autoIncrement="true" dataNode="dn1,dn2" rule="mod-long" />
- </schema>
- <!-- 分片配置 -->
- <dataNode name="dn1" dataHost="test1" database="lunch" />
- <dataNode name="dn2" dataHost="test2" database="lunch" />
- <!-- 物理数据库配置 -->
- <dataHost name="test1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">
- <heartbeat>select user();</heartbeat>
- <writeHost host="hostM1" url="192.168.0.2:3306" user="root" password="123456">
- </writeHost>
- </dataHost>
- <dataHost name="test2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">
- <heartbeat>select user();</heartbeat>
- <writeHost host="hostS1" url="192.168.0.3:3306" user="root" password="123456">
- </writeHost>
- </dataHost>
- </mycat:schema>
我在 192.168.0.2,192.168.0.3 均有数据库 lunch.
lunchmenu,restaurant,userlunch,users 这些表都只写入节点 dn1, 也就是 192.168.0.2 这个服务, 而 dictionary 写入了 dn1,dn2 两个节点, 也就是 192.168.0.2,192.168.0.3 这两台服务器. 分片的规则为: mod-long.
主要关注 rule 属性, rule 属性的内容来源于 rule.xml 这个文件, Mycat 支持 10 种分表分库的规则, 基本能满足你所需要的要求, 这个必须赞一个, 其他数据库中间件好像都没有这么多.
table 中的 rule 属性对应的就是 rule.xml 文件中 tableRule 的 name, 具体有哪些分表和分库的实现, 建议还是看下文档. 我这里选择的 mod-long 就是将数据平均拆分. 因为我后端是两台物理库, 所以 rule.xml 中 mod-long 对应的 function count 为 2, 见下面部分代码:
- <tableRule name="mod-long">
- <rule>
- <columns>id</columns>
- <algorithm>mod-long</algorithm>
- </rule>
- </tableRule>
- <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
- <!-- how many data nodes -->
- <property name="count">2</property>
- </function>
数据库读写分离
配置如下:
<?xml version="1.0"?>
- <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
- <mycat:schema xmlns:mycat="http://io.mycat/">
- <!-- 数据库配置, 与 server.xml 中的数据库对应 -->
- <schema name="lunch" checkSQLschema="false" sqlMaxLimit="100">
- <table name="lunchmenu" dataNode="dn1" />
- <table name="restaurant" dataNode="dn1" />
- <table name="userlunch" dataNode="dn1" />
- <table name="users" dataNode="dn1" />
- <table name="dictionary" primaryKey="id" autoIncrement="true" dataNode="dn1" />
- </schema>
- <!-- 分片配置 -->
- <dataNode name="dn1" dataHost="test1" database="lunch" />
- <!-- 物理数据库配置 -->
- <dataHost name="test1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native">
- <heartbeat>select user();</heartbeat>
- <writeHost host="hostM1" url="192.168.0.2:3306" user="root" password="123456">
- <readHost host="hostM1" url="192.168.0.3:3306" user="root" password="123456">
- </readHost>
- </writeHost>
- </dataHost>
- </mycat:schema>
这样的配置与前一个示例配置改动如下:
删除了 table 分配的规则, 以及 datanode 只有一个
datahost 也只有一台, 但是 writehost 总添加了 readhost,balance 改为 1, 表示读写分离.
以上配置达到的效果就是 102.168.0.2 为主库, 192.168.0.3 为从库.
注意: Mycat 主从分离只是在读的时候做了处理, 写入数据的时候, 只会写入到 writehost, 需要通过 mycat 的主从复制将数据复制到 readhost, 这个问题当时候我纠结了好久, 数据写入 writehost 后, readhost 一直没有数据, 以为是自己配置的问题, 后面才发现 Mycat 就没有实现主从复制的功能, 毕竟数据库本身自带的这个功能才是最高效稳定的.
至于其他的场景, 如同时主从和分表分库也是支持的了, 只要了解这个实现以后再去修改配置, 都是可以实现的. 而热备及故障专业官方推荐使用 haproxy 配合一起使用, 大家可以试试.
使用
Mycat 的启动也很简单, 启动命令在 Bin 目录:
- ## 启动
- mycat start
- ## 停止
- mycat stop
- ## 重启
- mycat restart
如果在启动时发现异常, 在 logs 目录中查看日志.
wrapper.log 为程序启动的日志, 启动时的问题看这个
mycat.log 为脚本执行时的日志, SQL 脚本执行报错后的具体错误内容, 查看这个文件. mycat.log 是最新的错误日志, 历史日志会根据时间生成目录保存.
mycat 启动后, 执行命令不成功, 可能实际上配置有错误, 导致后面的命令没有很好的执行.
Mycat 带来的最大好处就是使用是完全不用修改原有代码的, 在 mycat 通过命令启动后, 你只需要将数据库连接切换到 Mycat 的地址就可以了. 如下面就可以进行连接了:
MySQL -h192.168.0.1 -P8806 -uroot -p123456
连接成功后可以执行 sql 脚本了.
所以, 可以直接通过 sql 管理工具 (如: navicat,datagrip) 连接, 执行脚本. 我一直用 datagrip 来进行日常简单的管理, 这个很方便.
Mycat 还有一个管理的连接, 端口号是 9906.
MySQL -h192.168.0.1 -P9906 -uroot -p123456
连接后可以根据管理命令查看 Mycat 的运行情况, 当然, 喜欢 UI 管理方式的人, 可以安装一个 Mycat-Web 来进行管理, 有兴趣自行搜索.
简而言之, 开发中使用 Mycat 和直接使用 MySQL 机会没有差别.
常见问题
使用 Mycat 后总会遇到一些坑, 我将自己遇到的一些问题在这里列一下, 希望能与大家有共鸣:
Mycat 是不是配置以后, 就能完全解决分表分库和读写分离问题?
Mycat 配合数据库本身的复制功能, 可以解决读写分离的问题, 但是针对分表分库的问题, 不是完美的解决. 或者说, 至今为止, 业界没有完美的解决方案.
分表分库写入能完美解决, 但是, 不能完美解决主要是联表查询的问题, Mycat 支持两个表联表的查询, 多余两个表的查询不支持. 其实, 很多数据库中间件关于分表分库后查询的问题, 都是需要自己实现的, 而且节本都不支持联表查询, Mycat 已经算做地非常先进了.
分表分库的后联表查询问题, 大家通过合理数据库设计来避免.
Mycat 支持哪些数据库, 其他平台如 .net,PHP 能用吗?
官方说了, 支持的数据库包括 MySQL,SQL Server,Oracle,DB2,PostgreSQL 等主流数据库, 很赞.
尽量用 MySQL, 我试过 SQL Server, 会有些小问题, 因为部分语法有点差异.
Mycat 非 JAVA 平台如 .net,PHP 能用吗?
可以用. 这一点 MyCat 做的也很棒.
来源: http://www.bubuko.com/infodetail-2900498.html