業務介紹
我們有一個橫向分表的業務,本來是想自己搞的,但也想嘗試下一些中間件,找到了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 的配置在這裏沒作用, 看源代碼,貌似被註釋了。。。