MyCat全局主鍵生成策略


在分庫分表的情況下,多個數據庫自增主鍵無法保證自增主鍵的全局唯一,因此MyCat的全局主鍵生成策略孕育而生。

Mycat全局主鍵方式

1. 本地文件方式:使用服務器本地磁盤文件的方式

2. 本地時間戳方式:使用時間戳方式

3. 數據庫方式:使用數據庫的方式

4. 分布式zookeeper生成ID

 

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

注意事項

1.以上配置文件中,自定義表名必須大寫書寫
2.HISIDS:表示使用過的歷史分段(一般無特殊需要可不配置)
3.MINID :最小ID 值
4.MAXID :表示最大ID 值
5.CURID 表示當前ID 值。
6.當 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>

優點:本地加載,讀取速度較快,配置簡單 

缺點:mycat重新發布時,seq文件需要替換,集群部署無法用此方式,路由到不同的mycat上無法保證id唯一,使mycat變成了有狀態的中間件

 

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>

* 本地時間戳計算方式:

ID= 64 位二進制 (42(毫秒)+5(機器 ID)+5(業務編碼)+12(重復累加) 長度18位,因此表主鍵字段長度必須大於等於18位

優點:不存在mycat重新發布影響seq的問題,

缺點:字段長度是18位,比較占空間

 

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
    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 ;


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 ;


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 ;

添加過程:

[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表也放出來,且注意大小寫(數據庫默認區分大小寫)

優點:重新部署mycat不受影響,節點如果是主從切換后,數據id可能會有異常(重復)

缺點:當配置節點的部署是主從復制,當主掛了切從后會有重復。

 

4. 分布式zookeeper生成ID

vim conf/server.xml

<property name="sequnceHandlerType">3</property>

vim conf/sequence_distributed_conf.properties

INSTANCEID=01
CLUSTERID=01

vim conf/schema.xml

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集群的要求增加。

 


免責聲明!

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



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