1. 程式人生 > >mycat讀寫分離+垂直切分+水平切分+er分片+全局表 測試

mycat讀寫分離+垂直切分+水平切分+er分片+全局表 測試

mysql cal style st2 create 提交 org 方法 一起

原文http://blog.163.com/[email protected]/blog/static/172718064201683031639683/

讀寫分離:利用最基礎的mysql主從復制,事務性的查詢無法分離出去(因為會導致數據不一致),這樣就無法做到真正的讀寫分離,因為有些場景可能大部分都是事物性的讀。解決方法: galera for mysql 強一致性。 http://www.blogjava.net/amigoxie/archive/2014/12/24/421788.html

http://blog.csdn.net/benluobobo/article/details/51099607

http://blog.csdn.net/wulex/article/details/52495488 好的實例連接:http://blog.csdn.net/wulex/article/details/52495488

安裝使用過程遇到的問題: 1、mycat啟動後報錯,進程直接退出: Error: Exception thrown by the agent : java.net.MalformedURLException: Local host name unknown: java.net.UnknownHostException: ys-fs: ys-fs: Name or service not known 原因:本機要配置/etc/hosts 127.0.0.1 主機名 一、垂直切分測試: 1、schema.xml裏面加入: <schema name="weixin" checkSQLschema="false" sqlMaxLimit="100" dataNode="weixin" /> <schema name="yixin" checkSQLschema="false" sqlMaxLimit="100" dataNode="yixin" /> <schema name="sms" checkSQLschema="false" sqlMaxLimit="100" dataNode="sms" /> <dataNode name="weixin" dataHost="host0" database="weixin" /> <dataNode name="yixin" dataHost="host1" database="yixin" /> <dataNode name="sms" dataHost="host2" database="sms" /> <dataHost name="host0" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="namenode" url="192.168.168.230:3306" user="root" password="youngsun" /> </dataHost> <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hadoop1" url="192.168.168.231:3306" user="root" password="youngsun" /> </dataHost> <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hadoop2" url="192.168.168.232:3306" user="root" password="youngsun" /> </dataHost> 2、server.xml加入: <user name="test_wyh"> <property name="password">test</property> <property name="schemas">weixin,yixin,sms</property> </user> 3、遇到問題: 1)、Caused by: org.xml.sax.SAXParseException; lineNumber: 106; columnNumber: 16; The content of element type "mycat:schema" must match "(schema*,dataNode*,dataHost*)". 原因:要按照schema、datanode 、datahost的順序放,不能打亂。也就是所有schema要放一起,然後接著才能放datanode。。。。 2)、報1184錯誤,是因為沒有 把datahost主機的權限授予mycat所在主機。 <writeHost host="hadoop2" url="192.168.168.232:3306" user="root" password="youngsun" /> 這裏的 用戶要授予mycat所在主機遠程訪問權限: GRANT ALL PRIVILEGES ON *.* TO ‘root‘@‘%‘ IDENTIFIED BY ‘youngsun‘ 二、水平切分測試: 1、分別建立4個庫:user0、user1、user2、user3。我這裏4個庫建在4個獨立的主機上。 CREATE DATABASE user0 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 2、創建表結構

在user0~user2創建同樣的表結構,t_user和t_user_class_rel的建表語句參考如下:

