二、Mycat全局序列號
Mycat保證id唯一的方式有如下幾個:
1)本地文件方式
2)數據庫方式
3)時間戳方式
4)ZKID生成器
5)ZK遞增ID
推薦使用第4,5種
以上5中方式都要統一在server.xml文件中開啟全局序列號的配置和在schema.xml文件中配置邏輯表的autoIncrement屬性為true(2個必須步驟)
1)sequnceHandlerType進行相應全局序列號策略選項設置(server.xml),在mycat中對應的源碼是MyCATSequnceProcessor.java
<property name="sequnceHandlerType">0</property>
sequnceHandlerType可取的值有以下幾個:
0:本地文件方式
1:數據庫方式
2:時間戳方式
3:ZKID生成器
4:ZK遞增ID
2)autoIncrement屬性為true(schema.xml)
<table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3" rule="mod-long" />
1. 本地文件方式
使用到的mycat源碼:io.mycat.route.sequence.handler.IncrSequenceHandler
在server.xml文件中開啟全局序列號的配置:
<property name="sequnceHandlerType">0</property>
使用到的配置文件:sequence_conf.properties
#default global sequence GLOBAL.HISIDS= GLOBAL.MINID=10001 GLOBAL.MAXID=20000 GLOBAL.CURID=10000 # self define sequence COMPANY.HISIDS= COMPANY.MINID=1001 COMPANY.MAXID=2000 COMPANY.CURID=1000 CUSTOMER.HISIDS= CUSTOMER.MINID=1001 CUSTOMER.MAXID=2000 CUSTOMER.CURID=1000 ORDER.HISIDS= ORDER.MINID=1001 ORDER.MAXID=2000 ORDER.CURID=1000 HOTNEWS.HISIDS= HOTNEWS.MINID=1001 HOTNEWS.MAXID=2000 HOTNEWS.CURID=1000
拿HOTNEWS這個表的配置來說明:
HOTNEWS.HISIDS= #HOTNEWS這張表歷史使用的自增id,一般不配置 HOTNEWS.MINID=1001 #HOTNEWS這張表使用的最小自增id HOTNEWS.MAXID=2000 #HOTNEWS這張表使用的最大自增id HOTNEWS.CURID=1000 #HOTNEWS這張表當前使用的自增id
缺點:當Mycat重新發布后,自增ID恢復到初始值。原因是因為sequnceHandlerType定義的是靜態變量,不推薦使用
示例:
1.1 在mycat的schema.xml文件里面分別配置邏輯表hotnews和mysql的主從機,注意autoIncrement="true"才能使用全局唯一id
<table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3" rule="mod-long" /> <dataNode name="dn1" dataHost="centos1" database="db1" /> <dataNode name="dn2" dataHost="centos1" database="db2" /> <dataNode name="dn3" dataHost="centos1" database="db3" /> <dataHost name="centos1" 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="192.168.152.130:3306" user="root" password="123456"> <!-- can have multi read hosts --> <readHost host="hostS2" url="192.168.152.131:3306" user="root" password="123456" /> </writeHost> <!-- <writeHost host="hostS1" url="localhost:3316" user="root" password="123456" />--> <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> --> </dataHost>
1.2 在主數據庫(192.168.152.130)分別創建3個數據庫db1,db2,db3,然后創建hotnews表
create database db1; use db1; create table hotnews( id bigint(20) not null primary key auto_increment, title varchar(50) default null ); create database db2; use db2; create table hotnews( id bigint(20) not null primary key auto_increment, title varchar(50) default null ); create database db3; use db3; create table hotnews( id bigint(20) not null primary key auto_increment, title varchar(50) default null );
1.3 插入數據
插入數據到hotnews前我們先來看一下使用本地文件方式的配置文件sequence_conf.properties的內容
cat sequence_conf.properties |grep HOTNEWS
插入數據到hotnews
insert into hotnews(id, title) values(next value for MYCATSEQ_HOTNEWS, 'test1'); insert into hotnews(id, title) values(next value for MYCATSEQ_HOTNEWS, 'test2'); insert into hotnews(id, title) values(next value for MYCATSEQ_HOTNEWS, 'test3');
1.4 查看hotnews表的結果
select * from hotnews;
再次查看配置文件sequence_conf.properties的內容,發現內容隨着插入數據的自增id做了改變
2. 數據庫方式
這種方式和本地文件的方式是一樣的,只是把sequence_conf.properties的內容用數據庫來管理
使用到的mycat源碼:io.mycat.route.sequence.handler.IncrSequenceMySQLHandler
這里還是以hotnews表為例
2.1 在server.xml文件中開啟全局序列號的配置:
<property name="sequnceHandlerType">1</property>
使用到的配置文件:sequence_db_conf.properties
vim sequence_db_conf.properties
#sequence stored in datanode GLOBAL=dn1 COMPANY=dn1 CUSTOMER=dn1 ORDERS=dn1
2.2 選擇其中的一個分片,執行如下步驟,譬如我在dn1中創建,對應的數據庫名為db1(為什么這里會涉及到datanode,因為后續的sequence_db_conf.properties文件會使用到),注意:是登錄到數據庫中創建,而不是在mycat中創建
第一步:創建SEQUENCE表,用來存儲序列號
use db1; DROP TABLE IF EXISTS MYCAT_SEQUENCE; CREATE TABLE MYCAT_SEQUENCE ( NAME VARCHAR (50) NOT NULL, /*全局SEQ名稱*/ current_value INT NOT NULL, /*當前序列ID*/ increment INT NOT NULL DEFAULT 100, /*初始序列ID*/ PRIMARY KEY (NAME) ) ENGINE = INNODB ;
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('GLOBAL', 100000, 100);
第二步:創建SEQ function
-- 獲取當前sequence的值(返回當前值,增量) DROP FUNCTION IF EXISTS `mycat_seq_currval`; DELIMITER ;; 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 ;; DELIMITER ; -- 獲取下一個sequence值 DROP FUNCTION IF EXISTS `mycat_seq_nextval`; DELIMITER ;; 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 ;; DELIMITER ; -- 設置sequence值 DROP FUNCTION IF EXISTS `mycat_seq_setval`; DELIMITER ;; 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 ;; DELIMITER ;
插入需要自增長的表的策略,這條數據是我們hotnews這個表所需要的。 name必須是大寫的字符,不然就會報錯
insert into MYCAT_SEQUENCE values('HOTNEWS','101','100');
說明:插入了一個名為HOTNEWS的sequence,當前值為101,步長為100。當插入第一條數據時id為201,后面每插入一條數據id加1
第三步:在sequence_db_conf.properties這個文件中定義hotnews這張表的序列名稱,同時可以定義到哪個分片上。這里是定義在dn1上的
名字=分片1[,分片2][,.....][,分片N]
vim sequence_db_conf.properties
保存:
:wq
2.3 重啟mycat
[root@centos1 mycat]# ./bin/mycat restart;
2.4 連接mycat進行數據測試
mysql -uroot -p123456 -P8066 -h192.168.152.128
插入數據
insert into hotnews(id, title) values(next value for MYCATSEQ_HOTNEWS, 'test11111'); insert into hotnews(id, title) values(next value for MYCATSEQ_HOTNEWS, 'test11112'); insert into hotnews(id, title) values(next value for MYCATSEQ_HOTNEWS, 'test11113');
查看結果:
select * from hotnews;
缺點:當mycat掛掉時可能出現主鍵沖突。不推薦使用
3. 本地時間戳方式
使用到的mycat源碼:io.mycat.route.sequence.handler.IncrSequenceTimeHandler
3.1 在server.xml文件中開啟全局序列號的配置:
<property name="sequnceHandlerType">2</property>
使用到的配置文件:
sequence_time_conf.properties
WORKID=01(范圍01-31)
DATAACENTERID=01(范圍01-31)
示例:
首先清空hotnews這張表的數據,方便查看測試結果
delete from hotnews;
插入測試數據
insert into hotnews(id, title) values(next value for MYCATSEQ_GLOBAL, 'test11111'); insert into hotnews(id, title) values(next value for MYCATSEQ_GLOBAL, 'test11112'); insert into hotnews(id, title) values(next value for MYCATSEQ_GLOBAL, 'test11113');
查看結果:
select * from hotnews;
優點:不存在id重復的現象。
缺點:主鍵太長。時間可能被重置。沒有特殊要求的場景可以使用
4. 自增長主鍵
方式1:不同自增長初始值+相同步長
方式2:參考“數據庫方式”
5. 分布式ZK ID生成(推薦使用)
使用到的mycat源碼:
io.mycat.route.sequence.handler.IncrSequenceZKHandler
io.mycat.route.sequence.handler.DistributedSequenceHandler
環境准備:先在虛擬機192.168.152.130里面裝好zookeeper,具體參考我的文章 搭建dubbo+zookeeper+dubboadmin分布式服務框架(windows平台下)
5.1 在server.xml文件中開啟全局序列號的配置:
vim server.xml
<property name="sequnceHandlerType">3</property>
5.2 修改如下配置文件:
1)myid.properties
vim myid.properties
配置文件說明:
loadZK=true|false //是否使用zk序列生成器
zkURL=xxx.xxx.xxx.xxx:2182,xxx.xxx.xxx.xxx:2182,xxx.xxx.xxx.xxx:2182
clusterId=集群名稱
2)sequence_distributed_conf.properties
vim sequence_distributed_conf.properties
配置文件說明:
INSTANCEID=ZK //改成“ZK”(默認是01)
CLUSTERID=01 //集群編號
5.3 重啟mycat
[root@centos1 mycat]# ./bin/mycat restart;
5.4 連接mycat進行數據測試
mysql -uroot -p123456 -P8066 -h192.168.152.128
插入數據
insert into hotnews(id, title) values(next value for MYCATSEQ_GLOBAL, 'test00000001'); insert into hotnews(id, title) values(next value for MYCATSEQ_GLOBAL, 'test00000002'); insert into hotnews(id, title) values(next value for MYCATSEQ_GLOBAL, 'test00000003');
查看結果:
select * from hotnews;
6. ZK遞增方式(推薦使用)
使用到的mycat源碼:io.mycat.route.sequence.handler.IncrSequenceZKHandler
6.1 在server.xml文件中開啟全局序列號的配置:
vim server.xml
<property name="sequnceHandlerType">4</property>
使用到的配置文件:
1) myid.properties 參考“5. 分布式ZK ID生成器”中的介紹。
2) sequence_conf.properties
HOTNEWS.HISIDS= #HOTNEWS這張表歷史使用的自增id,一般不配置 HOTNEWS.MINID=1001 #zk使用的區間內最小值 HOTNEWS.MAXID=2000 #zk使用的區間內最大值 HOTNEWS.CURID=1000 #zk使用的區間內當前值
說明:
以hotnews為例,然后根據sequence_conf.properties里面的hotnews的配置取MAXID和MINID的偏移量(這里是1000)作為id的增量值,當插入數據時把這1000個值用完了在繼續取MAXID和MINID的偏移量
6.2 重啟mycat
[root@centos1 mycat]# ./bin/mycat restart;
6.3 連接mycat進行數據測試
mysql -uroot -p123456 -P8066 -h192.168.152.128
插入數據
insert into hotnews(id, title) values(next value for MYCATSEQ_GLOBAL, 'test00000001'); insert into hotnews(id, title) values(next value for MYCATSEQ_GLOBAL, 'test00000002'); insert into hotnews(id, title) values(next value for MYCATSEQ_GLOBAL, 'test00000003');
查看結果:
select * from hotnews;