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


原文http://blog.163.com/bigoceanwu@126/blog/static/172718064201683031639683/

 

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

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

 

安裝使用過程遇到的問題:
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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM