Mysql系列七:分库分表技术难题之分布式全局唯一id解决方案

Mysql系列七:分库分表技术难题之分布式全局唯一id解决方案,第1张

概述一、前言在前面的文章Mysql系列四:数据库分库分表基础理论中,已经说过分库分表需要应对的技术难题有如下几个:1. 分布式全局唯一id2. 分片规则和策略3. 跨分片技术问题4. 跨分片事物问题下面我们来看一下Mycat是如何解决分布式全局唯一id的问题的二、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递增ID2)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 sequenceGLOBAL.HISIDS=GLOBAL.MINID=10001GLOBAL.MAXID=20000GLOBAL.CURID=10000# self define sequenceCOMPANY.HISIDS=COMPANY.MINID=1001COMPANY.MAXID=2000COMPANY.CURID=1000CUSTOMER.HISIDS=CUSTOMER.MINID=1001CUSTOMER.MAXID=2000CUSTOMER.CURID=1000ORDER.HISIDS=ORDER.MINID=1001ORDER.MAXID=2000ORDER.CURID=1000HOTNEWS.HISIDS=HOTNEWS.MINID=1001HOTNEWS.MAXID=2000HOTNEWS.CURID=1000拿HOTNEWS这个表的配置来说明:HOTNEWS.HISIDS= #HOTNEWS这张表历史使用的自增id,一般不配置HOTNEWS.MINID=1001 #HOTNEWS这张表使用的最小自增idHOTNEWS.MAXID=2000 #HOTNEWS这张表使用的最大自增idHOTNEWS.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插入数据到hotnewsinsert 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.propertiesvim sequence_db_conf.properties#sequence stored in datanodeGLOBAL=dn1COMPANY=dn1CUSTOMER=dn1ORDERS=dn12.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 utf8DETERMINISTICBEGIN DECLARE retval VARCHAR(64);SET retval="-999999999,null";SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR) ) INTO retvalFROM MYCAT_SEQUENCE WHERE name = seq_name 一、前言

在前面的文章中,已经说过分库分表需要应对的技术难题有如下几个:

1. 分布式全局唯一id

2. 分片规则和策略

3. 跨分片技术问题

4. 跨分片事物问题

下面我们来看一下Mycat是如何解决分布式全局唯一id的问题的

二、Mycat全局序列号

Mycat保证id唯一的方式有如下几个:

1)本地文件方式

2)数据库方式

3)时间戳方式

4)ZKID生成器

5)ZK递增ID

4,5

1)sequnceHandlerType进行相应全局序列号策略选项设置(server.xml),在mycat中对应的源码是MyCATSequnceProcessor.java

0

  sequnceHandlerType可取的值有以下几个:

    0:本地文件方式    1:数据库方式    2:时间戳方式    3:ZKID生成器    4:ZK递增ID

2)autoIncrement属性为true(schema.xml)

1. 本地文件方式

使用到的mycat源码:io.mycat.route.sequence.handler.IncrSequenceHandler

 在server.xml文件中开启全局序列号的配置:

0

使用到的配置文件:sequence_conf.properties

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这个表的配置来说明:

示例:

1.1 在mycat的schema.xml文件里面分别配置逻辑表hotnews和mysql的主从机,注意autoIncrement="true"才能使用全局唯一id select user() 1.2 在主数据库(192.168.152.130)分别创建3个数据库db1,db2,db3,然后创建hotnews表 () () );
<span >create
<span >database
<span > db2;
<span >use
<span > db2;
<span >create
<span >table
<span > hotnews(
id
<span >bigint
(<span >20
) <span >not
<span >null
<span >primary
<span >key
<span > auto_increment,title
<span >varchar
(<span >50
) <span >default
<span >null
<span >

);
<span >create <span >database<span > db3;
<span >use<span > db3;
<span >create <span >table<span > hotnews(
id <span >bigint(<span >20) <span >not <span >null <span >primary <span >key<span > auto_increment,title <span >varchar(<span >50) <span >default <span >null<span >

);

1.3 插入数据

插入数据到hotnews前我们先来看一下使用本地文件方式的配置文件sequence_conf.properties的内容

cat sequence_conf.properties grep HOTNEWS

插入数据到hotnews

