1. 程式人生 > >mycat介紹01-mysql讀寫分離配置

mycat介紹01-mysql讀寫分離配置

一 。mycat介紹

 1》mycat出現場景 

   在網際網路時代,海量資料的儲存與訪問成為系統設計與使用的瓶頸問題,對於海量資料處理,按照使用場景,主要分為兩種型別:聯機事務處理(OLTP)和聯機分析處理(OLAP)。
聯機事務處理(OLTP)也稱為面向交易的處理系統,其基本特徵是原始資料可以立即傳送到計算中心進行處理,並在很短的時間內給出處理結果。
聯機分析處理(OLAP)是指通過多維的方式對資料進行分析、查詢和報表,可以同資料探勘工具、統計分析工具配合使用,增強決策分析功能

對於兩者的主要區別可以用下表來說明:

OLTP

OLAP

系統功能

日常交易處理

統計、分析、報表

DB 設計

面向實時交易類應用

面向統計分析類應用

資料處理

當前的, 最新的細節的, 二維的分立的

歷史的, 聚集的, 多維的整合的, 統一的

實時性

實時讀寫要求高

實時讀寫要求低

事務

強一致性

弱事務

分析要求

低、簡單

高、複雜 

資料切分的概念

     簡單來說,就是指通過某種特定的條件,將我們存放在同一個資料庫中的資料分散存放到多個數據庫(主機)上面,以達到分散單臺裝置負載的效果。
資料的切分(Sharding)根據其切分規則的型別,可以分為兩種切分模式。一種是按照不同的表(或者Schema)來切分到不同的資料庫(主機)之上,這種切可以稱之為資料的垂直(縱向)切分;另外一種則是根據表中的資料的邏輯關係,將同一個表中的資料按照某種條件拆分到多臺資料庫(主機)上面,這種切分稱之為資料的水平(橫向)切分。
垂直切分的最大特點就是規則簡單,實施也更為方便,尤其適合各業務之間的耦合度非常低,相互影響很小,業務邏輯非常清晰的系統。在這種系統中,可以很容易做到將不同業務模組所使用的表分拆到不同的資料庫中。根據不同的表來進行拆分,對應用程式的影響也更小,拆分規則也會比較簡單清晰。
水平切分於垂直切分相比,相對來說稍微複雜一些。因為要將同一個表中的不同資料拆分到不同的資料庫中,對於應用程式來說,拆分規則本身就較根據表名來拆分更為複雜,後期的資料維護也會更為複雜一些。
垂直切分


一個數據庫由很多表的構成,每個表對應著不同的業務,垂直切分是指按照業務將表進行分類,分佈到不同的資料庫上面,這樣也就將資料或者說壓力分擔到不同的庫上面,如下圖:


系統被切分成了,使用者,訂單交易,支付幾個模組。
一個架構設計較好的應用系統,其總體功能肯定是由很多個功能模組所組成的,而每一個功能模組所需要的資料對應到資料庫中就是一個或者多個表。而在架構設計中,各個功能模組相互之間的互動點越統一越少,系統的耦合度就越低,系統各個模組的維護性以及擴充套件性也就越好。這樣的系統,實現資料的垂直切分也就越容易。
但是往往系統之有些表難以做到完全的獨立,存在這擴庫join的情況,對於這類的表,就需要去做平衡,是資料庫讓步業務,共用一個數據源,還是分成多個庫,業務之間通過介面來做呼叫。在系統初期,資料量比較少,或者資源有限的情況下,會選擇共用資料來源,但是當資料發展到了一定的規模,負載很大的情況,就需要必須去做分割。
一般來講業務存在著複雜join的場景是難以切分的,往往業務獨立的易於切分。如何切分,切分到何種程度是考驗技術架構的一個難題。
下面來分析下垂直切分的優缺點:

優點:
19
 拆分後業務清晰,拆分規則明確。
 系統之間整合或擴充套件容易。
 資料維護簡單。
缺點:
 部分業務表無法join,只能通過介面方式解決,提高了系統複雜度。
 受每種業務不同的限制存在單庫效能瓶頸,不易資料擴充套件跟效能提高。
 事務處理複雜。
