Mycat 是數據庫中間件,就是介於數據庫與應用之間,進行數據處理與交互的中間服 務。由於前面講的對數據進行分片處理之后,從原有的一個庫,被切分為多個分片數據庫,所有的分片數據庫集 群構成了整個完整的數據庫存儲。
如下圖:
如上圖所表示,數據被分到多個分片數據庫后,應用如果需要讀取數據,就要需要處理多個數據源的數據。
如果沒有數據庫中間件,那么應用將直接面對分片集群,數據源切換、事務處理、數據聚合都需要應用直接處 理,原本該是專注於業務的應用,將會花大量的工作來處理分片后的問題,最重要的是每個應用處理將是完全的 重復造輪子。
所以有了數據庫中間件,應用只需要集中與業務處理,大量的通用的數據聚合,事務,數據源切換都由中間 件來處理,中間件的性能與處理能力將直接決定應用的讀寫性能,所以一款好的數據庫中間件至關重要。
第一部MyCat的環境搭建。
首先去官網下載MyCat,官網地址為:dl.mycat.io
注意必須下載發行版,也就是說帶有RELEASE字眼的就是發行版,BETA是測試版。選擇windows版本來學習即可。
我們主要關注的是MyCat的conf目錄如下圖:
我們打開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) --> <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" /> <!-- global table is auto cloned to all defined data nodes ,so can join with any table whose sharding node is in the same data node --> <table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" /> <table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" /> <!-- random sharding using mod sharind rule --> <table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3" rule="mod-long" /> <!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global" needAddLimit="false"/> <table name="worker" primaryKey="ID" dataNode="jdbc_dn1,jdbc_dn2,jdbc_dn3" rule="mod-long" /> --> <table name="employee" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-intfile" /> <table name="customer" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-intfile"> <childTable name="orders" primaryKey="ID" joinKey="customer_id" parentKey="id"> <childTable name="order_items" joinKey="order_id" parentKey="id" /> </childTable> <childTable name="customer_addr" primaryKey="ID" joinKey="customer_id" parentKey="id" /> </table> <!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate" /> --> </schema> <!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743" /> --> <dataNode name="dn1" dataHost="localhost1" database="db1" /> <dataNode name="dn2" dataHost="localhost1" database="db2" /> <dataNode name="dn3" dataHost="localhost1" database="db3" /> <!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" /> <dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" /> <dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" /> <dataNode name="jdbc_dn3" dataHost="jdbchost" 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> <!-- can have multi write hosts --> <writeHost host="hostM1" url="localhost:3306" user="root" password="123456"> <!-- can have multi read hosts --> <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" /> </writeHost> <writeHost host="hostS1" url="localhost:3316" user="root" password="123456" /> <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> --> </dataHost> <!-- <dataHost name="sequoiadb1" maxCon="1000" minCon="1" balance="0" dbType="sequoiadb" dbDriver="jdbc"> <heartbeat> </heartbeat> <writeHost host="hostM1" url="sequoiadb://1426587161.dbaas.sequoialab.net:11920/SAMPLE" user="jifeng" password="jifeng"></writeHost> </dataHost> <dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="oracle" dbDriver="jdbc"> <heartbeat>select 1 from dual</heartbeat> <connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql> <writeHost host="hostM1" url="jdbc:oracle:thin:@127.0.0.1:1521:nange" user="base" password="123456" > </writeHost> </dataHost> <dataHost name="jdbchost" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="mongodb" dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM" url="mongodb://192.168.0.99/test" user="admin" password="123456" ></writeHost> </dataHost> <dataHost name="sparksql" maxCon="1000" minCon="1" balance="0" dbType="spark" dbDriver="jdbc"> <heartbeat> </heartbeat> <writeHost host="hostM1" url="jdbc:hive2://feng01:10000" user="jifeng" password="jifeng"></writeHost> </dataHost> --> <!-- <dataHost name="jdbchost" maxCon="1000" minCon="10" balance="0" dbType="mysql" dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1" url="jdbc:mysql://localhost:3306" user="root" password="123456"> </writeHost> </dataHost> --> </mycat:schema>
schema 標簽用於定義 MyCat 實例中的邏輯庫,MyCat 可以有多個邏輯庫,每個邏輯庫都有自己的相關配 置。可以使用 schema 標簽來划分這些不同的邏輯庫。 如果不配置 schema 標簽,所有的表配置,會屬於同一個默認的邏輯庫。
對於我們開發人員來說,我們知道連接到mycat的邏輯庫,后面拖着多少個MySQL我們不管的,我們只需要連接到MyCat這個邏輯庫,對於后面的分庫分表,MyCat給我們屏蔽了分庫分表的復雜性。
table 標簽定義了 MyCat 中的邏輯表,所有需要拆分的表都需要在這個標簽中定義。
table標簽里面的子標簽childTabel表示這個表跟父table分在一起,不會被拆散,也就是前面所說的分庫分表之前,要考慮好表的關聯,不然否則就面臨跨庫Join連接問題。
如下代碼:
<table name="customer" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-intfile"> <childTable name="orders" primaryKey="ID" joinKey="customer_id" parentKey="id"> <childTable name="order_items" joinKey="order_id" parentKey="id" /> </childTable> <childTable name="customer_addr" primaryKey="ID" joinKey="customer_id" parentKey="id" /> </table>
table中的type屬性的global表示該表為全局表。即前面所提到每一個節點可以讀到這個表,這對是否在分庫分表中的join查詢很關鍵。而且這屬性表示不會進行分片,即全局表使用,每個節點都有。代碼如下:
<table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
table中的dataNode屬性表示你要分片,要分到那幾個節點上去,rule代表着分庫分表的規則。他的分片分表規則在rule.xml文件中,你可以在Table標簽的rule屬性設置復合
自己的分片分表規則,都在rule.xml中對應着如下圖:
<dataNode>標簽,標簽中的name屬性表示節點的名字。dataHost屬性表示對應MySQL的數據庫連接,database屬性表示Mysql數據庫名,代碼如下:
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataHost>標簽節點表示對應MySQL的數據庫連接對應配置,什么最大連接數,最小連接數之類的屬性。
<dataHost>標簽中的子標簽<hearbeat>表示存活檢測,
<dataHost>標簽中的子標簽<writeHost>和<readHost>表示MySQL中的讀寫分離,而<writeHost>子標簽中還有<readHost>子標簽,表示寫操作的數據庫還要承擔一部分讀庫的壓力。
代碼如下:
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="localhost:3306" user="root" password="123456"> <!-- can have multi read hosts --> <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" /> </writeHost> <writeHost host="hostS1" url="localhost:3316" user="root" password="123456" /> <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> --> </dataHost>
下面進行讀寫分離的演示:
第一步先注釋schma里面的配置如下圖:
接着在修改<dataNode>,<dataHost>節點信息,詳細信息在圖中說明。如下圖:
接着再還要修改mycat中server.xml文件,我這里沒有使用zookeeper所以要把zookeeper協調切換關閉。因為我們只是在本地玩,如下圖:
接着在繼續修改server.xml文件。如下圖:
接着就是啟動了,啟動之前要進行環境變量設置如下:
接着就是設置一起啟動參數了,在startup_newrap.bat文件中修改如下圖:
接着就是啟動了,如下:
接着就是用圖形化工具連接MyCat了。如下圖:
接着自己在圖形化界面中修改數據庫,這里就不演示了。如下:
接着mycat進行分庫分表演示:
注意一定要在每一個mysql中建立好tabel標簽對應的travelrecord表,而表中必須要有id這屬性,
如下圖:
注意一定要在每一個mysql中建立好tabel標簽對應的travelrecord表,而表中必須要有id這屬性,因為上面的分庫分表策略是根據id分的,在rule.xml中找到分表策略如下:
在根據rang-long在rule.xml找到對應的function,如下圖:
在找到autoparitition-long.txt文件,看到如下分庫分表了,如下圖:
然后在分別對應修改dataNode和dataHost標簽,如下圖:
最后進行分庫分表測試
比如490M=4900000分到第0個節點,在mycat總設置,如下圖:
接着去查看第0個節點會有一條數據分到這里,其他節點沒有。
如果使用上面的分庫分表策略不能超過范autoparitition-long.txt里面配置的范圍的。
其他的分配策略,還可以用CRC32slot策略類似於redis集群中的Slot,如下:
還可以用rang-mod求模來分,如下:
然后找partition-range-mod.txt,可以具體,如下:
其他就不演示了。