业务介绍
我们有一个横向分表的业务,本来是想自己搞的,但也想尝试下一些中间件,找到了mycat先试下,
现在是2017/12 , 版本采用 mycat1.6.5
安装及相关内容
https://github.com/MyCATApache/Mycat-Server
mysql准备
创建三个db :db1,db2,db3,都加入这张表:
CREATE TABLE `travelrecord` (
`id` bigint(20) NOT NULL,
`user_id` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`traveldate` date DEFAULT NULL,
`fee` decimal(10,0) DEFAULT NULL,
`days` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
相关配置
cd /alidata/server/mycat/mycat
基本上默认配置 加下小修改就行了,主要是server.xml 和 scheme.xml
server.xml:
<property name="serverPort">4566</property>
<property name="managerPort">4567</property>
<firewall>
<whitehost>
<host host="*" user="abcefg"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall>
<user name="abcefg">
<property name="password">abcefg2017</property>
<property name="schemas">TESTDB</property>
</user>
scheme.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) -->
<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
</schema>
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost1" database="db2" />
<dataNode name="dn3" dataHost="localhost1" database="db3" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostS1" url="127.0.0.1:3306" user="mycat"
password="mycat123" />
</dataHost>
</mycat:schema>
如果你的内存不太够,记得改一下 wrapper.conf 里面的内存配置,
mycat的服务(用mysql客户端访问):xxxx 端口 4566 , 用户xxx,密码 xxx2017
实际数据库表地址: xxx 端口 3306 用户mycat 密码 mycat123 (里面的dn1,dn2,dn3)
启动
/xxx/mycat/mycat/bin/mycat start
/xxx/mycat/mycat/bin/mycat stop
mycat 的一些策略
mycat的分片规则有很多,可能参考 其文档http://www.mycat.io/document/Mycat_V1.6.0.pdf
具体在规则配置上,则是rule.xml中
以下为我取的一个 一致性hash的配置
<function name="murmur"
class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0</property><!-- 默认是0 -->
<property name="count">4</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
<property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
<!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则
以1代替 -->
</function>
如果要使用,建立一个tableRule,algorithm 引用这个murmur
<tableRule name="rule-guid">
<rule>
<columns>device_guid</columns>
<algorithm>murmur</algorithm>
</rule>
</tableRule>
在表映射中的scheme.xml中,则这样引用
<table name="tx_device_user_jiguang" primaryKey="device_guid" subTables="tx_device_user_jiguang0$0-3" dataNode="dn1" rule="rule-guid" />
一致性hash的分析
我们要使用其一致性hash,但不知道其具体的规则,于是找他们的源码以确认,源码可在其github中找
PartitionByMurmurHash.java
发现这个类的init的时候调用生成bucketMap,
private void generateBucketMap(){
hash=Hashing.murmur3_32(seed);//计算一致性哈希的对象
for(int i=0;i<count;i++){//构造一致性哈希环,用TreeMap表示
StringBuilder hashName=new StringBuilder("SHARD-").append(i);
for(int n=0,shard=virtualBucketTimes*getWeight(i);n<shard;n++){
bucketMap.put(hash.hashUnencodedChars(hashName.append("-NODE-").append(n)).asInt(),i);
}
}
weightMap=null;
}
在其使用的时候则用
public Integer calculate(String columnValue) {
SortedMap<Integer, Integer> tail = bucketMap.tailMap(hash.hashUnencodedChars(columnValue).asInt());
if (tail.isEmpty()) {
return bucketMap.get(bucketMap.firstKey());
}
return tail.get(tail.firstKey());
}
结合 一致性hash的逻辑,可以确认,generateBucketMap是 生成一个主机数*160(160是默认值)的treeMap,其val为主机序列,而calculate的方法,入参为 字段值,出参则为 主机序列.
提示,网上很多说的bucketMapPath 这个rule.xml 的配置在这里没作用, 看源代码,貌似被注释了。。。