由於垂直切分是按照業務的分類將表分散到不同的庫,所以有些業務表會過於龐大,存在單庫讀寫與儲存瓶頸,所以就需要水平拆分來做解決。

水平切分

相對於垂直拆分,水平拆分不是將表做分類,而是按照某個欄位的某種規則來分散到多個庫之中,每個表中包含一部分資料。簡單來說,我們可以將資料的水平切分理解為是按照資料行的切分,就是將表中的某些行切分到一個數據庫,而另外的某些行又切分到其他的資料庫中,如圖:


拆分資料就需要定義分片規則。關係型資料庫是行列的二維模型,拆分的第一原則是找到拆分維度。比如:從會員的角度來分析,商戶訂單交易類系統中查詢會員某天某月某個訂單,那麼就需要按照會員結合日期來拆分,不同的資料按照會員ID做分組,這樣所有的資料查詢join都會在單庫內解決;如果從商戶的角度來講,要查詢某個商家某天所有的訂單數,就需要按照商戶ID做拆分;但是如果系統既想按會員拆分,又想按商家資料,則會有一定的困難。如何找到合適的分片規則需要綜合考慮衡量。
幾種典型的分片規則包括:
 按照使用者ID求模,將資料分散到不同的資料庫,具有相同資料使用者的資料都被分散到一個庫中。
 按照日期,將不同月甚至日的資料分散到不同的庫中。
 按照某個特定的欄位求摸,或者根據特定範圍段分散到不同的庫中。
如圖,切分原則都是根據業務找到適合的切分規則分散到不同的庫,下面用使用者ID求模舉例:


既然資料做了拆分有優點也就優缺點。
優點:
 拆分規則抽象好,join操作基本可以資料庫做。
 不存在單庫大資料,高併發的效能瓶頸。
 應用端改造較少。
 提高了系統的穩定性跟負載能力。

缺點:
21
 拆分規則難以抽象。
 分片事務一致性難以解決。
 資料多次擴充套件難度跟維護量極大。
 跨庫join效能較差。

前面講了垂直切分跟水平切分的不同跟優缺點,會發現每種切分方式都有缺點,但共同的特點缺點有:
 引入分散式事務的問題。
 跨節點Join的問題。
 跨節點合併排序分頁問題。
 多資料來源管理問題。
針對資料來源管理,目前主要有兩種思路:

A. 客戶端模式,在每個應用程式模組中配置管理自己需要的一個(或者多個)資料來源,直接訪問各個資料庫,在模組內完成資料的整合;
B. 通過中間代理層來統一管理所有的資料來源,後端資料庫叢集對前端應用程式透明;
可能90%以上的人在面對上面這兩種解決思路的時候都會傾向於選擇第二種,尤其是系統不斷變得龐大複雜的時候。確實,這是一個非常正確的選擇,雖然短期內需要付出的成本可能會相對更大一些,但是對整個系統的擴充套件性來說,是非常有幫助的。
Mycat 通過資料切分解決傳統資料庫的缺陷,又有了NoSQL易於擴充套件的優點。通過中間代理層規避了多資料來源的處理問題,對應用完全透明,同時對資料切分後存在的問題,也做了解決方案。下面章節就分析,mycat的由來及如何進行資料切分問題。

由於資料切分後資料Join的難度在此也分享一下資料切分的經驗:
第一原則:能不切分儘量不要切分。
第二原則:如果要切分一定要選擇合適的切分規則,提前規劃好。
第三原則:資料切分儘量通過資料冗餘或表分組(Table Group)來降低跨庫Join的可能。
第四原則:由於資料庫中介軟體對資料Join實現的優劣難以把握,而且實現高效能難度極大,業務讀取儘量少使用多表Join。
什麼是mycat,maycat從哪裡來,又是如何解決這些問題的

2》mycat概念

 Mycat是什麼?Mycat是資料庫中介軟體,就是介於資料庫與應用之間,進行資料處理與互動的中間服務。由於前面講的對資料進行分片處理之後,從原有的一個庫,被切分為多個分片資料庫,所有的分片資料庫叢集構成了整個完整的資料庫儲存。


  • 邏輯庫(schema) 就是在mycat中定義的庫 該庫可能指向多個主機的多個實際的物理庫 mycat中 show databases檢視所有邏輯庫

     在schema.xml中定義 比如