技術分享DROP TABLE IF EXISTS `t_user_ext`;
技術分享CREATE TABLE `t_user_ext` (
技術分享 `user_id` int(11) NOT NULL COMMENT ‘用戶ID‘,
技術分享 `receive_address` varchar(256) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT ‘收貨地址‘,
技術分享 `create_time` datetime NOT NULL,
技術分享 `province_code` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
技術分享 PRIMARY KEY (`user_id`)
技術分享
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT=‘用戶信息表‘;
技術分享
技術分享DROP TABLE IF EXISTS `t_user_class_rel`;
技術分享CREATE TABLE `t_user_class_rel` (
技術分享 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT ‘id‘,
技術分享 `caller` varchar(16) CHARACTER SET utf8 NOT NULL COMMENT ‘調用方系統表示‘,
技術分享 `province_code` varchar(10) CHARACTER SET utf8 DEFAULT NULL COMMENT ‘省份編碼‘,
技術分享 `user_id` int(11) NOT NULL COMMENT ‘用戶ID‘,
技術分享 `class_id` int(11) NOT NULL COMMENT ‘班級ID‘,
技術分享 `role_type` int(11) DEFAULT NULL COMMENT ‘用戶在該班的角色(1學生2家長3教師)‘,
技術分享 `create_time` datetime NOT NULL COMMENT ‘創建時間‘,
技術分享 `modify_time` datetime DEFAULT NULL COMMENT ‘修改時間‘,
技術分享 PRIMARY KEY (`id`),
技術分享 UNIQUE KEY `idx_rel_user_class_id` (`user_id`,`class_id`,`role_type`),
技術分享 KEY `idx_rel_user_id` (`user_id`) USING BTREE,
技術分享 KEY `idx_rel_class_id` (`class_id`)
技術分享) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 3、添加schema:加了一點內容:不分表的情況測試(只對部分表進行切分。其實這種時候,沒有切分的表,應該是不需要跟已經切分過的表進行關聯,否則就會垮庫join。既然是這樣,那業務就比較獨立了,為什麽不把這部分表垂直切分出去呢?) 總結心得:1、如果某張表進行水平切分了,那麽跟他有事物關聯的表,要麽搞全局表,要麽進行er分片,不然就會導致垮庫join。而沒有關聯關系的表或者非事物關聯的表,實際上可以垂直切分出去(如果有必要)。2、dataHost可以理解成一個主機組,可以是單機,可以是主從,可以是galera 等搭建起來的集群。讀寫分離就是在這裏處理的。ha、讀寫分離等都在這裏進行配置,都是針對datahost。 <schema name="test_sharding" checkSQLschema="false" sqlMaxLimit="100">

技術分享 <!-- auto sharding by id (long) -->
技術分享 <table name="t_user" dataNode="user0,user1,user2,user3" rule="rule_wyh">
技術分享 <childTable name="t_user_class_rel" primaryKey="id" joinKey="user_id" parentKey="user_id" />
技術分享 </table>

<!-- 此處測試不分表的情況。要先在這裏配置,然後可以在mycat創建t_user_1表,也可以在user3對應的local創建表。如果這裏沒事先配置,無法在mycat建表,會報錯。這個還可以通過制定默認datanode實現,更簡單,配置方法:在shcema標簽上加上datanode --> <table name="t_user_1" dataNode="user3" >
技術分享 </table>
</schema> <dataNode name="user0" dataHost="host0" database="user0" />
<dataNode name="user1" dataHost="host1" database="user1" />
<dataNode name="user2" dataHost="host2" database="user2" />
<dataNode name="user3" dataHost="host3" database="user3" />
4、添加datahost:host3 <dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="ys-fs" url="192.168.168.238:3306" user="root" password="youngsun" /> </dataHost> 在238上授權授權: GRANT ALL PRIVILEGES ON *.* TO ‘root‘@‘%‘ IDENTIFIED BY ‘youngsun‘; flush privileges; 5、配置rule.xml文件

在schema.xml的文件內容中可看到t_user表指定的分片規則是rule1,需要在conf/rule.xml文件中設置rule1的規則為根據user_id進行分片,並按照類“org.opencloudb.route.function.PartitionByLong”的規則進行分片,即將user_id模除1024後每256內分到一個數據庫中,即模除後0~255到user0數據庫庫,256~511到user1數據庫,512~767到user2數據庫,768~1023到user3數據庫。

總結心得:普通取模算法,連續的id會路由到不同的分片。大了批量插入的事務控制難度,而固定分片hash算法根據二進制則可能會分到連續的分片,減少插入事務事務控制難度。

該文件的參考內容如下所示:

技術分享<?xml version="1.0" encoding="UTF-8"?>
技術分享<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
技術分享<mycat:rule xmlns:mycat="http://org.opencloudb/">
技術分享 <tableRule name="rule_wyh">
技術分享 <rule>
技術分享 <columns>user_id</columns>
技術分享 <algorithm>func_4p</algorithm>
技術分享 </rule>
技術分享 </tableRule>
技術分享
技術分享 <function name="func_4p" class="org.opencloudb.route.function.PartitionByLong">
技術分享 <property name="partitionCount">4</property>
技術分享 <property name="partitionLength">256</property>
技術分享 </function>
技術分享</mycat:rule> 6、配置server.xml文件

在server.xml文件中的schemas屬性中添加test_sharding的schema。修改後的文件如下所示:

技術分享<!DOCTYPE mycat:server SYSTEM "server.dtd">
技術分享<mycat:server xmlns:mycat="http://org.opencloudb/">
技術分享 <system>
技術分享 <property name="sequnceHandlerType">0</property>
技術分享 </system>
技術分享 <user name="test">
技術分享 <property name="password">test</property>
技術分享 <property name="schemas">weixin,yixin,photo,test_sharding</property>
技術分享 </user>
技術分享</mycat:server> 7、水平切分測試

重啟MyCAT,使用MySQL客戶端連接後,連接後可在test_sharding數據庫下看到t_user和t_user_class_rel表,

在MySQL客戶端連接的MyCat的test_sharding數據庫的t_user表運行如下技術分享插入語句,插入user_id=1、255、256、511、512、1023、1024、50、300、1000的數據:註意insert into 必須帶上字段名列表,不然報錯插不進去。

INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘1‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘); INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘255‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘); INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘256‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘); INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘511‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘); INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘512‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘); INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘1023‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘); INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘1024‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘); INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘50‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘); INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘300‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘); INSERT INTO t_user( user_id , receive_address , create_time , province_code ) VALUES(‘1000‘, ‘廣州市越秀區廣州大道中599號‘, ‘2014-07-17 10:53:15‘, ‘GD‘);
技術分享

