Mycat安裝與配置詳解

需要提前準備兩個數據庫以便於測試

由於github限制,所以以後新版本從以下地址下載

去這裏下載 http://dl.mycat.io (GitHub的mycat: https://github.com/MyCATApache/Mycat-download)
可以看到最新的穩定版是1.6.7.1
之後的都是測試和開發版,所以我們下載穩定版的1.6.7.1
在這裏插入圖片描述

根據不同這裏下載不同的版本(這裏沒有顯示全,補過可以通過把鼠標移上去看左下角顯示的鏈接信息)
因爲我要下linux版本的。所以我下載第一個Mycat-server-1.6.7.1-release-20190213150257-lin的
在這裏插入圖片描述
下載後上傳到Linux上,我的是centos6.5

解壓安裝包

tar -xvf Mycat-server-1.6.7.1-release-20190213150257-linux.tar.gz
在這裏插入圖片描述
可以看到解壓出來的內容都放到mycat文件夾中了。
刪除安裝包,進入mycat文件夾

在這裏插入圖片描述
bin:命令文件
catlet:空的,擴展
conf:配置文件(server.xml,schema.xml,rule.xml等)
lib:依賴的jar包
在這裏插入圖片描述
進入conf文件夾配置文件

在mycat根目錄創建logs文件夾,會把日誌自動記錄到這裏。
如果啓動報錯可以到此目錄查看日誌
我在安裝的時候發現一個錯誤
本地主機名未知,我的linux主機名稱爲test1,所以報錯,需要在hosts文件中加上我的主機名字
在這裏插入圖片描述
編輯hosts文件:vim /etc/hosts

在這裏插入圖片描述
把我的主機名test1加上即可.
在這裏插入圖片描述

通過命令:ps -ef | grep mycat 查看服務是否已經確認啓動成功

確認成功之後開始配置conf文件夾下的schema.xml、server.xml、rule.xml

配置schema.xml

