Mycat學習實戰-Mycat全局主鍵
Mycat學習實戰-Mycat全局主鍵
@(學習)[mycat, mysql]
- Mycat學習實戰-Mycat全局主鍵
1. Mycat全局主鍵介紹
2. Mycat全局主鍵方式
2.1 本地文件方式
2.2 本地時間戳方式
2.3 數據庫方式
2.4 zookeeper方式
1. Mycat全局主鍵介紹
在分庫分表的情況下,數據庫自增主鍵無法保證自增主鍵的全局唯一。
全局序列號的語法符合標準SQL規範,其格式為:next value for MYCATSEQ_XXX
MYCATSEQ_XXX
是序列號的名字,MyCAT自動創建新的序列號,免去了開發的復雜度,另外,MyCAT也提供了一個全局的序列號,名稱為:MYCATSEQ_GLOBAL
註意,MYCATSEQ_
必須大寫才能正確識別。
MyCAT溫馨提示:實踐中,建議每個表用自己的序列號,序列號的命名建議為MYCATSEQ _tableName_ID_SEQ
。
SQL中使用說明
自定義序列號的標識為:MYCATSEQ_XXX
,其中XXX
為具體定義的sequence
的名稱,應用舉例如下:
使用默認的全局sequence
:insert into tb1(id,name) values(next value for MYCATSEQ_GLOBAL,‘tb1‘);
使用自定義的 sequence
:insert into tb2(id,name) values(next value for MYCATSEQ_MY1,‘tb2‘);
獲取最新的值
select next value for MYCATSEQ_xxx
2. Mycat全局主鍵方式
Mycat提供的全局主鍵方式如下:
本地文件方式:使用服務器本地磁盤文件的方式
數據庫方式:使用數據庫的方式
本地時間戳方式:使用時間戳方式
分布式zookeeper生成ID
2.1 本地文件方式
vim conf/server.xml
<property name="sequnceHandlerType">0</property>
vim conf/sequence_conf.properties
#default global sequence GLOBAL.HISIDS= GLOBAL.MINID=10001 GLOBAL.MAXID=20000 GLOBAL.CURID=10000 # self define sequence ID_LOCAL_FILE.HISIDS= ID_LOCAL_FILE.MINID=1001 ID_LOCAL_FILE.MAXID=2000 ID_LOCAL_FILE.CURID=1000
以上配置文件中,自定義表名必須大寫書寫
HISIDS:表示使用過的歷史分段(一般
無特殊需要可不配置)
MINID :最小ID 值
MAXID :表示最大ID 值
CURID 表示當前ID 值。
當 sequence_conf.properties的配置名字與 表名一致的時候sql可以不包含ID字段(此處表名為
id_local_file
)
vim conf/schema.xml
<?xml version="1.0"?><!DOCTYPE mycat:schema SYSTEM "schema.dtd"><mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="test" checkSQLschema="false" sqlMaxLimit="100"> <table name="id_local_file" dataNode="test1" autoIncrement="true" primaryKey="id"></table> </schema> <dataNode name="test1" dataHost="testA" database="test" /> <dataHost name="testA" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select 1</heartbeat> <writeHost host="hostM1" url="192.168.33.11:3306" user="root" password="123456" /> </dataHost></mycat:schema>
實驗驗證:
[root@testA conf]# mysql -uroot -p123456 -P8066 -h 127.0.0.1 test mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 3 Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB) Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the current input statement. mysql> CREATE TABLE `id_local_file` (`id` varchar(20) NOT NULL ,`nm` varchar(60) NULL ,PRIMARY KEY (`id`)); Query OK, 0 rows affected (0.06 sec) mysql> insert into id_local_file(id,nm) values(next value for MYCATSEQ_GLOBAL,‘id_local_file‘); Query OK, 1 row affected (0.03 sec) mysql> insert into id_local_file(nm) values(‘id_local_file‘); /* 插入的sql語句裏沒有了自增ID字段 */ Query OK, 1 row affected (0.01 sec) mysql> select * from id_local_file; +-------+---------------+ | id | nm | +-------+---------------+ | 10001 | id_local_file | | 1001 | id_local_file | +-------+---------------+ 2 rows in set (0.08 sec) mysql> select next value for MYCATSEQ_GLOBAL; +-------+ | 10002 | +-------+ | 10002 | +-------+ 1 row in set (0.00 sec) mysql>
優點:本地加載,讀取速度較快,配置簡單
缺點:mycat重新發布時,seq文件需要替換,集群部署無法用此方式,路由到不同的mycat上無法保證id唯一,使mycat變成了有狀態的中間件。
2.2 本地時間戳方式
vim conf/server.xml
<property name="sequnceHandlerType">2</property>
vim conf/sequence_time_conf.properties
#sequence depend on TIME WORKID=01 DATAACENTERID=01
兩個屬性值為:0-31 任意整數
vim conf/schema.xml
<?xml version="1.0"?><!DOCTYPE mycat:schema SYSTEM "schema.dtd"><mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="test" checkSQLschema="false" sqlMaxLimit="100"> <table name="id_local_time" dataNode="test1" autoIncrement="true" primaryKey="id"></table> </schema> <dataNode name="test1" dataHost="testA" database="test" /> <dataHost name="testA" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select 1</heartbeat> <writeHost host="hostM1" url="192.168.33.11:3306" user="root" password="123456" /> </dataHost></mycat:schema>
實驗驗證:
[root@testA conf]# mysql -uroot -p123456 -P8066 -h 127.0.0.1 test mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB) Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the current input statement. mysql> CREATE TABLE `id_local_time` (`id` varchar(20) NOT NULL ,`nm` varchar(60) NULL ,PRIMARY KEY (`id`)); Query OK, 0 rows affected (0.02 sec) mysql> insert into id_local_time(id,nm) values(next value for MYCATSEQ_GLOBAL,‘id_local_time‘); Query OK, 1 row affected (0.06 sec) mysql> insert into id_local_time(nm) values(‘id_local_time‘); /* 插入的sql語句裏沒有了自增ID字段 */ Query OK, 1 row affected (0.01 sec) mysql> select * from id_local_time; +--------------------+---------------+ | id | nm | +--------------------+---------------+ | 922641363168792576 | id_local_time | | 922641424359493632 | id_local_time | +--------------------+---------------+ 2 rows in set (0.06 sec) mysql> select next value for MYCATSEQ_GLOBAL; +--------------------+ | 922641542101995520 | +--------------------+ | 922641542101995520 | +--------------------+ 1 row in set (0.00 sec)
本地時間戳計算方式
ID= 64 位二進制 (42(毫秒)+5(機器 ID)+5(業務編碼)+12(重復累加)
長度18位,因此下面提示非常重要。
註意
表字段長度必須大於等於18位
優點:不存在mycat重新發布影響seq的問題,
缺點:字段長度是18位。
2.3 數據庫方式
vim conf/server.xml
<property name="sequnceHandlerType">1</property>
vim conf/sequence_db_conf.properties
#sequence stored in datanode GLOBAL=test1 ID_DB=test1
在test1節點本地數據庫添加函數和表,以下為sql內容:
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 100, PRIMARY KEY (NAME) ) ENGINE = INNODB ;INSERT INTO mycat_sequence(name,current_value,increment) VALUES (‘GLOBAL‘, 100000, 100);DROP FUNCTION IF EXISTS `mycat_seq_currval`; DELIMITER ;;CREATE FUNCTION `mycat_seq_currval`(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8 DETERMINISTICBEGIN 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 ;DROP FUNCTION IF EXISTS `mycat_seq_nextval`; DELIMITER ;;CREATE FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8 DETERMINISTICBEGIN UPDATE mycat_sequence SET current_value = current_value + increment WHERE name = seq_name; RETURN mycat_seq_currval(seq_name); END;; DELIMITER ;DROP FUNCTION IF EXISTS `mycat_seq_setval`; DELIMITER ;;CREATE FUNCTION `mycat_seq_setval`(seq_name VARCHAR(50), value INTEGER) RETURNS varchar(64) CHARSET utf8 DETERMINISTICBEGIN UPDATE mycat_sequence SET current_value = value WHERE name = seq_name; RETURN mycat_seq_currval(seq_name); END;; DELIMITER ;
添加過程:
[root@testA mycat]# mysql -uroot -p123456 test mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 102 Server version: 5.7.19-log Source distribution Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the current input statement. mysql> DROP TABLE IF EXISTS mycat_sequence; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> CREATE TABLE mycat_sequence ( -> NAME VARCHAR (50) NOT NULL, -> current_value INT NOT NULL, -> increment INT NOT NULL DEFAULT 100, -> PRIMARY KEY (NAME) -> ) ENGINE = INNODB ; INSERT INTO mycat_sequence(name,current_value,increment) VALUES (‘GLOBAL‘, 100000, 100); Query OK, 0 rows affected (0.11 sec) mysql> mysql> mysql> mysql> mysql> INSERT INTO mycat_sequence(name,current_value,increment) VALUES (‘GLOBAL‘, 100000, 100); Query OK, 1 row affected (0.00 sec) mysql> mysql> mysql> DROP FUNCTION IF EXISTS `mycat_seq_currval`; Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ;; mysql> CREATE FUNCTION `mycat_seq_currval`(seq_name VARCHAR(50)) -> RETURNS varchar(64) CHARSET utf8 -> 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 -> ;; Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ; mysql> mysql> mysql> DROP FUNCTION IF EXISTS `mycat_seq_nextval`; DELIMITER ;; Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ;; mysql> CREATE FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(50)) RETURNS varchar(64) -> CHARSET utf8 -> DETERMINISTIC -> BEGIN -> UPDATE mycat_sequence -> SET current_value = current_value + increment -> WHERE name = seq_name; -> RETURN mycat_seq_currval(seq_name); -> END -> ;; Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ; mysql> mysql> mysql> mysql> mysql> DROP FUNCTION IF EXISTS `mycat_seq_setval`; Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ;; mysql> CREATE FUNCTION `mycat_seq_setval`(seq_name VARCHAR(50), value INTEGER) -> RETURNS varchar(64) CHARSET utf8 -> DETERMINISTIC -> BEGIN -> UPDATE mycat_sequence -> SET current_value = value -> WHERE name = seq_name; -> RETURN mycat_seq_currval(seq_name); -> END -> ;; Query OK, 0 rows affected (0.00 sec) mysql> DELIMITER ; mysql>
以下步驟非常關鍵,讓id_db
表也支持數據庫序列號。
mysql> INSERT INTO mycat_sequence (‘ID_DB‘, 1, 100); mysql> select * from mycat_sequence; +--------+---------------+-----------+ | NAME | current_value | increment | +--------+---------------+-----------+ | GLOBAL | 100200 | 100 | | ID_DB | 301 | 100 | +--------+---------------+-----------+ 2 rows in set (0.00 sec)
vim conf/schema.xml
<?xml version="1.0"?><!DOCTYPE mycat:schema SYSTEM "schema.dtd"><mycat:schema xmlns:mycat="http://io.mycat/"> <schema name="test" checkSQLschema="false" sqlMaxLimit="100"> <table name="id_db" dataNode="test1" autoIncrement="true" primaryKey="id"></table> <table name="mycat_sequence" dataNode="test1" autoIncrement="true" primaryKey="id"></table> </schema> <dataNode name="test1" dataHost="testA" database="test" /> <dataHost name="testA" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100"> <heartbeat>select 1</heartbeat> <writeHost host="hostM1" url="192.168.33.11:3306" user="root" password="123456" /> </dataHost></mycat:schema>
註意
將mycat_sequence表也放出來,且註意大小寫(數據庫默認區分大小寫)
實驗驗證:
[root@testA mycat]# mysql -uroot -p123456 -P8066 -h127.0.0.1 test mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB) Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the current input statement. mysql> show databases; +----------+ | DATABASE | +----------+ | test | +----------+ 1 row in set (0.00 sec) mysql> show tables; +----------------+ | Tables in test | +----------------+ | id_db | | mycat_sequence | +----------------+ 2 rows in set (0.00 sec) mysql> drop id_db; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘id_db‘ at line 1 mysql> drop table id_db; Query OK, 0 rows affected (0.08 sec) mysql> CREATE TABLE `id_db` (`id` int NOT NULL ,`nm` varchar(60) NULL ,PRIMARY KEY (`id`)); Query OK, 0 rows affected (0.02 sec) mysql> insert into id_db(id,nm) values(next value for MYCATSEQ_GLOBAL,‘id_db‘); Query OK, 1 row affected (0.10 sec) mysql> insert into id_db(nm) values(‘db‘); Query OK, 1 row affected (0.00 sec) mysql> select next value for MYCATSEQ_GLOBAL; +--------+ | 100201 | +--------+ | 100201 | +--------+ 1 row in set (0.00 sec) mysql> select * from id_db; +--------+-------+ | id | nm | +--------+-------+ | 303 | db | | 100200 | id_db | +--------+-------+ 2 rows in set (0.00 sec) mysql> insert into id_db(nm) values(‘db‘); Query OK, 1 row affected (0.01 sec) mysql> select * from id_db; +--------+-------+ | id | nm | +--------+-------+ | 303 | db | | 304 | db | | 100200 | id_db | +--------+-------+ 3 rows in set (0.00 sec) mysql>
優點:重新部署mycat不受影響
缺點:當配置節點的部署是主從復制,當主掛了切從後會有重復。
註意
節點如果是主從切換後,數據id可能會有異常(重復)
2.4 zookeeper方式
vim conf/server.xml
<property name="sequnceHandlerType">3</property>
vim conf/sequence_distributed_conf.properties
INSTANCEID=01 CLUSTERID=01
schema的table 增加屬性 autoIncrement="true"
和 primaryKey="id"
基於ZK 與本地配置的分布式ID 生成器(可以通過ZK 獲取集群(機房)唯一InstanceID,也可以通過配置文件配置InstanceID)ID 結構:long 64 位,ID 最大可占63 位
current time millis(微秒時間戳38 位,可以使用17 年)
instanceId(實例ID,可以通過ZK 或者配置文件獲取,5 位,也就是十進制0-31)
threadId(線程ID,9 位)
increment(自增,6 位)
一共63 位,可以承受單機房單機器單線程1000*(2^6)=640000 的並發。
優點:無悲觀鎖,無強競爭,吞吐量更高
缺點:對zookeeper集群的要求增加。
參考資料:
[1] http://mycat.io/
[2] 《分布式數據庫架構及企業實踐——基於Mycat中間件》
[3] 龍哥官方課程課件、博客
本文出自 “ygqygq2” 博客,請務必保留此出處http://ygqygq2.blog.51cto.com/1009869/1976279
Mycat學習實戰-Mycat全局主鍵