hotnews(id,title) ( value MYCATSEQ_HOTNEWS, hotnews(id, hotnews(id,);1.4 查看hotnews表的结果 hotnews;

再次查看配置文件sequence_conf.properties的内容,发现内容随着插入数据的自增id做了改变

2. 数据库方式

使用到的mycat源码:io.mycat.route.sequence.handler.IncrSequenceMySQLHandler

这里还是以hotnews表为例

2.1 在server.xml文件中开启全局序列号的配置:1

使用到的配置文件:sequence_db_conf.properties

vim sequence_db_conf.properties
#sequence stored dn1

2.2 选择其中的一个分片,执行如下步骤,譬如我在dn1中创建,对应的数据库名为db1(为什么这里会涉及到datanode,因为后续的sequence_db_conf.properties文件会使用到),

第一步:创建SEQUENCE表,用来存储序列号

() , , , INNODB ; INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('GLOBAL',100000,100);

第二步:创建SEQ function

`mycat_seq_currval`(seq_name ( ( retval ( retval", concat((current_value ),",(increment ) ) MYCAT_SEQUENCE name <span >--<span > 获取下一个sequence值
<span >DROP
<span >FUNCTION
<span >IF
<span >EXISTS
<span > mycat_seq_nextval;
DELIMITER ;;
<span >CREATE
<span >FUNCTION
mycat_seq_nextval(seq_name <span >VARCHAR
(<span >50
)) <span >RETURNS
<span >varchar
(<span >64
<span >)
CHARSET utf8
DETERMINISTIC
<span >BEGIN
<span >UPDATE
<span > MYCAT_SEQUENCE
<span >SET
current_value <span >=
current_value <span >+
<span > increment
<span >WHERE
name <span >=
<span > seq_name;
<span >RETURN
<span > mycat_seq_currval(seq_name);
<span >END
<span >
;;
DELIMITER ;

<span >--<span > 设置sequence值
<span >DROP <span >FUNCTION <span >IF <span >EXISTS<span > mycat_seq_setval;
DELIMITER ;;
<span >CREATE <span >FUNCTION mycat_seq_setval(seq_name <span >VARCHAR(<span >50),value <span >INTEGER<span >)
<span >RETURNS <span >varchar(<span >64<span >) CHARSET utf8
DETERMINISTIC
<span >BEGIN <span >UPDATE<span > MYCAT_SEQUENCE
<span >SET current_value <span >=<span > value
<span >WHERE name <span >=<span > seq_name;
<span >RETURN<span > mycat_seq_currval(seq_name);
<span >END<span >
;;
DELIMITER ;

插入需要自增长的表的策略,这条数据是我们hotnews这个表所需要的。 name必须是大写的字符,不然就会报错 

MYCAT_SEQUENCE (,,);

第三步:在sequence_db_conf.properties这个文件中定义hotnews这张表的序列名称,同时可以定义到哪个分片上。这里是定义在dn1上的

      名字=分片1[,分片2][,.....][,分片N]

vim sequence_db_conf.properties

保存:

:wq

2.3 重启mycat# .binmycat restart;

2.4 连接mycat进行数据测试mysql uroot p123456 P8066 h192..

插入数据

hotnews(id, hotnews(id, hotnews(id,);

查看结果:

hotnews;

3. 本地时间戳方式

使用到的mycat源码:io.mycat.route.sequence.handler.IncrSequenceTimeHandler

3.1 在server.xml文件中开启全局序列号的配置:2

使用到的配置文件:

sequence_time_conf.properties

          WORKID=01(范围01-31)

          DATAACENTERID=01(范围01-31)

示例:

首先清空hotnews这张表的数据,方便查看测试结果

hotnews;

插入测试数据

hotnews(id,title) ( value MYCATSEQ_GLOBAL, hotnews(id, hotnews(id,);

查看结果:

hotnews;

4. 自增长主键

方式1:不同自增长初始值+相同步长

方式2:参考“数据库方式”

5. 分布式ZK ID生成

环境准备:先在虚拟机192.168.152.130里面装好zookeeper,具体参考我的文章 

5.1 在server.xml文件中开启全局序列号的配置:

vim server.xml

35.2 修改如下配置文件:

1)myID.propertIEs

vim myID.propertIEs

loadZK=true|false //

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

CLUSTERID=01   //集群

5.3 重启mycat# .binmycat restart;5.4 连接mycat进行数据测试MysqL -uroot -p123456 -P8066 -h192.168.152.128

插入数据

hotnews(ID, hotnews(ID, hotnews(ID,

查看结果:

hotnews;

6. ZK递增方式

使用到的mycat源码:io.mycat.route.sequence.handler.IncrSequenceZKHandler

6.1 在server.xml文件中开启全局序列号的配置:

vim server.xml

4

使用到的配置文件:

1) myID.propertIEs 参考“5. 分布式ZK ID生成器”中的介绍。

2) sequence_conf.propertIEs

hotnewsMAXID和MINID1000MAXID和MINID的偏移量

6.2 重启mycat[root@centos1 mycat]# ./bin/mycat restart;

6.3  连接mycat进行数据测试

MysqL -uroot -p123456 -P8066 -h192.168.152.128

插入数据

hotnews(ID,);

查看结果:

hotnews;

总结

以上是内存溢出为你收集整理的Mysql系列七:分库分表技术难题之分布式全局唯一id解决方案全部内容,希望文章能够帮你解决Mysql系列七:分库分表技术难题之分布式全局唯一id解决方案所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/1169249.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-02
下一篇 2022-06-02

发表评论

登录后才能评论

评论列表(0条)

保存