<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
	    <!-- 客戶端建立的表 必須在這裡定義否則 丟擲  op table not in schema MYUSER -->
		<table name="myuser" dataNode="dn1,dn2" rule="sharding-by-sex" />
</schema>
顯示資料庫
mysql> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB   |
+----------+
1 row in set (0.00 sec)


  • 邏輯表(table)可能資料被水平切分到不同的主機下不同資料庫下 mycat中 通過 show tables檢視所有邏輯表
<table name="myuser" dataNode="dn1,dn2" rule="sharding-by-sex" />
 進入邏輯庫 顯示邏輯表
mysql> use TESTDB;
Database changed
mysql> show tables;
+------------------+
| Tables in TESTDB |
+------------------+
| myuser           |
+------------------+
1 row in set (0.00 sec)
  • 節點主機(dataHost)  真正的資料庫的ip 埠使用者名稱資訊 一個節點主機(可能存在多個備機從機 備機和從機的資料和主機必須完全一樣也就是配置主從結構    等,可以用於做讀寫分離 )比如
<dataHost name="myhost" maxCon="1000" minCon="10" balance="1"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<!-- 主從結構 147是主節點  151是備節點     149和150是從節點 -->
		<writeHost host="hostM1" url="192.168.58.147:3306" user="root"
				   password="root">
		    <!-- 使用客戶端連線mycat後  預設使用readHost讀操作  使用主節點進行寫操作 如果主節點掛了 備節點稱為主節點 -->
			<readHost host="hostS1" url="192.168.58.149:3306" user="root" password="root" />
			
		</writeHost>
		<writeHost host="hostM2" url="192.168.58.151:3306" user="root"
				   password="root" />
	</dataHost>
  • 分片節點(dataNode)  表示哪臺節點主機上的哪個資料庫 邏輯庫和邏輯表的資料可以被拆分在分片節點上 
