学会数据库读写分离、分表分库——用Mycat,这一篇就够了!

系统开发中,数据库是很是重要的一个点。除了程序的自己的优化,如:SQL语句优化、代码优化,数据库的处理自己优化也是很是重要的。主从、热备、分表分库等都是系统发展早晚会遇到的技术问题问题。Mycat是一个广受好评的数据库中间件,已经在不少产品上进行使用了。但愿经过这篇文章的介绍,能学会Mycat的使用。 php

安装

Mycat官网:www.mycat.io/
能够了解下Mycat的背景和应用状况,这样使用起来比较有信心。 java

Mycat下载地址:dl.mycat.io/
官网有个文档,属于详细的介绍,初次入门,看起来比较花时间。node

下载:
建议你们选择 1.6-RELEASE 版本,毕竟是比较稳定的版本。mysql

安装:
根据不一样的系统选择不一样的版本。包括linux、windows、mac,做者考虑仍是很是周全的,固然,也有源码版的。(ps:源码版的下载后,只要配置正确,就能够正常运行调试,这个赞一下。)
linux

Mycat的安装其实只要解压下载的目录就能够了,很是简单。
安装完成后,目录以下:sql

目录 说明
bin mycat命令,启动、重启、中止等
catlet catlet为Mycat的一个扩展功能
conf Mycat 配置信息,重点关注
lib Mycat引用的jar包,Mycat是java开发的
logs 日志文件,包括Mycat启动的日志和运行的日志。

配置

Mycat的配置文件都在conf目录里面,这里介绍几个经常使用的文件:shell

文件 说明
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/windows

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.二、192.168.0.3均有数据库lunch。
lunchmenu、restaurant、userlunch、users这些表都只写入节点dn1,也就是192.168.0.2这个服务,而dictionary写入了dn一、dn2两个节点,也就是192.168.0.二、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、DB二、PostgreSQL 等主流数据库,很赞。
    尽可能用Mysql,我试过SQL Server,会有些小问题,由于部分语法有点差别。

  • Mycat 非JAVA平台如 .net、PHP能用吗?
    能够用。这一点MyCat作的也很棒。

参考

《Mycat权威指南》: www.mycat.io/document/My…
官网 :www.mycat.io/

若是想熟练使用Mycat,建议要仔细看看官方推荐的文档,可能须要花点时间。本文只是简单的介绍下Mycat的配置,但愿能快速让你们对Mycat有个认识,官方的文档理解起来也很容易,只是须要的时间更多,本文为说明的参数,请参考官方文档。


欢迎你们关注个人公众号交流、学习、第一时间获取最新的文章
微信号:itmifen

相关文章
相关标签/搜索