在後面的測試環節有對此配置的說明內容,很詳細。

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">


	<!--
	name:爲mycat邏輯庫的名字,對應server<property name="schemas">mydatabase</property>,
	建議設置跟數據庫一樣的名稱
	checkSQLschema:自動檢查邏輯庫名稱並拼接,true會在sql語句中的表名前拼接邏輯庫名,
	例如select * from mydatabase.t_user;
	sqlMaxLimit:查詢保護、如果沒有寫limit條件,會自動拼接。只查詢100條。
	-->
	<schema name="mydatabase" checkSQLschema="true" sqlMaxLimit="100">
		<!--
		name:爲物理數據庫的表名,命名與物理數據庫的一致 
		dataNode:爲dataNode標籤(<dataNode name="dn1" dataHost="dtHost1" database="db1" />)裏面的name值
		dataNode裏面填寫的節點數量必須和rule裏面的規則數量一致
		例如rule裏面只定義了兩個0-1M=0  1M-2M=1那麼此處只可以指定兩個節點,1M=10000,M爲單位萬
		primaryKey:爲表的ID字段,建議和rule.xml裏面指定的ID和物理庫的ID一致
		rule:分片規則,對應rule.xml中<tableRule name="student_id">的name
		type:表格類型,默認非global,用於全局表定義
		-->
		<table name="t_user" dataNode="dn1,dn2,dn3" primaryKey="id" rule="auto-sharding-long">
			<!--ER分片注意childTable 標籤需要放到table標籤內,是主外鍵關聯關係,
				name:爲物理數據庫的表名,命名與物理數據庫的一致 
				primaryKey:爲表t_loginlog的ID字段,建議和rule.xml裏面指定的ID和物理庫的ID一致.
				joinKey:從表t_loginlog的外鍵字段,需要和物理庫的字段名稱一致
				parentKey:爲主表t_user的字段名,依據此字段做關聯,進行ER分片
			-->		
			<childTable name="t_loginlog" primaryKey="id" joinKey="user_id" parentKey="id"></childTable>
		</table>
		<table name="t_student" dataNode="dn1,dn3" primaryKey="id" rule="student_id" />
		<table name="t_dictionaries" dataNode="dn1,dn2,dn3" type="global" />
		<table name="t_teacher" dataNode="dn1" />
    </schema>
		
		<!-- name:節點名稱,用於在table標籤裏面調用
		dataHost:dataHost標籤name值(<dataHost name="dtHost1">)
		database:物理數據庫名,需要提前創建好實際存在的-->
		<dataNode name="dn1" dataHost="dtHost1" database="db1" />
		<dataNode name="dn2" dataHost="dtHost1" database="db2" />
		<dataNode name="dn3" dataHost="dtHost2" database="db3" />
		
	<!--
	name:節點名稱,在上方dataNode標籤中調用
	maxCon:底層數據庫的鏈接最大數
	minCon:底層數據庫的鏈接最小數
	balance:值可以爲0,1,2,3,分別表示對當前datahost中維護的數據庫們的讀操作邏輯
	0:不開啓讀寫分離,所有的讀寫操作都在最小的索引號的writeHost(第一個writeHost標籤)
	1:全部的readHost和備用writeHost都參與讀數據的平衡,如果讀的請求過多,負責寫的第一個writeHost也分擔一部分
	2 :所有的讀操作,都隨機的在所有的writeHost和readHost中進行
	3 :所有的讀操作,都到writeHost對應的readHost上進行(備用writeHost不參加了),在集羣中沒有配置ReadHost的情況下,讀都到第
	一個writeHost完成
	writeType:控制當前datahost維護的數據庫集羣的寫操作
	0:所有的寫操作都在第一個writeHost標籤的數據庫進行
	1:所有的寫操作,都隨機分配到所有的writeHost(mycat1.5完全不建議配置了)
	dbtype:數據庫類型(不同數據庫配置不同名稱,mysql)
	dbDriver:數據庫驅動,native,動態獲取
	switchType:切換的邏輯
	-1:故障不切換
	1:故障切換,當前寫操作的writeHost故障,進行切換,切換到下一個writeHost;
	slaveThreshold:標籤中的<heartbeat>用來檢測後端數據庫的心跳sql語句;本屬性檢查從節點與主節點的同步情況(延遲時間數),配合心
	跳語句show slave status; 讀寫分離時,所有的readHost的數據都可靠
	-->
	<dataHost name="dtHost1" maxCon="1000" minCon="10" balance="1"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!--用於驗證心跳,這個是mysql主庫的配置-->
		<heartbeat>select user()</heartbeat>
		
		<writeHost host="127.0.0.1" url="192.168.199.11:3306" user="root" password="123456">
			<readHost host="127.0.0.1" url="192.168.199.12:3306" user="root" password="123456" />
		</writeHost>
	
	</dataHost>
	<dataHost name="dtHost2" maxCon="1000" minCon="10" balance="1"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!--用於驗證心跳,這個是mysql主庫的配置-->
		<heartbeat>select user()</heartbeat>
		
		<writeHost host="127.0.0.1" url="192.168.199.13:3306" user="root" password="123456">
			<readHost host="127.0.0.1" url="192.168.199.13:3306" user="root" password="123456" />
		</writeHost>
	
	</dataHost>
</mycat:schema>

配置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="serverPort">8066</property>
	<property name="nonePasswordLogin">0</property> <!-- 0爲需要密碼登陸、1爲不需要密碼登陸 ,默認爲0,設置爲1則需要指定默認賬戶-->
	<property name="useHandshakeV10">1</property>
	<property name="useSqlStat">0</property>  <!-- 1爲開啓實時統計、0爲關閉 -->
	<property name="useGlobleTableCheck">0</property>  <!-- 1爲開啓全加班一致性檢測、0爲關閉 -->

		<property name="sequnceHandlerType">2</property>
	<property name="subqueryRelationshipCheck">false</property> <!-- 子查詢中存在關聯查詢的情況下,檢查關聯字段中是否有分片字段 .默認 false -->
      <!--  <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="sequnceHandlerType">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="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">1</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>
		
		<property name="useZKSwitch">true</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賬戶登錄-->
	<!-- 此處是開放了本機和外網的請求鏈接,因爲我的mycat安裝在虛擬機上,所以本機是通過ip鏈接
	192.*是爲了讓navicat可以連接使用(配置完整的虛擬機IP也可以)
	127.*是爲了讓虛擬機本身可以通過命令連接-->
	<firewall>
	   <whitehost>
	      <host host="192.*" user="root"/>
		  <host host="127.*" user="root"/>
	   </whitehost>
       <blacklist check="false">
       </blacklist>
	</firewall>
	
	<!-- 此處定義了一個root用戶,可以管理的邏輯庫爲mydatabase,對應schema.xml中的<schema name="mydatabase" > -->
	<user name="root" defaultAccount="true">
		<property name="password">123456</property>
		<property name="schemas">mydatabase</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="user">
		<property name="password">123456</property>
		<property name="schemas">mycat1,test3</property>
		<property name="readOnly">true</property>
	</user>-->