<dataNode name="dn1" dataHost="myhost" database="db1" />
  • 分片規則(rule) 多個分片節點 必須通過一定的規則拆分到不同的分片節點上 一般定義在rule.xml中  在邏輯表上指定 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><!--演算法是哪一個 下邊定義的function定義的就是演算法-->
		</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>
	<!-- 
	  一致性hash(參考一致性hash解決方案 可以動態擴容和刪除節點 而基本不影響資料分佈)
	    虛擬一些節點用於平衡資料資料到環上所有節點
	 -->
	<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>
	<!-- 自動遷移御用分片演算法,預分slot 102400個,對映到dn上,再conf下會儲存對映檔案,請不要修改 -->
	<function name="crc32slot"
			  class="io.mycat.route.function.PartitionByCRC32PreSlot">
		<property name="count">2</property><!-- 要分片的資料庫節點數量,必須指定,否則沒法分片 -->
	</function>
	<!-- 
	   分片列舉
		首先所有的資料節點 配置的索引從 0 開始  如果有三臺 分別 是 0-1-2
		hash-int表示int型別列舉值 被放到哪個資料節點 
		  比如  資料庫欄位 sex 0表示男 1表示女  男性放在第二個資料節點  女性放在第一個資料節點
		 mapfile屬性指定檔案中 可以這樣配置
		 性別   datanode索引
		 0   1
		 1   0	
		 defaultNode表示 如果某些索引值 找不到對應的資料節點 資料存在於預設的該節點
	 -->
	<function name="hash-int"
		class="io.mycat.route.function.PartitionByFileMap">
		<property name="mapFile">partition-hash-int.txt</property>
		<property name="defaultNode">0</property>
	</function>
	<!-- 
	 範圍約定
	   表示傳入的列在某個範圍 就放某個節點上 比如id是1-10000的存在0節點  10001-20000的存在節點1
	   比如 mapFile 配置是
	   1-10000 0
	   10001 20000 1
	 -->
	<function name="rang-long"
		class="io.mycat.route.function.AutoPartitionByLong">
		<property name="mapFile">autopartition-long.txt</property>
		<property name="defaultNode">0</property>
	</function>
	<!-- 
	  取模
	   一般是主鍵的值 %節點數量(count指定) 獲取的結果決定存取的節點
	 -->
	<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
		<!-- how many data nodes -->
		<property name="count">3</property>
	</function>
	<!-- 
	 固定分片hash演算法
	  該種類型表示  最終傳入的列值是long型別 
	   要求滿足 1024 = sum((count[i]*length[i])).
	   比如 下面的count=8 length=128  count*length=8*128=1024資料被平均分配到8個節點
	 比如 count=2,1 length=256,512  2*256+1*512=1024  一個三個節點 前面兩個節點資料佔 256/1024=25%
	          最後一個節點是  512/1024=50% 總共100%
	 -->
	<function name="func1" class="io.mycat.route.function.PartitionByLong">
		<property name="partitionCount">8</property>
		<property name="partitionLength">128</property>
	</function>
	<!-- 按日期(天分片)
	    從開始日期到結束日期的 每過 10天分片一個數據節點 如果提供了結束時間到達時間後 從頭開始計算
	 -->
	<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="sEndDate">2014-01-02</property> 
		<property name="sPartionDay">10</property> 
	</function>
	<!-- 
	   按單月小時拆分
	     一天拆分 24個片 也就是一小時一個 下個月 從頭開始分片
	 -->
	<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>
	<!-- 
	  先對資料進行範圍分割槽 (範圍分割槽裡有幾個節點) 然後改範圍的節點中進行取模運算到哪個節點
	  id範圍  節點數
	  1-200  2              分片組1 裡面有兩個節點  id範圍1-200
	  201-400 3
	  401-500 5
	 比如插入 id為 5的 肯定通過範圍確定時在第一個分片組中   5%2=1 表示儲存在分片組1的第二個節點上
	 -->
	<function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
        	<property name="mapFile">partition-range-mod.txt</property>
	</function>
	<!-- 
	 跳增一致性雜湊分片 思想源自Google公開論文,比傳統一致性雜湊更省資源速度更快資料遷移量更少 
	 -->
	<function name="jump-consistent-hash" class="io.mycat.route.function.PartitionByJumpConsistentHash">
		<property name="totalBuckets">3</property>
	</function>
</mycat:rule>
  • 全域性序列號(sequence) 分片後 同一個邏輯表的資料分佈在不同的主機庫中 必須定義全域性的主鍵 用於控制資源的唯一
    支援以下幾種:本地檔案方式,資料庫方式,本地時間戳方式 ,zk方式等 具體參考權威指南  第九章 全域性序列號

  3》mycat的join

   Join絕對是關係型資料庫中最常用一個特性,然而在分散式環境中,跨分片的join確是最複雜的,最難解決一個問題。

  mycat建議你儘量使用innerjoin 少使用left或者rightjoin 條件儘量放在on中 少放在where中

  •  全域性表

一個真實的業務系統中,往往存在大量的類似字典表的表格,它們與業務表之間可能有關係,這種關係,可以理解為“標籤”,而不應理解為通常的“主從關係”,這些表基本上很少變動,可以根據主鍵ID進行快取,下面這張圖說明了一個典型的“標籤關係”圖:


在分片的情況下,當業務表因為規模而進行分片以後,業務表與這些附屬的字典表之間的關聯,就成了比較棘手的問題,考慮到字典表具有以下幾個特性:
• 變動不頻繁
• 資料量總體變化不大
• 資料規模不大,很少有超過數十萬條記錄。
鑑於此,MyCAT定義了一種特殊的表,稱之為“全域性表”,全域性表具有以下特性:
• 全域性表的插入、更新操作會實時在所有節點上執行,保持各個分片的資料一致性
• 全域性表的查詢操作,只從一個節點獲取
• 全域性表可以跟任何一個表進行JOIN操作
將字典表或者符合字典表特性的一些表定義為全域性表,則從另外一個方面,很好的解決了資料JOIN的難題。通過全域性表+基於E-R關係的分片策略,MyCAT可以滿足80%以上的企業應用開發。

全域性表配置比較簡單,不用寫Rule規則,如下配置即可: 

