windows环境使用mycat分库分表的安装与配置
一、mycat介绍
mycat官网地址: http://www.mycat.org.cn/简介:
- mycat是一款支持mysql数据库分库分表以及读写分离的开源中间件
- MyCat后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储
- 支持事务、ACID、可以替代MySQL的加强版数据库
MyCat的应用场景:
以下是几个典型应用场景:
1、 单纯的读写分离,此时配置最为简单,支持读写分离,主从切换
2、 分表分库,对于超过1000万的表进行分片,最大支持1000亿的单表分片
3、 多租户应用,每个应用一个库,但应用程序只连接MyCat,从而不改造程序本身,实现多租户
4、 报表系统,借助于MyCat的分表能力,处理大规模报表的统计
5、 替代HBase,分析大数据
6、 作为海量数据实时查询的一种方案,比如100亿条频繁查询的记录需要在3秒内查询出结果,除了基于主键的查询,还可能存在范围查询或其他属性查询,此时MyCat可能是最简单有效的选择。
二、window10环境下安装流程
1.下载win10环境支持的版本
下载好了以后,解压即可,解压到本地的文件夹下,为了防止莫名奇妙的问题,建议都放置到纯英文目录下。
2.mycat目录介绍
解压好以后,我们进入mycat 的目录,目录结构如下所示:
主要目录介绍:
1.bin目录:里面主要是mycat的启动/重启/停止的文件
2.conf目录:mycat的主要配置目录,我们最常用的是里面的server.xml,schema.xml,rule.xml3个配置文件
3.logs目录:日志目录,会记录启动,停止,执行的日志等等
3.mycat配置
在启动目录之前,我们要先配置一下基础的信息情况,否则启动会抛异常。mycat是java代码编写的,所以,有问题我们可以看到日志文件中抛出的各种异常原因:
学java的伙伴是不是有种很熟悉的感觉哈…
错误样例1
FATAL | wrapper | 2020/12/04 13:55:15 | OpenSCManager failed - 拒绝访问。 (0x5)
ERROR | wrapper | 2020/12/04 13:56:20 | CreateService failed - 指定的服务已存在。 (0x431)
ERROR | wrapper | 2020/12/04 13:58:28 | CreateService failed - 指定的服务已存在。 (0x431)
STATUS | wrapper | 2020/12/04 13:58:33 | Starting the Mycat-server service...
STATUS | wrapper | 2020/12/04 13:58:33 | --> Wrapper Started as Service
STATUS | wrapper | 2020/12/04 13:58:33 | Launching a JVM...
INFO | jvm 1 | 2020/12/04 13:58:35 | 错误: 代理抛出异常错误: java.rmi.server.ExportException: Port already in use: 1984; nested exception is:
INFO | jvm 1 | 2020/12/04 13:58:35 | java.net.BindException: Address already in use: JVM_Bind
ERROR | wrapper | 2020/12/04 13:58:36 | JVM exited while loading the application.
INFO | wrapper | 2020/12/04 13:58:38 | Waiting to start...
STATUS | wrapper | 2020/12/04 13:58:40 | Launching a JVM...
错误样例2
2020-12-05 09:46:55.064 ERROR [Timer1] (io.mycat.net.NIOSocketWR.checkAlive(NIOSocketWR.java:78)) -
java.nio.channels.ClosedChannelException: null
at sun.nio.ch.SocketChannelImpl.ensureReadOpen(Unknown Source) ~[?:1.8.0_102]
at sun.nio.ch.SocketChannelImpl.read(Unknown Source) ~[?:1.8.0_102]
at io.mycat.net.NIOSocketWR.checkAlive(NIOSocketWR.java:76) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.net.AbstractConnection.checkAlive(AbstractConnection.java:635) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.backend.ConQueue.takeIdleCon(ConQueue.java:22) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.backend.ConMap.tryTakeCon(ConMap.java:52) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.backend.ConMap.tryTakeCon(ConMap.java:32) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.backend.datasource.PhysicalDatasource.getConnection(PhysicalDatasource.java:534) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.sqlengine.SQLJob.run(SQLJob.java:70) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.backend.heartbeat.MySQLDetector.heartbeat(MySQLDetector.java:112) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.backend.heartbeat.MySQLHeartbeat.heartbeat(MySQLHeartbeat.java:142) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.backend.datasource.PhysicalDatasource.doHeartbeat(PhysicalDatasource.java:464) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.backend.datasource.PhysicalDBPool.doHeartbeat(PhysicalDBPool.java:436) [Mycat-server-1.6.7.6-release.jar:?]
at io.mycat.MycatServer$8$1.run(MycatServer.java:964) [Mycat-server-1.6.7.6-release.jar:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [?:1.8.0_102]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [?:1.8.0_102]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_102]
下面我们就来重点介绍一下mycat的基本配置信息
1. server.xml配置介绍:
<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - You
may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - Unless required by applicable law or agreed to in writing, software -
distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License for the specific language governing permissions and - limitations
under the License. -->
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
<property name="ignoreUnknownCommand">0</property><!-- 0遇上没有实现的报文(Unknown command:),就会报错、1为忽略该报文,返回ok报文。
在某些mysql客户端存在客户端已经登录的时候还会继续发送登录报文,mycat会报错,该设置可以绕过这个错误-->
<property name="useHandshakeV10">1</property>
<property name="removeGraveAccent">1</property>
<property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 -->
<property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 -->
<property name="sqlExecuteTimeout">300</property> <!-- SQL 执行超时 单位:秒-->
<property name="sequenceHandlerType">1</property>
<!--<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
INSERT INTO `travelrecord` (`id`,user_id) VALUES ('next value for MYCATSEQ_GLOBAL',"xxx");
-->
<!--必须带有MYCATSEQ_或者 mycatseq_进入序列匹配流程 注意MYCATSEQ_有空格的情况-->
<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
<property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
<property name="sequenceHanlderClass">io.mycat.route.sequence.handler.HttpIncrSequenceHandler</property>
<!-- <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
<!-- <property name="fakeMySQLVersion">5.6.20</property>--> <!--设置模拟的MySQL版本号-->
<!-- <property name="processorBufferChunk">40960</property> -->
<!--
<property name="processors">1</property>
<property name="processorExecutor">32</property>
-->
<!--默认为type 0: DirectByteBufferPool | type 1 ByteBufferArena | type 2 NettyBufferPool -->
<property name="processorBufferPoolType">0</property>
<!--默认是65535 64K 用于sql解析时最大文本长度 -->
<!--<property name="maxStringLiteralLength">65535</property>-->
<!--<property name="sequenceHandlerType">0</property>-->
<!--<property name="backSocketNoDelay">1</property>-->
<!--<property name="frontSocketNoDelay">1</property>-->
<!--<property name="processorExecutor">16</property>-->
<!--
<property name="serverPort">8066</property> <property name="managerPort">9066</property>
<property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
<property name="dataNodeIdleCheckPeriod">300000</property> 5 * 60 * 1000L; //连接空闲检查
<property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
<!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
<property name="handleDistributedTransactions">0</property>
<!--
off heap for merge/order/group/limit 1开启 0关闭
-->
<property name="useOffHeapForMerge">0</property>
<!--
单位为m
-->
<property name="memoryPageSize">64k</property>
<!--
单位为k
-->
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<!--
单位为m
-->
<property name="systemReserveMemorySize">384m</property>
<!--是否采用zookeeper协调切换 -->
<property name="useZKSwitch">false</property>
<!-- XA Recovery Log日志路径 -->
<!--<property name="XARecoveryLogBaseDir">./</property>-->
<!-- XA Recovery Log日志名称 -->
<!--<property name="XARecoveryLogBaseName">tmlog</property>-->
<!--如果为 true的话 严格遵守隔离级别,不会在仅仅只有select语句的时候在事务中切换连接-->
<property name="strictTxIsolation">false</property>
<!--如果为0的话,涉及多个DataNode的catlet任务不会跨线程执行-->
<property name="parallExecute">0</property>
</system>
<!-- 全局SQL防火墙设置 -->
<!--白名单可以使用通配符%或着*-->
<!--例如<host host="127.0.0.*" user="root"/>-->
<!--例如<host host="127.0.*" user="root"/>-->
<!--例如<host host="127.*" user="root"/>-->
<!--例如<host host="1*7.*" user="root"/>-->
<!--这些配置情况下对于127.0.0.1都能以root账户登录-->
<!--
<firewall>
<whitehost>
<host host="1*7.0.0.*" user="root"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall>
-->
<user name="root" defaultAccount="true">
<property name="password">root</property>
<property name="schemas">TESTDB</property>
<property name="defaultSchema">TESTDB</property>
<!--No MyCAT Database selected 错误前会尝试使用该schema作为schema,不设置则为null,报错 -->
</user>
<user name="user">
<property name="password">user</property>
<property name="schemas">TESTDB</property>
<property name="readOnly">true</property>
<property name="defaultSchema">TESTDB</property>
</user>
</mycat:server>
其实里面本身的介绍已经很详细了,重点给大家看下我修改的部分:
重点就算登陆的用户和密码了:这里的schemas其实就是下面schema.xml里的逻辑数据库名称,到下问中大家可以看到。
2. schema.xml配置介绍:
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<!-- auto sharding by id (long) -->
<!--splitTableNames 启用<table name 属性使用逗号分割配置多个表,即多个表使用这个配置-->
<!--fetchStoreNodeByJdbc 启用ER表使用JDBC方式获取DataNode-->
<!--<table name="user" primaryKey="id" dataNode="dn1,dn2" rule="sharding-by-intfile" autoIncrement="true" fetchStoreNodeByJdbc="true">
<childTable name="user" primaryKey="id" joinKey="id" parentKey="id"> </childTable>
</table>-->
<table name="user" dataNode="dn1,dn2" rule="mod-long"/>
<table name="company" dataNode="dn1"/>
<table name="tenant" primaryKey="id" autoIncrement="true" dataNode="dn1,dn2" rule="mod-long"/>
</schema>
<dataNode name="dn1" dataHost="localhost1" database="mycat_db1" />
<dataNode name="dn2" dataHost="localhost1" database="mycat_db2" />
<dataHost name="localhost1" maxCon="999" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root" password="root">
</writeHost>
</dataHost>
</mycat:schema>
原文件解压后里面的样例内容还是很多的,我删掉了多余的介绍,保留的自己需要的部分:
重点给大家看下修改了的地方
3. rule.xml配置介绍:
<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - You
may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - Unless required by applicable law or agreed to in writing, software -
distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License for the specific language governing permissions and - limitations
under the License. -->
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="rule1">
<rule>
<columns>id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-date">
<rule>
<columns>createTime</columns>
<algorithm>partbyday</algorithm>
</rule>
</tableRule>
<tableRule name="rule2">
<rule>
<columns>user_id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-intfile">
<rule>
<columns>sharding_id</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
<tableRule name="mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-murmur">
<rule>
<columns>id</columns>
<algorithm>murmur</algorithm>
</rule>
</tableRule>
<tableRule name="crc32slot">
<rule>
<columns>id</columns>
<algorithm>crc32slot</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-month">
<rule>
<columns>create_time</columns>
<algorithm>partbymonth</algorithm>
</rule>
</tableRule>
<tableRule name="latest-month-calldate">
<rule>
<columns>calldate</columns>
<algorithm>latestMonth</algorithm>
</rule>
</tableRule>
<tableRule name="auto-sharding-rang-mod">
<rule>
<columns>id</columns>
<algorithm>rang-mod</algorithm>
</rule>
</tableRule>
<tableRule name="jch">
<rule>
<columns>id</columns>
<algorithm>jump-consistent-hash</algorithm>
</rule>
</tableRule>
<function name="murmur"
class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0</property><!-- 默认是0 -->
<property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
<property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
<!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
<!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不会输出任何东西 -->
</function>
<function name="crc32slot"
class="io.mycat.route.function.PartitionByCRC32PreSlot">
<property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
</function>
<function name="hash-int"
class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
</function>
<function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
</function>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">2</property>
</function>
<function name="func1" class="io.mycat.route.function.PartitionByLong">
<property name="partitionCount">8</property>
<property name="partitionLength">128</property>
</function>
<function name="latestMonth"
class="io.mycat.route.function.LatestMonthPartion">
<property name="splitOneDay">24</property>
</function>
<function name="partbymonth"
class="io.mycat.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2015-01-01</property>
</function>
<function name="partbyday"
class="io.mycat.route.function.PartitionByDate">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sNaturalDay">0</property>
<property name="sBeginDate">2014-01-01</property>
<property name="sEndDate">2014-01-31</property>
<property name="sPartionDay">10</property>
</function>
<function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
<property name="mapFile">partition-range-mod.txt</property>
</function>
<function name="jump-consistent-hash" class="io.mycat.route.function.PartitionByJumpConsistentHash">
<property name="totalBuckets">3</property>
</function>
</mycat:rule>
里面配置的内容看似很多,其实都是配置的各种分片规则,有根据日期的,范围的,取模的等等;
因为我测试的是根据取模来分片的,且只分2个片。
所以,这个配置文件只改了一个地方,其它地方原封不动,就是下面截图的部分:默认是3个分片,我给改成2个:
4. mysql数据库准备:
上面都配置好了以后,就是创建配置文件中相关的数据库信息了。
如下截图内容:
所有的配置文件修改好以后,不要忘记保存,保存好以后再启动mycat;
5. 启动mycat
注意:1.mycat在windows环境下需要用管理员权限去启动
2.本机的java环境也安装完成,且是正常可执行的。
我喜欢的打开方式是使用开始菜单,可以查看执行效果:
1.打开以后,进入到mycat的bin目录下:学习的朋友替换成自己的路径地址:
C: cd C:\MyProgram\programs\Mycat-server-1.6.7.6-release-20201126013625-win\mycat\bin
2.执行启动脚本:mycat.bat start
C:\MyProgram\programs\Mycat-server-1.6.7.6-release-20201126013625-win\mycat\bin>mycat.bat start
wrapper | Starting the Mycat-server service...
wrapper | Waiting to start...
wrapper | Mycat-server started.
3.查看执行状态:mycat.bat status
C:\MyProgram\programs\Mycat-server-1.6.7.6-release-20201126013625-win\mycat\bin>mycat.bat status
wrapper | The Mycat-server Service is installed.
wrapper | Start Type: Automatic
wrapper | Interactive: No
wrapper | Running: Yes
看到上面的这个状态就是表示成功启动了,就可以关键命令行界面了,关了之后mycat也是启动状态
4.停止的话也很简单:mycat.bat stop
C:\MyProgram\programs\Mycat-server-1.6.7.6-release-20201126013625-win\mycat\bin>mycat.bat stop
wrapper | Stopping the Mycat-server service...
wrapper | Mycat-server stopped.
注意:
如果启动失败的话,很可能是配置文件有错误,可以到logs目录下去查看日志信息,找到错误原因。
实际中,大部分启动失败的原因是因为配置文件有错误。
6.验证
用native连接上mycat,连接方法和mysql一样,端口8066:用户名和密码就是server.xml中配置的超管用户root,密码也是root;实际生产密码可千万不能这样配置,必须按照密码安全策略去设置账号和密码,我这只是为了方便:
连接上以后,打开sql查询编辑器:随机插入几条数据
INSERT INTO user (`id`, `username`, `age`, `phone`) VALUES ('1', 'tom1', '22', '13200000000');
INSERT INTO user (`id`, `username`, `age`, `phone`) VALUES ('2', 'tom2', '22', '13200000000');
INSERT INTO user (`id`, `username`, `age`, `phone`) VALUES ('3', 'tom3', '22', '13200000000');
执行完成以后,我们先打开mycat中的user表,查看下user表的数据信息:
可以看到数据已经生成,但是id的这个顺序很奇怪,和我们直接在mysql操作的结果好像不太一样:这个就需要大家去了解一下mycat的取模执行原理了,本文不做过多讲解。
接下来,我们再看下mysql的两个实际库中的user表的结果:可以发现id1、3、5、7是在mycat_db2中,id2、4、6、8是在mycat_db1中。原因就算我设置的分片规则是根据2个分片按照2进行取模的。
关于mycat还有很多的坑需要我们去踩,这里只是最基本的一个使用介绍。让我们拿起枪,再接再励,继续踩坑。