</mycat:server>


配置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/">
<!--schema.xml中配置的rule="student_id" 所對應的規則,規則對應主鍵,
列名爲id需要與數據庫的列名對應algorithm對應下方function-->
	<tableRule name="student_id">
        <rule>
            <columns>id</columns>
            <algorithm>student_text</algorithm>
        </rule>
    </tableRule>
	
	
	<tableRule name="rule1">
		<rule>
			<columns>id</columns>
			<algorithm>func1</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>




<!--在conf中需要添加student_text.txt規則文件-->
 <function name="student_text"
        class="io.mycat.route.function.AutoPartitionByLong">
        <property name="mapFile">student_text.txt</property>
    </function>
	
	
	
	
	
	
	
	
	<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">
	</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">3</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="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>

在conf文件夾創建student_text.txt文件

vim student_text.txt
在這裏插入圖片描述
內容如下,需要注意的是
0-1M ,爲0<=id<=10000,
1M-2M,爲10000<id<=20000,因爲只定義了兩個範圍。如果超過20000例如20001會報錯
說明一下:1k=1000 , 1M=10000

0-1M=0
1M-2M=1

schema.xml中t_student的 table標籤值對應了兩個dataNode節點,所以此處只有兩個規則,不能多,也不能少

<table name="t_student" dataNode="dn1,dn3" primaryKey="id" rule="student_id" />

配置完成後就可以啓動mycat進行測試了

在bin文件夾下執行./mycat start
然後通過navicat進行連接,注意端口爲之前配置的8066,用戶名和密碼也是之前配置的root/123456,連接地址爲mycat安裝主機地址
192.168.199.11和192.168.199.12爲雙機熱備的物理庫,
192.168.199.13爲單機庫,
mycat爲邏輯庫,通過邏輯庫做增刪改查、建表、刪除表等表操作都會同步在其他物理庫上執行。
在這裏插入圖片描述

手動在物理庫上創建好已經定義的庫

然後在mycat中執行sql創建表,並自動同步到物理庫中,注意是mycat執行建表sql

DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;




DROP TABLE IF EXISTS `t_student`;

