当前位置: 首页 > 科技观察

MyCat全局序号的实现详解值得收藏

时间:2023-03-11 21:12:54 科技观察

分库分表实现的情况下,数据库自增主键已经不能保证自增的全局唯一性了首要的关键。为此,MyCat提供了一个全局序列,并提供了包括本地配置和数据库配置在内的多种实现方式。下面分别介绍这些实现方法。1.本地文件法原理:在这种方法中,MyCAT将序列配置到一个文件中。当使用sequence中的配置时,MyCAT会更新classpath下sequence_conf.properties文件中sequence的当前值。配置方法:在sequence_conf.properties文件中做如下配置:GLOBAL_SEQGLOBAL_SEQ.HISIDS=GLOBAL_SEQ.MINID=1001GLOBAL_SEQ.MAXID=1000000000GLOBAL_SEQ.CURID=1000其中HISIDS表示使用的历史段(一般没有特殊需要可以不配置),MINID表示最小ID值,MAXID表示最大ID值,CURID表示当前ID值。server.xml中配置:0注意:sequnceHandlerType需要配置为0,表示使用本地文件方式。使用示例:insertintotable1(id,name)values(nextvalueforMYCATSEQ_GLOBAL,'test');缺点:重新发布MyCAT时,配置文件中的sequence会恢复到初始值。优点:本地加载,读取速度更快。2.数据库法原理:在数据库中建表,存储序列名(name)、序列当前值(current_value)、步长(每次读取多少个序列)等信息incrementint类型,假设K)等信息;序列获取步骤:第一次使用序列时,根据传入的序列名从数据库表中读取current_value,递增到MyCat中,将数据库中的current_value设置为原来的current_value值+增量值。MyCat会读取current_value+increment作为本次要使用的序列值,下次使用时会自动加1。使用增量时间后,执行与步骤1)相同的操作。MyCat负责维护这张表,使用哪个sequence,只需要在这张表中插入一条记录即可。如果某次读取的序列没有用完,则系统停止,不再使用本次读取的序列的剩余值。配置方式(server.xml配置):1注意:sequnceHandlerType需要配置为1,表示使用数据库方式生成sequence。配置方法(数据库配置):1)创建一张MYCAT_SEQUENCE表——创建一张表DROPTABLEIFEXISTSMYCAT_SEQUENCE来存储序列;–namesequencename–current_value当前值–increment增长步长!可以理解为mycat一次读取数据库中的多少个序列。当这些用完之后,下次再从数据库中读取。CREATETABLEMYCAT_SEQUENCE(nameVARCHAR(50)NOTNULL,current_valueINTNOTNULL,incrementINTNOTNULLDEFAULT100,PRIMARYKEY(name))ENGINE=InnoDB;--插入一个序列INSERTINTOMYCAT_SEQUENCE(name,current_value,increment)VALUES('GLOBAL',1000)Createrelated)当前序列的值(当前值,增量)dropfunctionxistsmycat_seq_currval;delimiterCreateaTefunctionMycat_seq_currval(seq_namevarchar(50))returnsvarchar(64)charsetutf-8deteTeTutf-8detEteTerministicbegindeclareREteASCharch)INTOretvalFROMMYCAT_SEQUENCEWHEREname=seq_name;RETURNretval;ENDDELIMITER;–设置sequence值DROPFUNCTIONIFEXISTSmycat_seq_setval;DELIMITERCREATEFUNCTIONmycat_seq_setval(seq_nameVARCHAR(50),valueINTEGER)RETURNSvarchar(64)CHARSETutf-8DETERMINISTICBEGINUPDATEMYCAT_SEQUENCESETcurrent_value=valueWHEREname=seq_name;RETURNmycat_seq_currval(seq_name);ENDDELIMITER;?–Getthenextsequence值DROPFUNCTIONIFEXISTSmycat_seq_nextval;DELIMITERCREATEFUNCTIONmycat_seq_nextval(seq_nameVARCHAR(50))RETURNSvarchar(64)CHARSETutf-8DETERMINISTICBEGINUPDATEMYCAT_SEQUENCESETcurrent_valuecurrent_value=current_value+incrementWHEREname=seq_name;RETURNmycat_seq_currval(seq_name);ENDDELIMITER;3)sequence_db_conf.properties相关配置,指定sequence相关配置在哪个节点上:例如:USER_SEQ=test_dn1注意:MYCAT_SEQUENCE表和上面3个函数需要放在同一个节点上。该函数应直接在特定节点的数据库上执行。如果执行会报:youmightwanttousethelesssafelog_bin_trust_function_creatorsvariableneedstobesetforthedatabase:undermy.ini[mysqld]pluslog_bin_trust_function_creators=1underlinux/etc/my.cnfundermy.ini[mysqld]pluslog_bin_trust_function_creators=1修改后可以在mysql数据库中执行以上函数。使用示例:insertintotable1(id,name)values(nextvalueforMYCATSEQ_GLOBAL,'test');3、本地时间戳方式ID=64位二进制(42(毫秒)+5(机器ID)+5(业务代码)+12(重复累加)转成long型,十进制18位,二进制12位可以每毫秒同时累加。如何使用:配置server.xml2b。mycat下配置:sequence_time_conf.propertiesWORKID=0-31任意整数DATAACENTERID=0-31多个mycat节点下任意整数每个mycat配置的WORKID和DATAACENTERID不同,形成唯一标识,一共有32*32=1024种组合得到支持。4、分布式ZKID生成器3Zk的连接信息统一配置在myid.properties的zkURL属性中。基于ZK和本地配置的分布式ID生成器(可以通过ZK获取集群(机房)唯一的InstanceID,也可以通过配置文件配置InstanceID)ID结构:long64位,ID最多可占用63位bits*|currenttimemillis(微秒时间戳38位,可使用17年)|clusterId(机房或ZKid,通过配置文件配置5位)|instanceId(实例ID,可通过ZK或配置文件获取,5位))|threadId(线程ID,9位)|increment(自增,6位)*63位,一共可以承受单机房单机单线程1000*(2^6)=640000的并发。*无悲观锁,无强竞争,吞吐量更高配置文件:sequence_distributed_conf.properties,只要配置:INSTANCEID=ZK就是从ZK获取InstanceID。5、zk递增方法4Zk的连接信息统一配置在myid.properties的zkURL属性中,4为zookeeper实现递增序号1)配置文件:sequence_conf.properties,只要配置好ZK地址和表名的以下属性TABLE.MINID线程当前范围内的最小值TABLE.MAXID线程当前范围内的最大值TABLE.CURID当前值在一个线程的当前范围内2)文件配置的MAXID和MINID决定了每次获取间隔,对每个线程或进程都有效3)文件中这三个属性配置只对第一个线程的第一个线程有效进程,其他线程和进程会动态读取ZK6。自增主键(一)MyCAT自增长主键及返回生成主键ID的实现说明:Mysql本身对非自增长主键使用last_insert_id()不会返回结果,只会返回0;mysql只会定义自增长主键,可以使用last_insert_id()返回主键值;MyCAT目前提供了自增主键功能,但是如果对应mysql节点上的数据表没有定义auto_increment,那么在MyCAT层调用last_insert_id()是不会返回结果的。正确的配置方法如下:mysql定义自增主键CREATETABLEtable1('id_'INT(10)UNSIGNEDNOTNULLAUTO_INCREMENT,'name_'INT(10)UNSIGNEDNOTNULL,PRIMARYKEY('id_'))ENGINE=MYISAMAUTO_INCREMENT=6DEFAULTCHARSET=utf8;mycat定义主键自增mycat对应sequence_db_conf.properties,添加对应设置TABLE1=dn1,在数据库testuse中的mycat_sequence表中添加TABLE1表的sequence记录:127.0.0.1/root:[TESTDB>insertintot2(name_)values('t1');QueryOK,1rowaffected(0.14sec)127.0.0.1/root:[TESTDB>selectlast_insert_id();+——————+|LAST_INSERT_ID()|+——————+|100|+————+1rowinset(0.01sec)127.0.0.1/root:[TESTDB>insertintott2(name_)values('t2');QueryOK,1rowaffected(0.00sec)127.0.0.1/root:[TESTDB>selectlast_insert_id();+————————+|LAST_INSERT_ID()|+——————+|101|+——————+1row插入(0.00sec)127.0.0.1/root:[TESTDB>insertintott2(name_)values('t3');QueryOK,1rowaffected(0.00sec)127.0.0.1/root:[TESTDB>selectlast_insert_id();+——————+|LAST_INSERT_ID()|+——————+|102|+——————+1rowinset(0.00sec)Myibatis中新建记录后获取last_insert_id的例子: