Mycat 概念與配置
阿新 • • 發佈:2020-09-14
1.1 Mycat 介紹與核心概念
下載、解壓 Mycat(有 Windows 版本,可以在本地資料庫測試):
http://dl.mycat.io/
Mycat 解壓以後有 5 個目錄:
1.2 Mycat 配置詳解
主要的配置檔案 server.xml、schema.xml、rule.xml 和具體的分片配置檔案。
坑非常多,配置錯誤會導致無法啟動,這個時候要看日誌!
注意備份,不知道什麼時候就跑不起來了……
<dataNode/>
writeType:讀寫分離的配置,決定 update、delete、insert 語句的負載
switchType:主從切換配置
連線:
- 1.1.1 基本介紹
- 1、可以當做一個 MySQL 資料庫來使用;
- 2、支援 MySQL 之外的資料庫,通過 JDBC 實現;
- 3、解決了我們提到的所有問題,多表 join、分散式事務、全域性序列號、翻頁排序;
- 4、支援 ZK 配置,帶監控 mycat-web;
- 5、2.0 正在開發中;
- 1.1.2 核心概念
概念 | 含義 |
主機 | 物理主機,一臺伺服器,一個數據庫服務,一個 3306 埠 |
物理資料庫 | 真實的資料庫,例如 146、150、151 的 gpcat 資料庫 |
物理表 | 真實的表,例如 146、150、151 的 gpcat 資料庫的 order_info 表 |
分片 | 將原來單個數據庫的資料切分後分散儲存在不同的資料庫節點 |
分片節點 | 分片以後資料儲存的節點 |
分片鍵 | 分片依據的欄位,例如 order_info 表以 id 為依據分片,id 就是分片鍵,通常是主鍵 |
分片演算法 | 分片的規則,例如隨機、取模、範圍、雜湊、列舉以及各種組合演算法 |
邏輯表 | 相對於物理表,是分片表聚合後的結果,對於客戶端來說跟真實的表沒有區別 |
邏輯資料庫 | 相對於物理資料庫,是資料節點聚合後的結果,例如 catmall |
wget http://dl.mycat.io/1.6.7.3/20190927161129/Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz tar -xzvf Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz
目錄 | 作用 |
bin | 啟動目錄 |
catlet | 空目錄 |
conf | 配置目錄 |
lib | jar 包依賴 |
logs | 日誌目錄 |
- 1.2.1 server.xml
<user name="root" defaultAccount="true"> <property name="password">123456</property> <property name="schemas">catmall</property> </user>mycat 對密碼加密:
java -cp Mycat-server-1.6.7.3-release.jar io.mycat.util.DecryptUtil 0:root:123456
- 1.2.2 schema.xml
<schema name="catmall" checkSQLschema="false" sqlMaxLimit="100"> <!-- 範圍分片 --> <table name="customer" primaryKey="id" dataNode="dn1,dn2,dn3" rule="rang-long-cust" /> <!-- 取模分片 --> <table name="order_info" dataNode="dn1,dn2,dn3" rule="mod-long-order" > <!-- ER 表 --> <childTable name="order_detail" primaryKey="id" joinKey="order_id" parentKey="order_id"/> </table> <!-- 全域性表 --> <table name="student" primaryKey="sid" type="global" dataNode="dn1,dn2,dn3" /> </schema>
配置 | 作用 |
primaryKey | 指定該邏輯表對應真實表的主鍵。MyCat 會快取主鍵(通過 primaryKey 屬性配置)與 具體 dataNode 的資訊。 當分片規則(rule)使用非主鍵進行分片時,那麼在使用主鍵進行查詢時,MyCat 就 會通過快取先確定記錄在哪個 dataNode 上,然後再在該 dataNode 上執行查詢。 如果沒有快取/快取並沒有命中的話,還是會發送語句給所有的 dataNode。 |
dataNode | 資料分片的節點 |
autoIncrement | 自增長(全域性序列),true 代表主鍵使用自增長策略 |
type | 全域性表:global。其他:不配置 |
<dataNode name="dn1" dataHost="host1" database="gpcat" />資料節點與物理資料庫的對應關係。 配置物理主機的資訊,readhost 是從屬於 writehost 的。
<dataHost name="host1" 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.8.146: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>balance:負載的配置,決定 select 語句的負載
值 | 作用 |
0 | 不開啟讀寫分離機制,所有讀操作都發送到當前可用的 writeHost 上。 |
1 | 所有讀操作都隨機發送到當前的 writeHost 對應的 readHost 和備用的 writeHost |
2 | 所有的讀操作都隨機發送到所有的 writeHost,readHost 上 |
3 | 所有的讀操作都只發送到 writeHost 的 readHost 上 |
值 | 作用 |
0 | 所有寫操作都發送到可用的 writeHost 上(預設第一個,第一個掛了以後發到第二個) |
1 | 所有寫操作都隨機的傳送到 writeHost |
值 | 作用 |
-1 | 表示不自動切換 |
1 | 預設值,表示自動切換 |
2 | 基於 MySQL 主從同步的狀態決定是否切換,心跳語句為 show slave status |
3 | 基於 MySQL galary cluster 的切換機制(適合叢集)(1.4.1),心跳語句為 show status like 'wsrep%'。 |
- 1.2.3 rule.xml
<tableRule name="rang-long-cust"> <rule> <columns>id</columns> <algorithm>func-rang-long-cust</algorithm> </rule> </tableRule>分片演算法:
<function name="func-rang-long-cust" class="io.mycat.route.function.AutoPartitionByLong"> <property name="mapFile">rang-long-cust.txt</property> </function分片配置:rang-long-cust.txt
10001-20000=1 0-10000=0 20001-100000=23.2.4 ZK 配置 https://www.cnblogs.com/47Gamer/p/13656317.html Mycat 也支援 ZK 配置(用於管理配置和生成全域性 ID),執行 bin 目錄下init_zk_data.sh,會自動將 zkconf 下的所有配置檔案上傳到 ZK(先拷貝到這個目錄)。
cd /usr/local/soft/mycat/conf cp *.txt *.xml *.properties zkconf/ cd /usr/local/soft/mycat/bin ./init_zk_data.sh啟用 ZK 配置: mycat/conf/myid.properties
loadZk=true zkURL=127.0.0.1:2181 clusterId=010 myid=01001 clusterSize=1 clusterNodes=mycat_gp_01 #server booster ; booster install on db same server,will reset all minCon to 2 type=server boosterDataHosts=dataHost1注意如果執行 init_zk_data.sh 指令碼報錯的話,代表未寫入成功,此時不要啟用 ZK配置並重啟,否則本地檔案會被覆蓋。 啟動時如果 loadzk=true 啟動時,會自動從 zk 下載配置檔案覆蓋本地配置。 在這種情況下如果修改配置,需要先修改 conf 目錄的配置,copy 到 zkconf,再行上傳。
- 1.2.5 啟動停止
操作 | 命令 |
啟動 | ./mycat start |
停止 | ./mycat stop |
重啟 | ./mycat restart |
檢視狀態 | ./mycat status |
前臺執行 | ./mycat console |
mysql -uroot -p123456 -h 192.168.8.151 -P8066 catmall1.3 Mycat 分片驗證 explain 可以用來看路由結果 在三個資料庫中建表
CREATE TABLE `customer` ( `id` INT (11) DEFAULT NULL, `name` VARCHAR (255) DEFAULT NULL ) ENGINE = INNODB DEFAULT CHARSET = utf8;
CREATE TABLE `order_info` ( `order_id` INT (11) NOT NULL COMMENT '訂單 ID', `uid` INT (11) DEFAULT NULL COMMENT '使用者 ID', `nums` INT (11) DEFAULT NULL COMMENT '商品數量', `state` INT (2) DEFAULT NULL COMMENT '訂單狀態', `create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '建立時間', `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間', PRIMARY KEY (`order_id`) ) ENGINE = INNODB DEFAULT CHARSET = utf8;
CREATE TABLE `order_detail` ( `order_id` INT (11) NOT NULL COMMENT '訂單號', `id` INT (11) NOT NULL COMMENT '訂單詳情', `goods_id` INT (11) DEFAULT NULL COMMENT '貨品 ID', `price` DECIMAL (10, 2) DEFAULT NULL COMMENT '價格', `is_pay` INT (2) DEFAULT NULL COMMENT '支付狀態', `is_ship` INT (2) DEFAULT NULL COMMENT '是否發貨', `status` INT (2) DEFAULT NULL COMMENT '訂單詳情狀態', PRIMARY KEY (`order_id`, `id`) ) ENGINE = INNODB DEFAULT CHARSET = utf8;
CREATE TABLE `student` ( `sid` INT (8) NOT NULL AUTO_INCREMENT, `name` VARCHAR (255) DEFAULT NULL, `qq` VARCHAR (255) DEFAULT NULL, PRIMARY KEY (`sid`) ) ENGINE = INNODB DEFAULT CHARSET = utf8;schema.xml
<table name="customer" dataNode="dn1,dn2,dn3" rule="rang-long-cust" primaryKey="id" /> <table name="order_info" dataNode="dn1,dn2,dn3" rule="mod-long-order"> <childTable name="order_detail" joinKey="order_id" parentKey="order_id" primaryKey="id" /> </table> <table name="student" dataNode="dn1,dn2,dn3" primaryKey="sid" type="global" />資料節點配置
<dataNode name="dn1" dataHost="host1" database="gpcat" /> <dataNode name="dn2" dataHost="host2" database="gpcat" /> <dataNode name="dn3" dataHost="host3" database="gpcat" /> <dataHost balance="0" maxCon="1000" minCon="10" name="host1" writeType="0" switchType="1" slaveThreshold="100" dbType="mysql" dbDriver="native"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1" url="192.168.8.146:3306" password="123456" user="root" /> </dataHost> <dataHost balance="0" maxCon="1000" minCon="10" name="host2" writeType="0" switchType="1" slaveThreshold="100" dbType="mysql" dbDriver="native"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1" url="192.168.8.150:3306" password="123456" user="root" /> </dataHost> <dataHost balance="0" maxCon="1000" minCon="10" name="host3" writeType="0" switchType="1" slaveThreshold="100" dbType="mysql" dbDriver="native"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1" url="192.168.8.151:3306" password="123456" user="root" /> </dataHost>schema——rule.xml——分片配置。
- 1.3.1 範圍分片
<tableRule name="rang-long-cust"> <rule> <columns>id</columns> <algorithm>rang-long-cust</algorithm> </rule> </tableRule>
<function name="rang-long-cust" class="io.mycat.route.function.AutoPartitionByLong"> <property name="mapFile">rang-long-cust.txt</property> </function>customer:
INSERT INTO `customer` (`id`, `name`) VALUES (6666, '趙先生'); INSERT INTO `customer` (`id`, `name`) VALUES (7777, '錢先生'); INSERT INTO `customer` (`id`, `name`) VALUES (16666, '孫先生'); INSERT INTO `customer` (`id`, `name`) VALUES (17777, '李先生'); INSERT INTO `customer` (`id`, `name`) VALUES (26666, '周先生'); INSERT INTO `customer` (`id`, `name`) VALUES (27777, '吳先生');
- 1.3.2 取模分片(ER 表)
<tableRule name="mod-long-order"> <rule> <columns>order_id</columns> <algorithm>mod-long</algorithm> </rule> </tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod"> <property name="count">3</property> </function>
INSERT INTO `order_info` (`order_id`, `uid`, `nums`, `state`,`create_time`, `update_time`) VALUES (1, 1000001, 1, 2, '2019-9-23 14:35:37', '2019-9-23 14:35:37'); INSERT INTO `order_info` (`order_id`,`uid`, `nums`, `state`, `create_time`, `update_time`) VALUES (2,1000002, 1, 2, '2019-9-24 14:35:37', '2019-9-24 14:35:37'); INSERT INTO `order_info` (`order_id`, `uid`, `nums`, `state`, `create_time`,`update_time`) VALUES (3, 1000003, 3, 1, '2019-9-25 11:35:49','2019-9-25 11:35:49');order_detail:
INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`,`is_pay`, `is_ship`, `status`) VALUES (3, 20180001, 85114752, 19.99, 1,1, 1); INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`,`price`, `is_pay`, `is_ship`, `status`) VALUES (1, 20180002, 25411251,1280.00, 1, 1, 0); INSERT INTO `order_detail` (`order_id`, `id`,`goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (1, 20180003,62145412, 288.00, 1, 1, 2); INSERT INTO `order_detail` (`order_id`,`id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (2,20180004, 21456985, 399.00, 1, 1, 2); INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`, `is_ship`, `status`) VALUES (2, 20180005, 21457452, 1680.00, 1, 1, 2); INSERT INTO `order_detail` (`order_id`, `id`, `goods_id`, `price`, `is_pay`,`is_ship`, `status`) VALUES (2, 20180006, 65214789, 9999.00, 1, 1, 3);
- 1.3.3 全域性表
<table name="student" dataNode="dn1,dn2,dn3" primaryKey="sid" type="global"/>
INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (1, '黑白','166669999'); INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (2, 'AV哥', '466669999'); INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (3, '最強菜鳥', '368828888'); INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (4, '載入中', '655556666'); INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (5, '貓老公', '265286999'); INSERT INTO `student` (`sid`, `name`, `qq`) VALUES (6, '一個人的精彩', '516895555');1.4 Mycat 全域性 ID Mycat 全域性序列實現方式主要有 4 種:本地檔案方式、資料庫方式、本地時間戳演算法、ZK。也可以自定義業務序列。 注意獲取全域性 ID 的字首都是:MYCATSEQ_
- 1.4.1 檔案方式
<property name="sequnceHandlerType">0</property>檔案方式,配置 conf/sequence_conf.properties:
CUSTOMER.HISIDS= CUSTOMER.MINID=10000001 CUSTOMER.MAXID=20000000 CUSTOMER.CURID=10000001語法:select next value for MYCATSEQ_CUSTOMER
INSERT INTO `customer` (`id`, `name`) VALUES (next value for MYCATSEQ_CUSTOMER, 'qingshan');優點:本地載入,讀取速度較快。 缺點:當 Mycat 重新發布後,配置檔案中的 sequence 需要替換。Mycat 不能做叢集部署。
- 1.4.2 資料庫方式
<property name="sequnceHandlerType">1</property>配置: sequence_db_conf.properties 把這張表建立在 146 上,所以是 dn1
#sequence stored in datanode GLOBAL=dn1 CUSTOMER=dn1在第一個資料庫節點上建立 MYCAT_SEQUENCE 表:
DROP TABLE IF EXISTS MYCAT_SEQUENCE; CREATE TABLE MYCAT_SEQUENCE ( NAME VARCHAR (50) NOT NULL, current_value INT NOT NULL, increment INT NOT NULL DEFAULT 1, remark VARCHAR (100), PRIMARY KEY (NAME) ) ENGINE = INNODB;注:可以在 schema.xml 配置檔案中配置這張表,供外部訪問。
<table name="mycat_sequence" dataNode="dn1" autoIncrement="true" primaryKey="id"></table>建立儲存過程——獲取當前 sequence 的值
DROP FUNCTION IF EXISTS `mycat_seq_currval`; DELIMITER; ; CREATE DEFINER = `root`@`%` FUNCTION `mycat_seq_currval` (seq_name VARCHAR(50)) RETURNS VARCHAR (64) CHARSET latin1 DETERMINISTIC BEGIN DECLARE retval VARCHAR (64); SET retval = "-999999999,null"; SELECT concat( CAST(current_value AS CHAR), ",", CAST(increment AS CHAR) ) INTO retval FROM MYCAT_SEQUENCE WHERE NAME = seq_name; RETURN retval; END; ; DELIMITER;建立儲存過程,獲取下一個 sequence:
DROP FUNCTION IF EXISTS `mycat_seq_nextval`; DELIMITER; ; CREATE DEFINER = `root`@`%` FUNCTION `mycat_seq_nextval` (seq_name VARCHAR(50)) RETURNS VARCHAR (64) CHARSET latin1 DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE NAME = seq_name; RETURN mycat_seq_currval (seq_name); END; ; DELIMITER;建立儲存過程,設定 sequence:
DROP FUNCTION IF EXISTS `mycat_seq_setval`; DELIMITER; ; CREATE DEFINER = `root`@`%` FUNCTION `mycat_seq_setval` ( seq_name VARCHAR (50), VALUE INTEGER ) RETURNS VARCHAR (64) CHARSET latin1 DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = VALUE WHERE NAME = seq_name; RETURN mycat_seq_currval (seq_name); END; ; DELIMITER;插入記錄:
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment,remark) VALUES ('GLOBAL', 1, 100,''); INSERT INTO MYCAT_SEQUENCE(name,current_value,increment,remark) VALUES ('ORDERS', 1, 100,'訂單表使用');測試:
select next value for MYCATSEQ_ORDERS
- 1.4.3 本地時間戳方式
<property name="sequnceHandlerType">2</property>配置檔案 sequence_time_conf.properties:
#sequence depend on TIME WORKID=01 DATAACENTERID=01驗證:select next value for MYCATSEQ_GLOBAL
- 1.4.4 ZK 方式
<property name="sequnceHandlerType">3</property>配置檔案:sequence_distributed_conf.properties:
# 代表使用 zk INSTANCEID=ZK # 與 myid.properties 中的 CLUSTERID 設定的值相同 CLUSTERID=010複製配置檔案
cd /usr/local/soft/mycat/conf cp *.txt *.xml *.properties zkconf/ chown -R zkconf/ cd /usr/local/soft/mycat/bin ./init_zk_data.sh驗證:select next value for MYCATSEQ_GLOBAL
- 1.4.5 使用