<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
需要注意的是,全域性表每個分片節點上都要有執行建立表的DDL語句。
  • ER Join
MyCAT借鑑了NewSQL領域的新秀Foundation DB的設計思路,Foundation DB創新性的提出了Table Group的概念,其將子表的儲存位置依賴於主表,並且物理上緊鄰存放,因此徹底解決了JION的效率和效能問題,根據這一思路,提出了基於E-R關係的資料分片策略,子表的記錄與所關聯的父表記錄存放在同一個資料分片上。
customer採用sharding-by-intfile這個分片策略,分片在dn1,dn2上,orders依賴父表進行分片,兩個表的關聯關係為orders.customer_id=customer.id。於是資料分片和儲存的示意圖如下:


這樣一來,分片Dn1上的的customer與Dn1上的orders就可以進行區域性的JOIN聯合,Dn2上也如此,再合併兩個節點的資料即可完成整體的JOIN,試想一下,每個分片上orders表有100萬條,則10個分片就有1個億,基於E-R對映的資料分片模式,基本上解決了80%以上的企業應用所面臨的問題。
配置
以上述例子為例,schema.xml中定義如下的分片配置:

<table name="customer" dataNode="dn1,dn2" rule="sharding-by-intfile"> <childTable name="orders" joinKey="customer_id" parentKey="id"/> </table>
  • Share join
ShareJoin是一個簡單的跨分片Join,基於HBT的方式實現。
目前支援2個表的join,原理就是解析SQL語句,拆分成單表的SQL語句執行,然後把各個節點的資料彙集。

二。mycat原始碼安裝

 使用git客戶端 使用 git clone 或者eclipse下載github原始碼

eclipse切換到git透檢視 新增git地址:https://github.com/MyCATApache/Mycat-Server.git 選擇1.6版本 點選fetch抓取


選擇目錄下載後 檢視是個maven專案 eclipse匯入 存在的maven專案(eclipse配置maven環境 我配置倉庫是maven.aliyun.com)

mycat原始碼中 連線的mycat自己的私服 無法連線 所以需要去掉 使用maven環境下的aliyun

開啟pom.xml註釋 以下內容

<!--
	<repositories>
		<repository>
			<id>nexus</id>
			<name>local private nexus</name>
			<url>http://nexus.mycat.io/content/groups/public</url>
		</repository>
	</repositories>
	<distributionManagement>
		<repository>
			<id>releases</id>
			<name>Internal Releases</name>
			<url>http://nexus.mycat.io/content/repositories/releases</url>
		</repository>
		<snapshotRepository>
			<id>snapshots</id>
			<name>Internal Snapshots</name>
			<url>http://nexus.mycat.io/content/repositories/snapshots</url>
		</snapshotRepository>
	</distributionManagement>
	-->
大概半分鐘後 jar包下載完成 專案不再報錯  執行 MycatStartup 類 報錯 說是 記憶體
2017-11-21 10:14:38,518 [ERROR][main] 2017-11-21 10:14:38 startup error java.lang.NumberFormatException: Size must be specified as bytes (b), kibibytes (k), mebibytes (m), gibibytes (g), tebibytes (t), or pebibytes(p). E.g. 50b, 100k, or 250m.
Failed to parse byte string: -53215232B
	at io.mycat.memory.unsafe.utils.JavaUtils.byteStringAs(JavaUtils.java:223)
	at io.mycat.memory.unsafe.utils.JavaUtils.byteStringAsBytes(JavaUtils.java:234)
	at io.mycat.memory.unsafe.utils.MycatPropertyConf.byteStringAsBytes(MycatPropertyConf.java:92)
	at io.mycat.memory.unsafe.utils.MycatPropertyConf.getSizeAsBytes(MycatPropertyConf.java:50)
	at io.mycat.memory.unsafe.memory.mm.MemoryManager.<init>(MemoryManager.java:30)
	at io.mycat.memory.unsafe.memory.mm.ResultMergeMemoryManager.<init>(ResultMergeMemoryManager.java:15)
	at io.mycat.memory.MyCatMemory.<init>(MyCatMemory.java:126)
	at io.mycat.MycatServer.startup(MycatServer.java:390)
	at io.mycat.MycatStartup.main(MycatStartup.java:57)
 (io.mycat.MycatStartup:MycatStartup.java:62) 
後面除錯了一下原始碼 發現是
  Runtime.maxMemory()-SystemConfig.systemReserveMemorySize結果出來個負數 java程式執行的記憶體減去 server.xml配置的systemReserveMemorySize(384M)

將執行內容 調大   新增執行vm引數  -Xmx1024M 重啟正常

三。mycat配置一覽

 mycat存在三個核心的配置檔案:

  Schema.xml作為MyCat中重要的配置檔案之一,管理著MyCat的邏輯庫、表、分片規則、DataNode以及DataSource。弄懂這些配置,是正確使用MyCat的前提。這裡就一層層對該檔案進行解析。

  server.xml幾乎儲存了所有mycat需要的系統配置資訊。其在程式碼內直接的對映類為SystemConfig類。

  rule.xml裡面就定義了我們對錶進行拆分所涉及到的規則定義。我們可以靈活的對錶使用不同的分片演算法,或者對錶使用相同的演算法但具體的引數不同。這個檔案裡面主要有tableRule和function這兩個標籤。在具體使用過程中可以按照需求新增tableRule和function。

 具體配置參考 http://mycat.io/和mycat權威指南(入門篇  第七章 Mycat的配置)

四。mycat讀寫分離配置

 環境:

   資料庫:mariadb 中介軟體mycat

主:192.168.58.147:3306" 
 從1:192.168.58.149:3306 
主備:192.168.58.151:3306
 從2:192.168.58.150:3306 
mycat不支援主從複製的 必須依靠mysql的logbin機制 mycat只是做讀寫分離負載 所有的寫入都寫入到WriteHost,所有的讀都平均分配到所有的ReadHost

