Mysql系列七:分库分表技术难题之分布式全局唯一id解决方案
一、前言在前面的文章中,已经说过分库分表需要应对的技术难题有如下几个: 1. 分布式全局唯一id 2. 分片规则和策略 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 0sequnceHandlerType可取的值有以下几个: 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 self define sequenceCOMPANY.HISIDS= CUSTOMER.HISIDS= ORDER.HISIDS= HOTNEWS.HISIDS= 拿HOTNEWS这个表的配置来说明:
示例: 1.1 在mycat的schema.xml文件里面分别配置逻辑表hotnews和mysql的主从机,注意autoIncrement="true"才能使用全局唯一idselect user()1.2 在主数据库(192.168.152.130)分别创建3个数据库db1,db2,db3,然后创建hotnews表() () );<span style="color: #0000ff">create <span style="color: #0000ff">database<span style="color: #000000"> db2; <span style="color: #0000ff">use<span style="color: #000000"> db2; <span style="color: #0000ff">create <span style="color: #0000ff">table<span style="color: #000000"> hotnews( id <span style="color: #0000ff">bigint(<span style="color: #800000; font-weight: bold">20) <span style="color: #808080">not <span style="color: #0000ff">null <span style="color: #0000ff">primary <span style="color: #0000ff">key<span style="color: #000000"> auto_increment,title <span style="color: #0000ff">varchar(<span style="color: #800000; font-weight: bold">50) <span style="color: #0000ff">default <span style="color: #0000ff">null<span style="color: #000000"> ); <span style="color: #0000ff">use<span style="color: #000000"> db3; <span style="color: #0000ff">create <span style="color: #0000ff">table<span style="color: #000000"> hotnews( id <span style="color: #0000ff">bigint(<span style="color: #800000; font-weight: bold">20) <span style="color: #808080">not <span style="color: #0000ff">null <span style="color: #0000ff">primary <span style="color: #0000ff">key<span style="color: #000000"> auto_increment,title <span style="color: #0000ff">varchar(<span style="color: #800000; font-weight: bold">50) <span style="color: #0000ff">default <span style="color: #0000ff">null<span style="color: #000000"> ); 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. 数据库方式这种方式和本地文件的方式是一样的,只是把sequence_conf.properties的内容用数据库来管理 使用到的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文件会使用到),注意:是登录到数据库中创建,而不是在mycat中创建 第一步:创建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 style="color: #008080">--<span style="color: #008080"> 获取下一个sequence值<span style="color: #0000ff">DROP <span style="color: #0000ff">FUNCTION <span style="color: #0000ff">IF <span style="color: #808080">EXISTS<span style="color: #000000"> mycat_seq_nextval ;DELIMITER ;; <span style="color: #0000ff">CREATE <span style="color: #0000ff">FUNCTION mycat_seq_nextval (seq_name <span style="color: #0000ff">VARCHAR(<span style="color: #800000; font-weight: bold">50)) <span style="color: #0000ff">RETURNS <span style="color: #0000ff">varchar(<span style="color: #800000; font-weight: bold">64<span style="color: #000000">)CHARSET utf8 DETERMINISTIC <span style="color: #0000ff">BEGIN <span style="color: #0000ff">UPDATE<span style="color: #000000"> MYCAT_SEQUENCE <span style="color: #0000ff">SET current_value <span style="color: #808080">= current_value <span style="color: #808080">+<span style="color: #000000"> increment <span style="color: #0000ff">WHERE name <span style="color: #808080">=<span style="color: #000000"> seq_name; <span style="color: #0000ff">RETURN<span style="color: #000000"> mycat_seq_currval(seq_name); <span style="color: #0000ff">END<span style="color: #000000"> ;; DELIMITER ; <span style="color: #008080">--<span style="color: #008080"> 设置sequence值 <span style="color: #0000ff">DROP <span style="color: #0000ff">FUNCTION <span style="color: #0000ff">IF <span style="color: #808080">EXISTS<span style="color: #000000"> mycat_seq_setval ;DELIMITER ;; <span style="color: #0000ff">CREATE <span style="color: #0000ff">FUNCTION mycat_seq_setval (seq_name <span style="color: #0000ff">VARCHAR(<span style="color: #800000; font-weight: bold">50),value <span style="color: #0000ff">INTEGER<span style="color: #000000">)<span style="color: #0000ff">RETURNS <span style="color: #0000ff">varchar(<span style="color: #800000; font-weight: bold">64<span style="color: #000000">) CHARSET utf8 DETERMINISTIC <span style="color: #0000ff">BEGIN <span style="color: #0000ff">UPDATE<span style="color: #000000"> MYCAT_SEQUENCE <span style="color: #0000ff">SET current_value <span style="color: #808080">=<span style="color: #000000"> value <span style="color: #0000ff">WHERE name <span style="color: #808080">=<span style="color: #000000"> seq_name; <span style="color: #0000ff">RETURN<span style="color: #000000"> mycat_seq_currval(seq_name); <span style="color: #0000ff">END<span style="color: #000000"> ;; DELIMITER ; 插入需要自增长的表的策略,这条数据是我们hotnews这个表所需要的。 name必须是大写的字符,不然就会报错? MYCAT_SEQUENCE (,,);说明:插入了一个名为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# .binmycat restart;2.4 连接mycat进行数据测试mysql uroot p123456 P8066 h192..插入数据 hotnews(id, hotnews(id, hotnews(id,);查看结果: hotnews;缺点:当mycat挂掉时可能出现主键冲突。不推荐使用 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;优点:不存在id重复的现象。 缺点:主键太长。时间可能被重置。没有特殊要求的场景可以使用 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, |