CREATE TABLE `t_student` (
  `id` int(11) NOT NULL,
  `s_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;





DROP TABLE IF EXISTS `t_teacher`;
CREATE TABLE `t_teacher` (
  `id` int(11) NOT NULL,
  `t_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `t_loginlog`;

CREATE TABLE `t_loginlog` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `create_time` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;



DROP TABLE IF EXISTS `t_dictionaries`;

CREATE TABLE `t_dictionaries` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

在mycat中執行插入數據sql

INSERT INTO `t_student` VALUES ('0', '00');
INSERT INTO `t_student` VALUES ('1', '111');
INSERT INTO `t_student` VALUES ('10000', '10000');
INSERT INTO `t_student` VALUES ('10001', '10001');
INSERT INTO `t_student` VALUES ('20000', '20000');

INSERT INTO `t_user` VALUES ('1', '111');
INSERT INTO `t_user` VALUES ('10000001', '10000001');
INSERT INTO `t_user` VALUES ('5000001', '5000001');

INSERT INTO `t_loginlog` VALUES ('1', '1', '2019-03-08');
INSERT INTO `t_loginlog` VALUES ('3', '10000001', '2019-03-06');
INSERT INTO `t_loginlog` VALUES ('2', '5000001', '2019-03-07');

INSERT INTO `t_dictionaries` VALUES ('1', '1');

打開mycat查看剛剛插入的數據,
在這裏插入圖片描述
首先確認t_student的數據,分片節點爲dn1和dn3對應db1和db3的物理庫,並分別存儲在dtHost1和dtHost2兩臺mysql上
分片規則爲
0-1M=0
1M-2M=1
確認物理庫確實根據ID分開進行存儲
在這裏插入圖片描述

確認t_user是否進行了分片,t_loginlog是否根據和t_user的主外鍵規則進行分片

在這裏插入圖片描述
確認t_user確實按照ID進行了分片,t_loginlog確實根據t_user的外鍵關聯進行了分片,因爲我的SQL並沒有寫主外鍵的約束,所以我手動往t_loginlog也是可以插入數據的

t_dictionaries表爲全局表,所以他的數據操作是同步在所有的數據節點上,

配置了3個數據節點,所以3個數據節點中的數據是一致的
此處就不截圖了。

t_teacher 並沒有進行分片配置,也只定義了一個節點所以是單表,確認只有一個物理庫中存在即可。

在這裏插入圖片描述

至此已經搭建完畢

rule規則詳解



 常用的分片規則:總共十個(基本夠用)
 
一、枚舉法
<tableRule name="sharding-by-intfile">
    <rule>
      <columns>user_id</columns>
      <algorithm>hash-int</algorithm>
    </rule>
  </tableRule>
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
    <property name="mapFile">partition-hash-int.txt</property>
    <property name="type">0</property>
    <property name="defaultNode">0</property>
  </function>
 
partition-hash-int.txt 配置:
10000=0
10010=1
上面columns 標識將要分片的表字段,algorithm 分片函數,
其中分片函數配置中,mapFile標識配置文件名稱,type默認值爲0,0表示Integer,非零表示String,
所有的節點配置都是從0開始,及0代表節點1
/**
*  defaultNode 默認節點:小於0表示不設置默認節點,大於等於0表示設置默認節點,結點爲指定的值
* 
默認節點的作用:枚舉分片時,如果碰到不識別的枚舉值,就讓它路由到默認節點
*                如果不配置默認節點(defaultNode值小於0表示不配置默認節點),碰到
*                不識別的枚舉值就會報錯,
*                like this:can't find datanode for sharding column:column_name val:ffffffff    
*/
 
二、固定分片hash算法
<tableRule name="rule1">
    <rule>
      <columns>user_id</columns>
      <algorithm>func1</algorithm>
    </rule>
</tableRule>
 
  <function name="func1" class="io.mycat.route.function.PartitionByLong">
    <property name="partitionCount">2,1</property>
    <property name="partitionLength">256,512</property>
  </function>
配置說明:
上面columns 標識將要分片的表字段,algorithm 分片函數,
partitionCount 分片個數列表,partitionLength 分片範圍列表
分區長度:默認爲最大2^n=1024 ,即最大支持1024分區
約束 :
count,length兩個數組的長度必須是一致的。
1024 = sum((count[i]*length[i])). count和length兩個向量的點積恆等於1024
用法例子:
@Test
public void testPartition() {
// 本例的分區策略:希望將數據水平分成3份,前兩份各佔25%,第三份佔50%。(故本例非均勻分區)
// |<---------------------1024------------------------>|
// |<----256--->|<----256--->|<----------512---------->|
// | partition0 | partition1 | partition2 |
// | 共2份,故count[0]=2 | 共1份,故count[1]=1 |
int[] count = new int[] { 2, 1 };
int[] length = new int[] { 256, 512 };
PartitionUtil pu = new PartitionUtil(count, length);

// 下面代碼演示分別以offerId字段或memberId字段根據上述分區策略拆分的分配結果
int DEFAULT_STR_HEAD_LEN = 8; // cobar默認會配置爲此值
long offerId = 12345;
String memberId = "qiushuo";

// 若根據offerId分配,partNo1將等於0,即按照上述分區策略,offerId爲12345時將會被分配到partition0中
int partNo1 = pu.partition(offerId);

// 若根據memberId分配,partNo2將等於2,即按照上述分區策略,memberId爲qiushuo時將會被分到partition2中
int partNo2 = pu.partition(memberId, 0, DEFAULT_STR_HEAD_LEN);

Assert.assertEquals(0, partNo1);
Assert.assertEquals(2, partNo2);
}
 
如果需要平均分配設置:平均分爲4分片,partitionCount*partitionLength=1024
<function name="func1" class="org.opencloudb.route.function.PartitionByLong">
    <property name="partitionCount">4</property>
    <property name="partitionLength">256</property>
  </function>
 
三、範圍約定
<tableRule name="auto-sharding-long">
    <rule>
      <columns>user_id</columns>
      <algorithm>rang-long</algorithm>
    </rule>
  </tableRule>
<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
    <property name="mapFile">autopartition-long.txt</property>
  </function>
# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
500M-1000M=1
1000M-1500M=2
或
0-10000000=0
10000001-20000000=1
 
 
配置說明:
上面columns 標識將要分片的表字段,algorithm 分片函數,
rang-long 函數中mapFile代表配置文件路徑
所有的節點配置都是從0開始,及0代表節點1,此配置非常簡單,即預先制定可能的id範圍到某個分片
 
四、求模法
<tableRule name="mod-long">
    <rule>
      <columns>user_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">3</property>
  </function>
 
配置說明:
上面columns 標識將要分片的表字段,algorithm 分片函數,
此種配置非常明確即根據id與count(你的結點數)進行求模預算,相比方式1,此種在批量插入時需要切換數據源,id不連續
 
五、日期列分區法
<tableRule name="sharding-by-date">
      <rule>
        <columns>create_time</columns>
        <algorithm>sharding-by-date</algorithm>
      </rule>
   </tableRule> 
<function name="sharding-by-date" class="io.mycat.route.function..PartitionByDate">
   <property name="dateFormat">yyyy-MM-dd</property>
    <property name="sBeginDate">2014-01-01</property>
    <property name="sPartionDay">10</property>
  </function>
配置說明:
上面columns 標識將要分片的表字段,algorithm 分片函數,
配置中配置了開始日期,分區天數,即默認從開始日期算起,分隔10天一個分區
 
還有一切特性請看源碼
 
 
Assert.assertEquals(true, 0 == partition.calculate("2014-01-01"));
Assert.assertEquals(true, 0 == partition.calculate("2014-01-10"));
Assert.assertEquals(true, 1 == partition.calculate("2014-01-11"));
Assert.assertEquals(true, 12 == partition.calculate("2014-05-01"));
 
 
 
六、通配取模
<tableRule name="sharding-by-pattern">
      <rule>
        <columns>user_id</columns>
        <algorithm>sharding-by-pattern</algorithm>
      </rule>
   </tableRule>
<function name="sharding-by-pattern" class="io.mycat.route.function.PartitionByPattern">
    <property name="patternValue">256</property>
    <property name="defaultNode">2</property>
    <property name="mapFile">partition-pattern.txt</property>
 
  </function>
partition-pattern.txt 
# id partition range start-end ,data node index
###### first host configuration
1-32=0
33-64=1
65-96=2
97-128=3
######## second host configuration
129-160=4
161-192=5
193-224=6
225-256=7
0-0=7
配置說明:
上面columns 標識將要分片的表字段,algorithm 分片函數,patternValue 即求模基數,defaoultNode 默認節點,如果不配置了默認,則默認是0即第一個結點
mapFile 配置文件路徑
配置文件中,1-32 即代表id%256後分布的範圍,如果在1-32則在分區1,其他類推,如果id非數字數據,則會分配在defaoultNode 默認節點
 
 
String idVal = "0";
Assert.assertEquals(true, 7 == autoPartition.calculate(idVal));
idVal = "45a";
Assert.assertEquals(true, 2 == autoPartition.calculate(idVal));
 
七、ASCII碼求模通配
<tableRule name="sharding-by-prefixpattern">
      <rule>
        <columns>user_id</columns>
        <algorithm>sharding-by-prefixpattern</algorithm>
      </rule>
   </tableRule>
<function name="sharding-by-pattern" class="io.mycat.route.function.PartitionByPrefixPattern">
    <property name="patternValue">256</property>
    <property name="prefixLength">5</property>
    <property name="mapFile">partition-pattern.txt</property>
 
  </function>
 
partition-pattern.txt
 
# range start-end ,data node index
# ASCII
# 48-57=0-9
# 64、65-90=@、A-Z
# 97-122=a-z
###### first host configuration
1-4=0
5-8=1
9-12=2
13-16=3
###### second host configuration
17-20=4
21-24=5
25-28=6
29-32=7
0-0=7
配置說明:
上面columns 標識將要分片的表字段,algorithm 分片函數,patternValue 即求模基數,prefixLength ASCII 截取的位數
mapFile 配置文件路徑
配置文件中,1-32 即代表id%256後分布的範圍,如果在1-32則在分區1,其他類推 
 
此種方式類似方式6只不過採取的是將列種獲取前prefixLength位列所有ASCII碼的和進行求模sum%patternValue ,獲取的值,在通配範圍內的
即 分片數,
/**
* ASCII編碼:
* 48-57=0-9阿拉伯數字
* 64、65-90=@、A-Z
* 97-122=a-z
*
*/
如 
 
String idVal="gf89f9a";
Assert.assertEquals(true, 0==autoPartition.calculate(idVal));

idVal="8df99a";
Assert.assertEquals(true, 4==autoPartition.calculate(idVal));

idVal="8dhdf99a";
Assert.assertEquals(true, 3==autoPartition.calculate(idVal));
 
八、編程指定
<tableRule name="sharding-by-substring">
      <rule>
        <columns>user_id</columns>
        <algorithm>sharding-by-substring</algorithm>
      </rule>
   </tableRule>
<function name="sharding-by-substring" class="io.mycat.route.function.PartitionDirectBySubString">
    <property name="startIndex">0</property> <!-- zero-based -->
    <property name="size">2</property>
    <property name="partitionCount">8</property>
    <property name="defaultPartition">0</property>
  </function>
配置說明:
上面columns 標識將要分片的表字段,algorithm 分片函數 
此方法爲直接根據字符子串(必須是數字)計算分區號(由應用傳遞參數,顯式指定分區號)。
例如id=05-100000002
在此配置中代表根據id中從startIndex=0,開始,截取siz=2位數字即05,05就是獲取的分區,如果沒傳默認分配到defaultPartition
 
九、字符串拆分hash解析
<tableRule name="sharding-by-stringhash">
      <rule>
        <columns>user_id</columns>
        <algorithm>sharding-by-stringhash</algorithm>
      </rule>
   </tableRule>
<function name="sharding-by-substring" class="io.mycat.route.function.PartitionByString">
    <property name=length>512</property> <!-- zero-based -->
    <property name="count">2</property>
    <property name="hashSlice">0:2</property>
  </function>
配置說明:
上面columns 標識將要分片的表字段,algorithm 分片函數 
函數中length代表字符串hash求模基數,count分區數,hashSlice hash預算位
即根據子字符串 hash運算
 
hashSlice : 0 means str.length(), -1 means str.length()-1
 
/**
     * "2" -&gt; (0,2)<br/>
     * "1:2" -&gt; (1,2)<br/>
     * "1:" -&gt; (1,0)<br/>
     * "-1:" -&gt; (-1,0)<br/>
     * ":-1" -&gt; (0,-1)<br/>
     * ":" -&gt; (0,0)<br/>
     */
public class PartitionByStringTest {

@Test
public void test() {
PartitionByString rule = new PartitionByString();
String idVal=null;
rule.setPartitionLength("512");
rule.setPartitionCount("2");
rule.init();
rule.setHashSlice("0:2");
//    idVal = "0";
//    Assert.assertEquals(true, 0 == rule.calculate(idVal));
//    idVal = "45a";
//    Assert.assertEquals(true, 1 == rule.calculate(idVal));



//last 4
rule = new PartitionByString();
rule.setPartitionLength("512");
rule.setPartitionCount("2");
rule.init();
//last 4 characters
rule.setHashSlice("-4:0");
idVal = "aaaabbb0000";
Assert.assertEquals(true, 0 == rule.calculate(idVal));
idVal = "aaaabbb2359";
Assert.assertEquals(true, 0 == rule.calculate(idVal));
}
 
十、一致性hash
<tableRule name="sharding-by-murmur">
      <rule>
        <columns>user_id</columns>
        <algorithm>murmur</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>



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章