Dubbo學習系列之十三(Mycat資料庫代理)
軟體界有隻貓,不用我說,各位看官肯定知道是哪隻,那就是大名鼎鼎的Tomcat,現在又來了一隻貓,據說是位東方萌妹子,暫且認作Tom貓的表妹,本來叫OpencloudDB,後又改名為Mycat,或許Cat更親切?那現在就來認識下這隻小貓吧。
資料庫的核心地位就不說了,但現在的問題是,各種RDB,各種NoSQL交織,又是分散式、多租戶的場景下,心裡有沒有十足的把握能穩住如此局面呢。有需求,就有市場!自然,相應的技術也應運而生,Mycat作為一款DB中介軟體,可以作為應用和DB間的“橋樑”,讓後臺DB的複雜組成對應用透明,處理分庫分表、多租戶架構和大資料實時查詢等都不在話下!
工具:
Idea201902/JDK11/ZK3.5.5/Gradle5.4.1/RabbitMQ3.7.13/Lombok0.26/Erlang21.2/RocketMQ4.5.2/Sentinel1.6.3/SpringBoot2.1.6/RHEL7.6/VMware15.0.4/Mysql8.0.17/Mycat1.6.7.3/MysqlWorkbench6.3
難度: 新手--戰士--老兵--大師
目標:
1.Linux下使用Mycat連線Mysql叢集(兩主一從),讀寫分離式應用
步驟:
1.建立Mysql叢集,步驟參考往期文章(Linux下Mysql叢集使用)。
2.下載Mycat,放到Linux中/usr/mycat下,記得先建立此目錄。
3.進入該目錄,解壓:
[root@localhost mycat]# tar -zxvf Mycat-server-1.6.7.3-release-20190828135747-linux.tar.gz
4.可以看到目錄結構如下,兩貓確實略像:
- bin—Mycat的各種管理命令;
- catlet—擴充套件功能;
- conf—配置資訊,這個也是本期重點使用的;
- lib—jar包庫,因為Mycat是Java開發的;
- logs—日誌檔案;
5.Mycat融合應用的架構,即本次目標架構:
如果需要做擴充套件高可用,即可變成這樣的:
就是這麼簡單!
6.其實Mycat從應用上講,就是做配置,原始碼可按喜好研究,據說很複雜!
主要是三個檔案核心檔案rule.xml、schema.xml、server.xml的配置:
- server.xml:Mycat的配置檔案,可以將Mycat視為DBServer的代理,
- schema.xml:邏輯表與物理DB/分片分庫的對映配置,
- rule.xml:分庫分表規則,
7.挨個看看長啥樣,引數的含義註釋上基本有說明,這裡都是全域性配置引數:
-
<system>
中設定Mycat全域性屬性; -
<firewall>
設定黑白名單; -
<user>
設定使用者登入Mycat的賬號資訊; -
<privileges>
單獨設定表的DML許可權;
server.xml原版樣例:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mycat:server SYSTEM "server.dtd"> 3 <mycat:server xmlns:mycat="http://io.mycat/"> 4 <system> 5 <property name="nonePasswordLogin">0</property> <!-- 0為需要密碼登陸、1為不需要密碼登陸 ,預設為0,設定為1則需要指定預設賬戶--> 6 <property name="useHandshakeV10">1</property> 7 <property name="useSqlStat">0</property> <!-- 1為開啟實時統計、0為關閉 --> 8 <property name="useGlobleTableCheck">0</property> <!-- 1為開啟全加班一致性檢測、0為關閉 --> 9 <property name="sqlExecuteTimeout">300</property> <!-- SQL 執行超時 單位:秒--> 10 <property name="sequnceHandlerType">2</property> 11 <!--<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>--> 12 <!--必須帶有MYCATSEQ_或者 mycatseq_進入序列匹配流程 注意MYCATSEQ_有空格的情況--> 13 <property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property> 14 <property name="subqueryRelationshipCheck">false</property> <!-- 子查詢中存在關聯查詢的情況下,檢查關聯欄位中是否有分片欄位 .預設 false --> 15 <!-- <property name="useCompression">1</property>--> <!--1為開啟mysql壓縮協議--> 16 <!-- <property name="fakeMySQLVersion">5.6.20</property>--> <!--設定模擬的MySQL版本號--> 17 <!-- <property name="processorBufferChunk">40960</property> --> 18 <!-- 19 <property name="processors">1</property> 20 <property name="processorExecutor">32</property> 21 --> 22 <!--預設為type 0: DirectByteBufferPool | type 1 ByteBufferArena | type 2 NettyBufferPool --> 23 <property name="processorBufferPoolType">0</property> 24 <!--預設是65535 64K 用於sql解析時最大文字長度 --> 25 <!--<property name="maxStringLiteralLength">65535</property>--> 26 <!--<property name="sequnceHandlerType">0</property>--> 27 <!--<property name="backSocketNoDelay">1</property>--> 28 <!--<property name="frontSocketNoDelay">1</property>--> 29 <!--<property name="processorExecutor">16</property>--> 30 <!-- 31 <property name="serverPort">8066</property> <property name="managerPort">9066</property> 32 <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property> 33 <property name="dataNodeIdleCheckPeriod">300000</property> 5 * 60 * 1000L; //連線空閒檢查 34 <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> --> 35 <!--分散式事務開關,0為不過濾分散式事務,1為過濾分散式事務(如果分散式事務內只涉及全域性表,則不過濾),2為不過濾分散式事務,但是記錄分散式事務日誌--> 36 <property name="handleDistributedTransactions">0</property> 37 <!--off heap for merge/order/group/limit 1開啟 0關閉--> 38 <property name="useOffHeapForMerge">0</property> 39 <!--單位為m--> 40 <property name="memoryPageSize">64k</property> 41 <!--單位為k--> 42 <property name="spillsFileBufferSize">1k</property> 43 <property name="useStreamOutput">0</property> 44 <!--單位為m--> 45 <property name="systemReserveMemorySize">384m</property> 46 <!--是否採用zookeeper協調切換 --> 47 <property name="useZKSwitch">false</property> 48 <!-- XA Recovery Log日誌路徑 --> 49 <!--<property name="XARecoveryLogBaseDir">./</property>--> 50 <!-- XA Recovery Log日誌名稱 --> 51 <!--<property name="XARecoveryLogBaseName">tmlog</property>--> 52 <!--如果為 true的話 嚴格遵守隔離級別,不會在僅僅只有select語句的時候在事務中切換連線--> 53 <property name="strictTxIsolation">false</property> 54 <property name="useZKSwitch">true</property> 55 </system> 56 57 <!-- 全域性SQL防火牆設定 --> 58 <!--白名單可以使用萬用字元%或著*--> 59 <!--例如<host host="127.0.0.*" user="root"/>--> 60 <!--例如<host host="127.0.*" user="root"/>--> 61 <!--例如<host host="127.*" user="root"/>--> 62 <!--例如<host host="1*7.*" user="root"/>--> 63 <!--這些配置情況下對於127.0.0.1都能以root賬戶登入--> 64 <!-- 65 <firewall> 66 <whitehost> 67 <host host="1*7.0.0.*" user="root"/> 68 </whitehost> 69 <blacklist check="false"> 70 </blacklist> 71 </firewall> 72 --> 73 <user name="root" defaultAccount="true"> 74 <property name="password">123456</property> 75 <property name="schemas">TESTDB</property> 76 <!-- 表級 DML 許可權設定 --> 77 <!-- 78 <privileges check="false"> 79 <schema name="TESTDB" dml="0110" > 80 <table name="tb01" dml="0000"></table> 81 <table name="tb02" dml="1111"></table> 82 </schema> 83 </privileges> 84 --> 85 </user> 86 <user name="user"> 87 <property name="password">user</property> 88 <property name="schemas">TESTDB</property> 89 <property name="readOnly">true</property> 90 </user> 91 </mycat:server>
8.schema.xml,配置schema下各個table的分片/分庫,以及物理DB:
-
<schema>+<table>
租戶和子表配置, -
<dataNode>
分片, -
<dataHost>
物理DB,
原版樣例:
1 <?xml version="1.0"?> 2 <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> 3 <mycat:schema xmlns:mycat="http://io.mycat/"> 4 <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100"> 5 <!-- auto sharding by id (long) --> 6 <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" /> 7 <!-- global table is auto cloned to all defined data nodes ,so can join 8 with any table whose sharding node is in the same data node --> 9 <table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" /> 10 <table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" /> 11 <!-- random sharding using mod sharind rule --> 12 <table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3" 13 rule="mod-long" /> 14 <!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global" 15 needAddLimit="false"/> <table name="worker" primaryKey="ID" dataNode="jdbc_dn1,jdbc_dn2,jdbc_dn3" 16 rule="mod-long" /> --> 17 <table name="employee" primaryKey="ID" dataNode="dn1,dn2" 18 rule="sharding-by-intfile" /> 19 <table name="customer" primaryKey="ID" dataNode="dn1,dn2" 20 rule="sharding-by-intfile"> 21 <childTable name="orders" primaryKey="ID" joinKey="customer_id" 22 parentKey="id"> 23 <childTable name="order_items" joinKey="order_id" 24 parentKey="id" /> 25 </childTable> 26 <childTable name="customer_addr" primaryKey="ID" joinKey="customer_id" 27 parentKey="id" /> 28 </table> 29 <!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate" 30 /> --> 31 </schema> 32 <!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743" 33 /> --> 34 <dataNode name="dn1" dataHost="localhost1" database="db1" /> 35 <dataNode name="dn2" dataHost="localhost1" database="db2" /> 36 <dataNode name="dn3" dataHost="localhost1" database="db3" /> 37 <!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" /> 38 <dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" /> 39 <dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" /> 40 <dataNode name="jdbc_dn3" dataHost="jdbchost" database="db3" /> --> 41 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" 42 writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> 43 <heartbeat>select user()</heartbeat> 44 <!-- can have multi write hosts --> 45 <writeHost host="hostM1" url="localhost:3306" user="root" 46 password="123456"> 47 <!-- can have multi read hosts --> 48 <readHost host="hostS2" url="192.168.1.200:3306" user="root" password="xxx" /> 49 </writeHost> 50 <writeHost host="hostS1" url="localhost:3316" user="root" 51 password="123456" /> 52 <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> --> 53 </dataHost> 54 <!-- 55 <dataHost name="sequoiadb1" maxCon="1000" minCon="1" balance="0" dbType="sequoiadb" dbDriver="jdbc"> 56 <heartbeat> </heartbeat> 57 <writeHost host="hostM1" url="sequoiadb://1426587161.dbaas.sequoialab.net:11920/SAMPLE" user="jifeng" password="jifeng"></writeHost> 58 </dataHost> 59 60 <dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="oracle" dbDriver="jdbc"> <heartbeat>select 1 from dual</heartbeat> 61 <connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql> 62 <writeHost host="hostM1" url="jdbc:oracle:thin:@127.0.0.1:1521:nange" user="base" password="123456" > </writeHost> </dataHost> 63 64 <dataHost name="jdbchost" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="mongodb" dbDriver="jdbc"> 65 <heartbeat>select user()</heartbeat> 66 <writeHost host="hostM" url="mongodb://192.168.0.99/test" user="admin" password="123456" ></writeHost> </dataHost> 67 68 <dataHost name="sparksql" maxCon="1000" minCon="1" balance="0" dbType="spark" dbDriver="jdbc"> 69 <heartbeat> </heartbeat> 70 <writeHost host="hostM1" url="jdbc:hive2://feng01:10000" user="jifeng" password="jifeng"></writeHost> </dataHost> --> 71 72 <!-- <dataHost name="jdbchost" maxCon="1000" minCon="10" balance="0" dbType="mysql" 73 dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1" 74 url="jdbc:mysql://localhost:3306" user="root" password="123456"> </writeHost> 75 </dataHost> --> 76 </mycat:schema>
9.rule.xml詳細描述表的分片規則,格式如下:
1 <tableRule name="分片規則名"> 2 <rule> 3 <columns>分片的列</columns> 4 <algorithm>分片演算法名</algorithm> 5 </rule> 6 </tableRule> 7 <function name="分片演算法名" class="演算法實現類"> 8 <property name="演算法引數">引數值</property> 9 </function>
原版樣例:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mycat:rule SYSTEM "rule.dtd"> 3 <mycat:rule xmlns:mycat="http://io.mycat/"> 4 <tableRule name="rule1"> 5 <rule> 6 <columns>id</columns> 7 <algorithm>func1</algorithm> 8 </rule> 9 </tableRule> 10 <tableRule name="rule2"> 11 <rule> 12 <columns>user_id</columns> 13 <algorithm>func1</algorithm> 14 </rule> 15 </tableRule> 16 <tableRule name="sharding-by-intfile"> 17 <rule> 18 <columns>sharding_id</columns> 19 <algorithm>hash-int</algorithm> 20 </rule> 21 </tableRule> 22 <tableRule name="auto-sharding-long"> 23 <rule> 24 <columns>id</columns> 25 <algorithm>rang-long</algorithm> 26 </rule> 27 </tableRule> 28 <tableRule name="mod-long"> 29 <rule> 30 <columns>id</columns> 31 <algorithm>mod-long</algorithm> 32 </rule> 33 </tableRule> 34 <tableRule name="sharding-by-murmur"> 35 <rule> 36 <columns>id</columns> 37 <algorithm>murmur</algorithm> 38 </rule> 39 </tableRule> 40 <tableRule name="crc32slot"> 41 <rule> 42 <columns>id</columns> 43 <algorithm>crc32slot</algorithm> 44 </rule> 45 </tableRule> 46 <tableRule name="sharding-by-month"> 47 <rule> 48 <columns>create_time</columns> 49 <algorithm>partbymonth</algorithm> 50 </rule> 51 </tableRule> 52 <tableRule name="latest-month-calldate"> 53 <rule> 54 <columns>calldate</columns> 55 <algorithm>latestMonth</algorithm> 56 </rule> 57 </tableRule> 58 <tableRule name="auto-sharding-rang-mod"> 59 <rule> 60 <columns>id</columns> 61 <algorithm>rang-mod</algorithm> 62 </rule> 63 </tableRule> 64 <tableRule name="jch"> 65 <rule> 66 <columns>id</columns> 67 <algorithm>jump-consistent-hash</algorithm> 68 </rule> 69 </tableRule> 70 <function name="murmur" 71 class="io.mycat.route.function.PartitionByMurmurHash"> 72 <property name="seed">0</property><!-- 預設是0 --> 73 <property name="count">2</property><!-- 要分片的資料庫節點數量,必須指定,否則沒法分片 --> 74 <property name="virtualBucketTimes">160</property><!-- 一個實際的資料庫節點被對映為這麼多虛擬節點,預設是160倍,也就是虛擬節點數是物理節點數的160倍 --> 75 <!-- <property name="weightMapFile">weightMapFile</property> 節點的權重,沒有指定權重的節點預設是1。以properties檔案的格式填寫,以從0開始到count-1的整數值也就是節點索引為key,以節點權重值為值。所有權重值必須是正整數,否則以1代替 --> 76 <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property> 77 用於測試時觀察各物理節點與虛擬節點的分佈情況,如果指定了這個屬性,會把虛擬節點的murmur hash值與物理節點的對映按行輸出到這個檔案,沒有預設值,如果不指定,就不會輸出任何東西 --> 78 </function> 79 <function name="crc32slot" 80 class="io.mycat.route.function.PartitionByCRC32PreSlot"> 81 </function> 82 <function name="hash-int" 83 class="io.mycat.route.function.PartitionByFileMap"> 84 <property name="mapFile">partition-hash-int.txt</property> 85 </function> 86 <function name="rang-long" 87 class="io.mycat.route.function.AutoPartitionByLong"> 88 <property name="mapFile">autopartition-long.txt</property> 89 </function> 90 <function name="mod-long" class="io.mycat.route.function.PartitionByMod"> 91 <!-- how many data nodes --> 92 <property name="count">3</property> 93 </function> 94 95 <function name="func1" class="io.mycat.route.function.PartitionByLong"> 96 <property name="partitionCount">8</property> 97 <property name="partitionLength">128</property> 98 </function> 99 <function name="latestMonth" 100 class="io.mycat.route.function.LatestMonthPartion"> 101 <property name="splitOneDay">24</property> 102 </function> 103 <function name="partbymonth" 104 class="io.mycat.route.function.PartitionByMonth"> 105 <property name="dateFormat">yyyy-MM-dd</property> 106 <property name="sBeginDate">2015-01-01</property> 107 </function> 108 <function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod"> 109 <property name="mapFile">partition-range-mod.txt</property> 110 </function> 111 <function name="jump-consistent-hash" class="io.mycat.route.function.PartitionByJumpConsistentHash"> 112 <property name="totalBuckets">3</property> 113 </function> 114 </mycat:rule>
部分常用的分片規則演算法說明:
-
PartitionByMurmurHash(一致性hash):將物理節點虛擬並對映為一個“一致性hash環”;
-
PartitionByCRC32PreSlot(crc32slot 演算法):crc32(key)%102400=slot,slot 按照範圍均勻分佈在 dataNode 上;
-
LatestMonthPartion(單月小時拆分):單月內按照小時拆分,最小粒度是小時,可以一天最多 24 個分片,最少 1 個分片,一個月完後下月 從頭開始迴圈;
-
PartitionByMonth(自然月):按自然月分片;
-
PartitionByRangeMod(範圍求模):先進行範圍分片計算出分片組,組內再求模;
-
PartitionByJumpConsistentHash(一致性hash):另一種一致性hash演算法;
-
PartitionByFileMap(列舉):通過在配置檔案中配置可能的列舉 id,自己配置分片,本規則適用於特定的場景,比如有些業務需要按照省份或區縣來做儲存,而全國省份區縣是固定的;
-
PartitionByLong(固定分片 hash 演算法):取 id 的二進位制低 10 位取模運算,即( id 二進位制) &1111111111,partitionCount分片個數,partitionLength分片長度,預設這兩個引數的向量積為1024;
-
AutoPartitionByLong(範圍約定):按照提前規劃好分片欄位範圍計算屬於哪個分片,start <= range <= end;
-
PartitionByMod(求模):即根據 id 進行十進位制求模預算,相比固定分片 hash,此種在批量插入時可能存在批量插入單事務插入多資料分片,增大事務一致性難度;
-
PartitionByDate(按天分片):即根據指定的格式,起止日期,按日期劃分,如果配置了 sEndDate 則代表資料達到了這個日期的分片後後迴圈從開始分片插入;
10.情況一:如果DB是一主一從
:需注意這裡的主從複製由Mysql實現,Mycat不負責資料複製功能
。只需配置server.xml和schema.xml即可: 本次server.xml例項:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mycat:server SYSTEM "server.dtd"> 3 <mycat:server xmlns:mycat="http://io.mycat/"> 4 <system> 5 <property name="nonePasswordLogin">0</property> 6 <property name="useHandshakeV10">1</property> 7 <property name="useSqlStat">0</property> 8 <property name="useGlobleTableCheck">0</property> 9 <property name="sqlExecuteTimeout">300</property> 10 <property name="sequnceHandlerType">2</property> 11 <property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property> 12 <property name="subqueryRelationshipCheck">false</property> 13 <property name="processorBufferPoolType">0</property> 14 <property name="handleDistributedTransactions">0</property> 15 <property name="useOffHeapForMerge">0</property> 16 <property name="memoryPageSize">64k</property> 17 <property name="spillsFileBufferSize">1k</property> 18 <property name="useStreamOutput">0</property> 19 <property name="systemReserveMemorySize">384m</property> 20 <property name="useZKSwitch">false</property> 21 <property name="strictTxIsolation">false</property> 22 <property name="useZKSwitch">true</property> 23 </system> 24 <user name="mycat" defaultAccount="true"> 25 <property name="password">12345678</property> 26 <property name="schemas">dubbo_db</property> 27 </user> 28 </mycat:server>
schema.xml示例:
1 <?xml version="1.0"?> 2 <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> 3 <!-- 資料庫配置,與server.xml中的資料庫對應 --> 4 <mycat:schema xmlns:mycat="http://io.mycat/"> 5 <schema name="dubbo_db" checkSQLschema="true" sqlMaxLimit="100"> 6 <table name="dubbo_delivery" primaryKey="ID" dataNode="dn1"/> 7 <table name="dubbo_finance" primaryKey="ID" dataNode="dn1 "/> 8 <table name="dubbo_item" primaryKey="ID" dataNode="dn1 " /> 9 <table name="dubbo_order" primaryKey="ID" dataNode="dn1"/> 10 <table name="dubbo_order_detail" primaryKey="ID" dataNode="dn1 "/> 11 <table name="dubbo_stock" primaryKey="ID" dataNode="dn1 " /> 12 </schema> 13 <!-- 分片配置 --> 14 <dataNode name="dn1" dataHost="localhost1" database="dubbo_db" /> 15 <!-- 物理資料庫配置 --> 16 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" 17 writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> 18 <heartbeat>select user()</heartbeat> 19 <writeHost host="hostM1" url="192.168.1.204:3306" user="root" password="abcd@1234"> 20 <readHost host="hostS2" url="192.168.1.205:3306" user="root" password="abcd@1234" /> 21 </writeHost> 22 </dataHost> 23 </mycat:schema>
11.情況二,即本期目標架構,DB是兩主一從:server.xml不變, 本次schema.xml例項:
1 <?xml version="1.0"?> 2 <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> 3 <!-- 資料庫配置,與server.xml中的資料庫對應 --> 4 <mycat:schema xmlns:mycat="http://io.mycat/"> 5 <schema name="dubbo_db" checkSQLschema="true" sqlMaxLimit="100"> 6 <table name="dubbo_delivery" primaryKey="ID" dataNode="dn1"/> 7 <table name="dubbo_finance" primaryKey="ID" dataNode="dn1,dn2" rule="rule1"/> 8 <table name="dubbo_item" primaryKey="ID" dataNode="dn1,dn2" rule="rule2"/> 9 <table name="dubbo_order" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-murmur"/> 10 <table name="dubbo_order_detail" primaryKey="ID" dataNode="dn1,dn2" rule="sharding-by-month"/> 11 <table name="dubbo_stock" primaryKey="ID" dataNode="dn1" /> 12 </schema> 13 <!-- 分片配置 --> 14 <dataNode name="dn1" dataHost="localhost1" database="dubbo_db" /> 15 <dataNode name="dn2" dataHost="localhost2" database="dubbo_db" /> 16 <!-- 物理資料庫配置 --> 17 <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" 18 writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> 19 <heartbeat>select user()</heartbeat> 20 <writeHost host="hostM1" url="192.168.1.204:3306" user="root" password="abcd@1234"> 21 <readHost host="hostS2" url="192.168.1.205:3306" user="root" password="abcd@1234" /> 22 </writeHost> 23 </dataHost> 24 <dataHost name="localhost2" maxCon="1000" minCon="10" balance="0" 25 writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> 26 <heartbeat>select user()</heartbeat> 27 <writeHost host="hostM2" url="192.168.1.206:3306" user="root" password="abcd@1234" /> 28 </dataHost> 29 </mycat:schema>
本次rule.xml例項:只有使用了分片模式時,才需要配置rule規則,這裡寫了三種rule,其實也沒全部用上:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mycat:rule SYSTEM "rule.dtd"> 3 <mycat:rule xmlns:mycat="http://io.mycat/"> 4 <!--規則定義--> 5 <tableRule name="sharding-by-murmur"> 6 <rule> 7 <columns>id</columns> 8 <algorithm>murmur</algorithm> 9 </rule> 10 </tableRule> 11 <!--自定義規則--> 12 <tableRule name="rule1"> 13 <rule> 14 <columns>userr_id</columns> 15 <algorithm>func1</algorithm> 16 </rule> 17 </tableRule> 18 <tableRule name="rule2"> 19 <rule> 20 <columns>id</columns> 21 <algorithm>func2</algorithm> 22 </rule> 23 </tableRule> 24 <tableRule name="sharding-by-month"> 25 <rule> 26 <columns>create_time</columns> 27 <algorithm>partbymonth</algorithm> 28 </rule> 29 </tableRule> 30 <!--規則演算法實現--> 31 <function name="murmur" 32 class="io.mycat.route.function.PartitionByMurmurHash"> 33 <property name="seed">0</property><!-- 預設是0 --> 34 <property name="count">2</property><!-- 要分片的資料庫節點數量,必須指定,否則沒法分片 --> 35 <property name="virtualBucketTimes">160</property><!-- 一個實際的資料庫節點被對映為這麼多虛擬節點,預設是160倍,也就是虛擬節點數是物理節點數的160倍 --> 36 <!-- <property name="weightMapFile">weightMapFile</property> 節點的權重,沒有指定權重的節點預設是1。以properties檔案的格式填寫,以從0開始到count-1的整數值也就是節點索引為key,以節點權重值為值。所有權重值必須是正整數,否則以1代替 --> 37 <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property> 38 用於測試時觀察各物理節點與虛擬節點的分佈情況,如果指定了這個屬性,會把虛擬節點的murmur hash值與物理節點的對映按行輸出到這個檔案,沒有預設值,如果不指定,就不會輸出任何東西 --> 39 </function> 40 <function name="func1" class="io.mycat.route.function.PartitionByLong"> 41 <!--分片數量,partitionCount*partitionLength=1024--> 42 <property name="partitionCount">2</property> 43 <property name="partitionLength">512</property> 44 </function> 45 <function name="func2" class="io.mycat.route.function.PartitionByLong"> 46 <property name="partitionCount">8</property> 47 <property name="partitionLength">128</property> 48 </function> 49 <function name="partbymonth" 50 class="io.mycat.route.function.PartitionByMonth"> 51 <property name="dateFormat">yyyy-MM-dd</property> 52 <property name="sBeginDate">2015-01-01</property> 53 </function> 54 </mycat:rule>
12.測試:配置好mycat/conf/下的3個xml檔案,即配置好了Mycat與物理DB的連線,應用端連線僅需修改連線串埠為Mycat的IP+埠,賬號為server.xml中user資訊,注意:
要寫上預設schema,否則啟動應用報Mycat no chose
錯,
13.此處有坑!如果Mysql是獨立安裝在linux上,需要對遠端訪問開啟,否則訪問預設僅限本地,導致遠端連線一直報錯,以開放root
使用者遠端連線為例:
mysql> use mysql; mysql> update user set Host='%' where User='root'; mysql> quit;
再重啟mysql:
[root@localhost ~]# systemctl restart mysqld
啟動Mycat:
[root@localhost ~]# cd /usr/mycat/mycat/bin [root@localhost bin]# ./mycat start
mycat啟動成功:
如果啟動有問題,使用以下命令檢視log:
[root@localhost conf]# tail -F /usr/mycat/mycat/logs/wrapper.log [root@localhost conf]# tail -F /usr/mycat/mycat/logs/mycat.log
然後可以在window上使用如MysqlWorkbench,Navicat測試下是否連線正常,並測試下Mycat連線:
為了集中測試程式碼,我只改寫了finance模組,寫個service方法:com.biao.mall.service.DubboFinanceServiceImpl中:
1 //插入1000條資料,看data分佈 2 @Override 3 public void testMycat(){ 4 DubboFinanceEntity financeEntity = new DubboFinanceEntity(); 5 for (int i = 0; i < 1000; i++) { 6 financeEntity.setUserId(String.valueOf(i+100)); 7 financeDao.insert(financeEntity); 8 } 9 return "testMycat successfully"; 10 }
寫個controller方法跑一跑:
@RestController @RequestMapping("/finance") public class DubboFinanceController { private DubboFinanceServiceImpl financeService; @Autowired public DubboFinanceController(DubboFinanceServiceImpl financeService) { this.financeService = financeService; } @RequestMapping("/mycat") public void testMycat(){ return financeService.testMycat(); } }
啟動:ZK---> business --> finance, URI來一個!
DB情況,請看數量和ID分佈,紅色數字是IP:
這裡只測試了兩主一從和一種分片規則,其他請君自測!
13.程式碼地址:其中的day16,https://github.com/xiexiaobiao/dubbo-project.git
後記:
1.認識Mycat的關鍵特性:
- 支援Mysql原生協議,跨語言,跨平臺,跨資料庫的通用中介軟體代理;
- 基於心跳的自動故障切換,支援讀寫分離,支援MySQL主從;
- 基於Nio實現,有效管理執行緒,高併發問題;
- 支援資料的多片自動路由與聚合,支援sum,count,max等常用的聚合函式,支援跨庫分頁;
- 支援通過全域性表,ER關係的分片策略,實現了高效的單庫多表join查詢;
- 支援多租戶方案,即同DB下多schema模式;
- 支援全域性序列號,解決分散式下的主鍵生成問題;
- 分片規則豐富,外掛化開發,易於擴充套件,可自定義;
- 叢集基於ZooKeeper管理,線上升級,擴容,智慧優化,大資料處理(V2.0dev);
- 引入Mycat的無痕切換,我覺得這是最大的優勢;
2.認清Mycat的侷限性:
-
目前只支援跨庫join2個表,不支援3 表及其以上跨庫 join ;
-
Mycat並沒有根據二階段提交協議實現 XA事務,而是隻保證 prepare 階段資料一致性的弱XA事務,分散式事務場景下,強一致性無法保證;
-
分頁排序場景下,會一次查詢所有分片,再集中排序分頁,有效能瓶頸;
-
不同型別DB適配一般,如Oracle/SQLServer等,由於SQL語法差異,須做徹底的語句相容測試;
-
沒有API配置方法,只有XML方式配置,十分過時;
3.Mycat作為DB上一層的重量級中介軟體,統一了入口,實際上也破壞了分散式的定義,未能充分發揮DB層的效能,所以也有很多不看好的聲音,DB獨立使用,更能發揮靈活自由配置,直接對接應用層更為高效。
4.總結:Mycat框架的使用,需持謹慎態度,至少目前來看如此。
推薦閱讀:
-
Dubbo學習系列之十二(Quartz任務排程)
-
Linux下Mysql叢集使用
-
Dubbo學習系列之十一(Dashboard+Nacos規則推送)
-
Dubbo學習系列之十(Sentinel之限流與降級)
-
Dubbo學習系列之九(Shiro+JWT許可權管理)
-