而後在MyCAT的test_sharding數據庫的t_user表運行select查看記錄執行情況。進入localhost的user0~user3數據庫,查看數據是否按照之前確定的rule1的規則寫入不同的數據庫。

讀者可在test_sharding數據庫的t_user表執行update和delete等語句,並去分庫查看執行結果,可得知MyCAT對MySQL客戶端基本透明,對程序也幾乎透明,在select語句運行時,MyCAT會自行去各個分庫按照規則獲取合並結果。

接著測試按照ER關系策略分片的t_user_class_rel表是否按照user_id的分片策略,同樣user_id的數據分布在同一個user庫的t_user表和t_user_class_rel表。

在MyCAT的test_mycat數據庫的t_user_class_rel表運行如下語句:

INSERT INTO `t_user_class_rel`( `id` , `caller` , `province_code` , `user_id` , `class_id` , `role_type` , `create_time` , `modify_time`) VALUES (‘257‘, ‘eip‘, ‘GD‘, ‘2‘, ‘35‘, ‘3‘, ‘2012-08-05 17:32:13‘, ‘2013-12-27 16:07:32‘); INSERT INTO `t_user_class_rel`( `id` , `caller` , `province_code` , `user_id` , `class_id` , `role_type` , `create_time` , `modify_time`) VALUES (‘1‘, ‘eip‘, ‘GD‘, ‘257‘, ‘35‘, ‘3‘, ‘2012-08-05 17:32:13‘, ‘2013-12-27 16:07:32‘); INSERT INTO `t_user_class_rel`( `id` , `caller` , `province_code` , `user_id` , `class_id` , `role_type` , `create_time` , `modify_time`) VALUES (‘2‘, ‘eip‘, ‘GD‘, ‘513‘, ‘35‘, ‘3‘, ‘2012-08-05 17:32:13‘, ‘2013-12-27 16:07:32‘); INSERT INTO `t_user_class_rel`( `id` , `caller` , `province_code` , `user_id` , `class_id` , `role_type` , `create_time` , `modify_time`) VALUES (‘3‘, ‘eip‘, ‘GD‘, ‘769‘, ‘35‘, ‘3‘, ‘2012-08-05 17:32:13‘, ‘2013-12-27 16:07:32‘);

而後在MyCAT的test_mycat數據庫的t_user_class_rel表運行select查看記錄執行情況。進入localhost的user0~user3數據庫,查看數據是否按照之前確定的rule1的規則和ER分片策略寫入不同的數據庫。

分片join解決方案心得小結:如果一張表做分片了,其他有一張表要跟這張表做關聯,方案如下:

1、全局表(適合做的才做):非跨分片join

2、另一張表也搞分片:非跨分片join

3、share join(只能2個表join):跨分片join

4、另一張表裏join用到的字段冗余到 已經做了分片的那張表上去:不用join (該方案可用性不錯)

5、另一張表裏join用到的字段 搞成一張全局表:非跨分片join

三、讀寫分離

MyCAT的讀寫分離機制如下:

  • 事務內的SQL,全部走寫節點,除非某個select語句以註釋/*balance*/開頭
  • 自動提交的select語句會走讀節點,並在所有可用讀節點中間隨機負載均衡
  • 當某個主節點宕機,則其全部讀節點都不再被使用,因為此時,同步失敗,數據已經不是最新的,MyCAT會采用另外一個主節點所對應的全部讀節點來實現select負載均衡。
  • 當所有主節點都失敗,則為了系統高可用性,自動提交的所有select語句仍將提交到全部存活的讀節點上執行,此時系統的很多頁面還是能出來數據,只是用戶修改或提交會失敗。
231和233主從配置,233配置成讀庫。 <dataHost name="host1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hadoop1" url="192.168.168.231:3306" user="root" password="youngsun" > <readHost host="hadoop3" url="192.168.168.233:3306" user="root" password="youngsun" weight="1" /> </writeHost> </dataHost>

mycat讀寫分離+垂直切分+水平切分+er分片+全局表 測試