zoukankan      html  css  js  c++  java
  • 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集群的要求增加。

  • 相关阅读:
    SVN 服务器 配置
    字符串写入到json文件
    关于Linux系统打开最大文件数量
    svn clearup svn cleanup failed–previous operation has not finished; run cleanup if it was int错误的解决办法
    原标题:北大最短毕业致辞,4分钟9次掌声!
    Mysql 基础操作命令
    Git 合并两个分支内容
    微信、QQ第三方登录授权时的问题总结
    PHP CI框架数据库常用操作
    Python 抓取数据存储到Mysql中
  • 原文地址:https://www.cnblogs.com/zeussbook/p/12941672.html
Copyright © 2011-2022 走看看