mysql的雙主雙從 環境 參考mysql的安裝(http://blog.csdn.net/liaomin416100569/article/details/78580382)
schema.xml(src/main/resources)配置節點主機 分片節點 邏輯庫(TESTDB) 邏輯表(myuser)

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

	<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
	    <!-- 客戶端建立的表 必須在這裡定義否則 丟擲  op table not in schema MYUSER -->
		<table name="myuser" dataNode="dn1,dn2" rule="sharding-by-sex" />
	</schema>
	<!--分片節點 同一臺主機可以有多個數據庫充當節點-->
	<dataNode name="dn1" dataHost="myhost" database="db1" />
	<dataNode name="dn2" dataHost="myhost" database="db2" />
	<!--分片主機 -->
	<!-- 執行測試sql
	    create database db1;
		use db1;
		create table myuser(
		  id int primary key auto_increment,
		  uname varchar(20),
		  sex int default 0
		);
		
		create database db2;
		use db2;
		create table myuser(
		  id int primary key auto_increment,
		  uname varchar(20),
		  sex int default 0
		);
		
	 -->
	<dataHost name="myhost" maxCon="1000" minCon="10" balance="1"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<!-- 主從結構 147是主節點  151是備節點     149和150是從節點 -->
		<writeHost host="hostM1" url="192.168.58.147:3306" user="root"
				   password="root">
		    <!-- 使用客戶端連線mycat後  預設使用readHost讀操作  使用主節點進行寫操作 如果主節點掛了 備節點稱為主節點 -->
			<readHost host="hostS1" url="192.168.58.149:3306" user="root" password="root" />
			
		</writeHost>
		<writeHost host="hostM2" url="192.168.58.151:3306" user="root"
				   password="root" >
			<readHost host="hostS2" url="192.168.58.150:3306" user="root" password="root" />
		</writeHost>
	</dataHost>
	
</mycat:schema>
配置分表規則  rule="sharding-by-sex"  這裡只是測試假設有張表 有個性別欄位 性別等於0和1 進行分庫

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="sharding-by-sex">
		<rule>
			<columns>sex</columns>
			<algorithm>hash-int</algorithm>
		</rule>
	</tableRule>
	
	
	<!-- 
	   分片列舉
		首先所有的資料節點 配置的索引從 0 開始  如果有三臺 分別 是 0-1-2
		hash-int表示int型別列舉值 被放到哪個資料節點 
		  比如  資料庫欄位 sex 0表示男 1表示女  男性放在第二個資料節點  女性放在第一個資料節點
		 mapfile屬性指定檔案中 可以這樣配置
		 性別   datanode索引
		 0   1
		 1   0	
		 defaultNode表示 如果某些索引值 找不到對應的資料節點 資料存在於預設的該節點
	 -->
	<function name="hash-int"
		class="io.mycat.route.function.PartitionByFileMap">
		<property name="mapFile">partition-sex.txt</property>
		<property name="defaultNode">0</property>
	</function>
	
</mycat:rule>
partition-sex.txt
0=1
1=0	

server.xml配置允許客戶端登入的使用者名稱和密碼以及有許可權操作的邏輯庫(該配置server.xml預設就有)

<user name="root" defaultAccount="true">
		<property name="password">123456</property>
		<property name="schemas">TESTDB</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>
啟動 主程式 MycatStartup mycat預設啟動的mysql埠是 8066

假設本機安裝了 mysql客戶端

C:\Users\jiaozi>mysql -uroot -p123456 -P8066
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.29-mycat-1.6.5-BETA-20170424174212 MyCat Server (OpenClound
B)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB   |
+----------+
1 row in set (0.01 sec)
mysql> use TESTDB;
Database changed
mysql> show tables;
+------------------+
| Tables in TESTDB |
+------------------+
| myuser           |
+------------------+
1 row in set (0.00 sec)

mysql>
雖然連線mycat存在表 myuser但是配置schema.xml實際的主機的db1和db2中都不存在實際的物理表
mysql> select * from myuser;
ERROR 1105 (HY000): Table 'db2.myuser' doesn't exist
在mycat客戶端手工建立一下
mysql> create table myuser(
    ->   id int primary key auto_increment,
    ->   uname varchar(20),
    ->   sex int default 0
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> select * from myuser;
Empty set (0.01 sec)
可以去檢測 那四臺主機發現確實後端實際資料庫都存在了該表

插入資料測試

mysql> insert into myuser(uname,sex) values('zs',0);
Query OK, 1 row affected (0.03 sec)

mysql> insert into myuser(uname,sex) values('ls',1);
Query OK, 1 row affected (0.02 sec)

mysql> select * from myuser;
+----+-------+------+
| id | uname | sex  |
+----+-------+------+
|  2 | ls    |    1 |
|  2 | zs    |    0 |
+----+-------+------+
2 rows in set (0.02 sec)
去147物理主機上檢視 發現被拆分到不同的分片db1和db2上 但是存在一個問題就是 id是重複的 要解決這個問題 必須使用全域性鍵
MariaDB [db1]> select * from db1.myuser;
+----+-------+------+
| id | uname | sex  |
+----+-------+------+
|  2 | ls    |    1 |
+----+-------+------+
1 row in set (0.00 sec)

MariaDB [db1]> select * from db2.myuser;
+----+-------+------+
| id | uname | sex  |
+----+-------+------+
|  2 | zs    |    0 |
+----+-------+------+
1 row in set (0.00 sec)
配置全域性序列號(採用本地檔案方式 適用於單機mycat)

編輯 sequence_conf.properties  新增一個自己的序列

MYUSER_SEQ.HISIDS=
MYUSER_SEQ.MINID=1
MYUSER_SEQ.MAXID=1000000000
MYUSER_SEQ.CURID=1

重啟 mycat 清空之前的id重複資料(mycat操作)

mysql> delete from myuser;
Query OK, 2 rows affected (0.02 sec)

mysql> select * from myuser;
Empty set (0.02 sec)
server.xml中配置
<system><property name="sequnceHandlerType">0</property></system>
注:sequnceHandlerType需要配置為0,表示使用本地檔案方式。

插入資料測試(注意序列的名字是 MYCATSEQ_開頭帶上你定義的名字 否則會語法錯誤)

insert into myuser(id,uname,sex) values(next value for MYCATSEQ_MYUSER_SEQ,'zs',0);
insert into myuser(id,uname,sex) values(next value for MYCATSEQ_MYUSER_SEQ,'ls',1);