游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

分布式全局ID生成器原理剖析及非常齐全开源方案应用示例

  拿我们系统常用Mysql数据库来说,在之前的单体架构基本是单库结构,每个业务表的ID一般从1增,通过AUTOINCREMENT1设置自增起始值,随着系统(比如互联网电商、外卖)用户数据日渐增长,单库性能无法满足业务系统,在这之后我们会使用基于主从同步的读写分离,但当用户量规模连主从模式都无法应对时,我们会采用分库分表(当然现在还有其他解决方案比如分布式关系型数据库如TiDB)的方案,这样对数据分库分表后需要有一个唯一ID来标识一条数据或消息,数据库的自增ID显然不能满足需求,在复杂分布式系统中,往往还有很多场景需要对大量的数据和消息进行唯一标识,这就迫使我们需要用到分布式系统中全局ID生成器。我们本篇文章只是介绍一些常用实现方案,而大部分的开源分布式ID生成器基本都是基于号段模式和雪花算法为基础,可以根据不同业务场景需要选择,不做详细说明分布式ID满足要求全局唯一:需要是唯一标识,不能出现重复的ID好,这是最基本的要求。高性能:高QPS、低延迟、否则反倒会成为系统瓶颈高可用性:可用性接近5个9信息安全:如果ID是连续的对于恶意用户爬虫采用顺序爬取指定URL爬取信息就非常容易完成;如果是作为订单号就更危险了,可以直接知道一天的单量,所以在一些应用场景下会需要ID无规则、不规则的要求趋势递增:在MySQLInnoDB引擎中使用的是聚集索引,采用BTree的数据结构来存储索引数据,在主键的选择上我们应该尽量使用有序的编号保证写入性能单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求。常用解决方案UUID
  全局ID在Java中们可以简单使用来UUID生成,输出的41c9b76fc5ac4265939cd5b27bdacdf1这种结果的字符串数据,可以看生成的是36位长度的16进制的字符串,然后将中划线替换为空字符串publicstaticvoidmain(String〔〕args){StringuuidUUID。randomUUID()。toString()。replaceAll(,);System。out。println(uuid);}优点优点UUID设计上固然是可以满足全局唯一的要求缺点UUID太长且无序,在互联网大部分企业中都是使用Mysql数据库,且有些业务场景需要使用到事务因此底层存储引擎采用的是Innodb,这就导致BTree索引的分裂,存储和索引的性能差,并不适合在Innodb作为主键,自增ID比较适合作为Innodb主键数据库自增ID这样方式就是单独使用一个数据库来生成ID,业务程序通过这个数据库获取ID,表结构可以简单设计如下,然后再通过事务通过插入等操作数据触发ID自增,这个数据库层级性能比较高,你也可以采用表级别插入返回数据的主键CREATEDATABASESEQID;CREATETABLESEQID。SEQUENCEID(idbigint(20)unsignedNOTNULLautoincrement,idvaluechar(10)NOTNULLdefault,PRIMARYKEY(id),UNIQUEKEYidvalue(idvalue))ENGINEMyISAM;beginreplaceintoSEQUENCEID(idvalue)values(xxx);SELECTLASTINSERTID();commit;end优点简单、ID自增缺点DB单点故障Mysql并发不好,无法抗住高并发数据库集群模式上面单个数据库有弊端,那么可以采用数据库集群,数据库集群常用主从和主主,我们使用主主模式,每个数据库通过设置不同起始值和相同自增步长来实现,比如三台mysql主主模式,mysql1从1开始自增步长为3,序号1、4、7。。。,mysql2从2开始自增步长为3,序号2、5、8。。。,mysql3从3开始自增步长为3,序号3、6、9。。。。,每个业务系统可以通过这三台中获取到IDsetautoincrementoffset1;mysql1起始值setautoincrementincrement3;mysql1自增步长setautoincrementoffset2;mysql2起始值setautoincrementincrement3;mysql2自增步长setautoincrementoffset3;mysql3起始值setautoincrementincrement3;mysql3自增步长优点解决DB单点问题缺点不利于扩容,如果需要进行MySQL扩容增加节点还是比较麻烦,可能还需要停机扩容号段模式号段模式几乎是目前所有开源分布式ID生成器的主流实现方式之一,号段模式比如每次从数据库取出一个号段范围,例如(1,1000〕代表1000个ID,具体的业务服务将本号段,生成11000的自增ID并加载到内存,不强依赖于数据库,不会频繁的访问数据库,对数据库的压力小很多。简易版本的表结构如下:CREATETABLEidgenerator(idint(10)NOTNULL,maxidbigint(20)NOTNULLCOMMENT当前最大id,stepint(20)NOTNULLCOMMENT号段的步长,biztypeint(20)NOTNULLCOMMENT业务类型,versionint(20)NOTNULLCOMMENT版本号,PRIMARYKEY(id))biztype:代表不同业务类型maxid:当前最大的可用idstep:代表号段的长度version:是一个乐观锁,每次都更新version,保证并发时数据的正确性
  每次申请一个号段,通过乐观锁的机制兑换maxid字段做一次update操作,update成功则说明新号段获取成功,新的号段范围是(maxid,maxidstep〕updateidgeneratorsetmaxid{maxidstep},versionversion1whereversion{version}andbiztypeXXXRedis实现
  Redis也同样可以实现,原理就是利用redis的incr命令实现ID的原子性自增,redis持久化也支持基于每条命令持久化方式,且redis自身有高可用集群模式192。168。3。117:6379setseqid1初始化自增ID为1OK192。168。3。117:6379incrseqid增加1,并返回递增后的数值(integer)2雪花算法(SnowFlake)雪花算法(Snowflake)是twitter公司内部分布式项目采用的ID生成算法,开源后广受国内大厂的好评,在该算法影响下各大公司相继开发出各具特色的分布式生成器。SnowFlake算法用来生成64位的ID,刚好可以用long整型存储,能够用于分布式系统中生产唯一的ID,并且生成的ID有序
  Snowflake生成的是Long类型的ID,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特。
  SnowflakeID组成结构:正数位(占1比特)时间戳(占41比特)机器ID(占5比特)数据中心(占5比特)自增值(占12比特),总共64比特组成的一个Long类型。第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L41)(1000L606024365)69年工作机器id(10bit):也被叫做workId,这个可以灵活配置,机房或者机器号组合都可以。序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID
  雪花算法比较依赖于时间,会出现时钟回拨的问题,所以尽量保证时间同步,大部分开源分布式ID生成器大都有优化解决时钟回拨的问题
  雪花算法Java实现源码Gitub地址
  下面是基于Twitter的雪花算法SnowFlake,使用Java语言实现,封装成工具方法,各个业务应用可以直接使用该工具方法来获取分布式ID,只需保证每个业务应用有自己的工作机器id即可,而不需要单独去搭建一个获取分布式ID的应用041位时间戳5位数据中心标识5位机器标识12位序列号
  5位数据中心标识跟5位机器标识这样的分配仅仅是当前实现中分配的,如果业务有其实的需要,可以按其它的分配比例分配,如10位机器标识,不需要数据中心标识。twitter的snowflake算法java实现authorbeyonddate20161126publicclassSnowFlake{起始的时间戳privatefinalstaticlongSTARTSTMP1480166465631L;每一部分占用的位数privatefinalstaticlongSEQUENCEBIT12;序列号占用的位数privatefinalstaticlongMACHINEBIT5;机器标识占用的位数privatefinalstaticlongDATACENTERBIT5;数据中心占用的位数每一部分的最大值privatefinalstaticlongMAXDATACENTERNUM1L(1LDATACENTERBIT);privatefinalstaticlongMAXMACHINENUM1L(1LMACHINEBIT);privatefinalstaticlongMAXSEQUENCE1L(1LSEQUENCEBIT);每一部分向左的位移privatefinalstaticlongMACHINELEFTSEQUENCEBIT;privatefinalstaticlongDATACENTERLEFTSEQUENCEBITMACHINEBIT;privatefinalstaticlongTIMESTMPLEFTDATACENTERLEFTDATACENTERBIT;privatelongdatacenterId;数据中心privatelongmachineId;机器标识privatelongsequence0L;序列号privatelonglastStmp1L;上一次时间戳publicSnowFlake(longdatacenterId,longmachineId){if(datacenterIdMAXDATACENTERNUMdatacenterId0){thrownewIllegalArgumentException(datacenterIdcantbegreaterthanMAXDATACENTERNUMorlessthan0);}if(machineIdMAXMACHINENUMmachineId0){thrownewIllegalArgumentException(machineIdcantbegreaterthanMAXMACHINENUMorlessthan0);}this。datacenterIddatacenterId;this。machineIdmachineId;}产生下一个IDreturnpublicsynchronizedlongnextId(){longcurrStmpgetNewstmp();if(currStmplastStmp){thrownewRuntimeException(Clockmovedbackwards。Refusingtogenerateid);}if(currStmplastStmp){相同毫秒内,序列号自增sequence(sequence1)MAXSEQUENCE;同一毫秒的序列数已经达到最大if(sequence0L){currStmpgetNextMill();}}else{不同毫秒内,序列号置为0sequence0L;}lastStmpcurrStmp;return(currStmpSTARTSTMP)TIMESTMPLEFT时间戳部分datacenterIdDATACENTERLEFT数据中心部分machineIdMACHINELEFT机器标识部分sequence;序列号部分}privatelonggetNextMill(){longmillgetNewstmp();while(milllastStmp){millgetNewstmp();}returnmill;}privatelonggetNewstmp(){returnSystem。currentTimeMillis();}publicstaticvoidmain(String〔〕args){SnowFlakesnowFlakenewSnowFlake(2,3);for(inti0;i(112);i){System。out。println(snowFlake。nextId());}}}百度(Uidgenerator)概述
  官方GitHub地址https:github。combaiduuidgenerator
  UidGenerator是Java实现的,基于Snowflake算法的唯一ID生成器。UidGenerator以组件形式工作在应用项目中,支持自定义workerId位数和初始化策略,从而适用于docker等虚拟化环境下实例自动重启、漂移等场景。在实现上,UidGenerator通过借用未来时间来解决sequence天然存在的并发限制;采用RingBuffer来缓存已生成的UID,并行化UID的生产和消费,同时对CacheLine补齐,避免了由RingBuffer带来的硬件级伪共享问题。最终单机QPS可达600万。
  依赖版本:Java8及以上版本,MySQL(内置WorkerID分配器,启动阶段通过DB进行分配;如自定义实现,则DB非必选依赖)
  〔〕(https:github。combaiduuidgeneratorblobmasterdocsnowflake。png)Snowflake算法描述:指定机器同一时刻某一并发序列,是唯一的。据此可生成一个64bits的唯一ID(long)。默认采用上图字节分配方式:sign(1bit)固定1bit符号标识,即生成的UID为正数。deltaseconds(28bits)当前时间,相对于时间基点20160520的增量值,单位:秒,而不是毫秒,最多可支持约8。7年workerid(22bits)机器id,最多可支持约420w次机器启动。内置实现为在启动时由数据库分配,默认分配策略为用后即弃,后续可提供复用策略,同一应用每次重启就会消费一个workIdsequence(13bits)
  每秒下的并发序列,13bits可支持每秒8192个并发。
  UidGenerator是基于Snowflake算法实现的,与原始的snowflake算法不同在于,UidGenerator支持自定义时间戳、工作机器ID和序列号等各部分的位数,而且UidGenerator中采用用户自定义workId的生成策略。
  UidGenerator需要与数据库配合使用,需要新增一个WORKERNODE表。当应用启动时会向数据库表中去插入一条数据,插入成功后返回的自增ID就是该机器的workId数据由host,port组成。提供了两种生成器:DefaultUidGenerator、CachedUidGenerator,如对UID生成性能有要求则使用CachedUidGenerator。CachedUidGenerator
  RingBuffer环形数组,数组每个元素成为一个slot。RingBuffer容量,默认为Snowflake算法中sequence最大值,且为2N。可通过boostPower配置进行扩容,以提高RingBuffer读写吞吐量。Tail指针、Cursor指针用于环形数组上读写slot:Tail指针表示Producer生产的最大序号(此序号从0开始,持续递增)。Tail不能超过Cursor,即生产者不能覆盖未消费的slot。当Tail已赶上curosr,此时可通过rejectedPutBufferHandler指定PutRejectPolicyCursor指针
  表示Consumer消费到的最小序号(序号序列与Producer序列相同)。Cursor不能超过Tail,即不能消费未生产的slot。当Cursor已赶上tail,此时可通过rejectedTakeBufferHandler指定TakeRejectPolicy
  CachedUidGenerator采用了双RingBuffer,UidRingBuffer用于存储Uid、FlagRingBuffer用于存储Uid状态(是否可填充、是否可消费)由于数组元素在内存中是连续分配的,可最大程度利用CPUcache以提升性能。但同时会带来伪共享FalseSharing问题,为此在Tail、Cursor指针、FlagRingBuffer中采用了CacheLine补齐方式。
  RingBuffer填充时机初始化预填充RingBuffer初始化时,预先填充满整个RingBuffer。即时填充Take消费时,即时检查剩余可用slot量(tailcursor),如小于设定阈值,则补全空闲slots。阈值可通过paddingFactor来进行配置,请参考QuickStart中CachedUidGenerator配置周期填充
  通过Schedule线程,定时补全空闲slots。可通过scheduleInterval配置,以应用定时填充功能,并指定Schedule时间间隔简单使用官方源码导入idea
  建立数据库和导入表WORKERNODE。sql
  创建一个SpringBoot启动类,在applicationdev。yml文件配置数据库信息,启动类配置Mybatis扫描com。baidu。fsg。uid的mapper文件注解,创建一个UidControoler提供一个获取单个uid的接口,启动SpringBoot程序
  访问提供接口地址:http:localhost:8080uidsnowflake,返回uid结果,每次刷新1
  数据库表WORKERNODE当我们每次启动程序会重新生成新的记录
  美团(Leaf)概述
  官方GitHub地址https:github。comMeituanDianpingLeafTherearenotwoidenticalleavesintheworld。世界上没有两片完全相同的树叶。莱布尼茨
  Leaf最早期需求是各个业务线的订单ID生成需求。在美团早期,有的业务直接通过DB自增的方式生成ID,有的业务通过redis缓存来生成ID,也有的业务直接用UUID这种方式来生成ID。以上的方式各自有各自的问题,因此我们决定实现一套分布式ID生成服务来满足需求。
  目前Leaf覆盖了美团点评公司内部金融、餐饮、外卖、酒店旅游、猫眼电影等众多业务线。在4C8GVM基础上,通过公司RPC方式调用,QPS压测结果近5ws,TP9991ms当然,为了追求更高的性能,需要通过RPCServer来部署Leaf服务,那仅需要引入leafcore的包,把生成ID的API封装到指定的RPC框架中即可。LeafServer是一个springboot的程序,提供HTTP服务来获取ID。Leaf提供两种生成的ID的方式(号段模式和snowflake模式),你可以同时开启两种方式,也可以指定开启某种方式(默认两种方式为关闭状态)配置LeafServer的配置都在leafserversrcmainresourcesleaf。properties中
  配置项
  含义
  默认值
  leaf。name
  leaf服务名
  leaf。segment。enable
  是否开启号段模式
  false
  leaf。jdbc。url
  mysql库地址
  leaf。jdbc。username
  mysql用户名
  leaf。jdbc。password
  mysql密码
  leaf。snowflake。enable
  是否开启snowflake模式
  false
  leaf。snowflake。zk。address
  snowflake模式下的zk地址
  leaf。snowflake。port
  snowflake模式下的服务注册端口
  号段模式如果使用号段模式,需要建立DB表,并配置leaf。jdbc。url,leaf。jdbc。username,leaf。jdbc。password如果不想使用该模式配置leaf。segment。enablefalse即可。Snowflake模式算法取自twitter开源的snowflake算法。如果不想使用该模式配置leaf。snowflake。enablefalse即可。配置zookeeper地址在leaf。properties中配置leaf。snowflake。zk。address,配置leaf服务监听的端口leaf。snowflake。port。简单使用创建数据库,通过源码根目录下的scripts的leafalloc。sql导入数据库表leafalloc
  初始化数据,设置步长为2000,每次重启重新获取为下一个号段起始值INSERTINTOleafalloc(biztag,maxid,step,DESCRIPTION)VALUES(itxs,1,2000,TestleafSegmentModeGetId)
  配置application。properties中的数据库信息,将leaf。segment。enable设置为true或者注释;配置zookeeper信息,leaf。snowflake。enable设置为true或者注释;启动leafserverSpringBoot启动类
  访问号段模式http接口地址:http:localhost:8080apisegmentgetitxs
  访问雪花算法的http接口地址:http:localhost:8080apisnowflakegettest
  访问监控页面地址:http:localhost:8080cache
  我们再使用上一小节的工程项目先简单通过将leaf的core模块源码工程引入,使用号段模式,通过AutowiredSegmentIDGenImpl主动注入leaf号段模式实现类,并完成httpgetSegment测试接口的controllerpackagecom。itxs。uiddemo。controller;importjavax。annotation。Resource;importorg。springframework。beans。factory。annotation。Autowired;importorg。springframework。web。bind。annotation。GetMapping;importorg。springframework。web。bind。annotation。PathVariable;importorg。springframework。web。bind。annotation。RequestMapping;importorg。springframework。web。bind。annotation。RestController;importcom。baidu。fsg。uid。UidGenerator;importcom。sankuai。inf。leaf。Result;importcom。sankuai。inf。leaf。segment。SegmentIDGenImpl;RestControllerRequestMapping(valueuid)publicclassUidController{Resource(namecachedUidGenerator)privateUidGeneratorcachedUidGenerator;AutowiredprivateSegmentIDGenImplidGen;GetMapping(snowflake)publicStringsnowflake(){returnString。valueOf(this。cachedUidGenerator。getUID());}GetMapping(valuesegment{key})publicResultLonggetSegment(PathVariable(key)Stringkey)throwsException{returnthis。idGen。get(key);}}
  启动SpringBoot程序,访问http:localhost:8080uidsegmentitxs,返回data字段就是uid值,每次刷新1
  重新启动后,再次访问http:localhost:8080uidsegmentitxs,返回data字段1001,也即是新的号段的起始值,数据库的maxid也变为1001
  当然也可以采用SpringBootStartser方式使用,官网也有相关的说明
  我们自己下载leafstarter整合SpringBoot制作启动器starter源码进行编译
  编译好leafbootstarter后我们新建一个SpringBootdemo工程,由于原来封装是基于SpringBoot早期的版本,高版本不兼容,所以用早期版本,由于leafbootstarter里面使用zookeeper的客户端curator,我们直接运行是出现curator的某些类找不到,因此我们简单就直接在工程加入curatorframework和curatorrecipes的依赖。pom文件lt;?xmlversion1。0encodingUTF8?projectxmlnshttp:maven。apache。orgPOM4。0。0xmlns:xsihttp:www。w3。org2001XMLSchemainstancexsi:schemaLocationhttp:maven。apache。orgPOM4。0。0http:maven。apache。orgxsdmaven4。0。0。xsdmodelVersion4。0。0modelVersiongroupIdcom。itxsgroupIdleafspringbootdemoartifactIdversion1。0SNAPSHOTversionparentspringbootstarterparentartifactIdgroupIdorg。springframework。bootgroupIdversion2。0。3。RELEASEversionparentpropertiesmaven。compiler。source8maven。compiler。sourcemaven。compiler。target8maven。compiler。targetpropertiesdependenciesdependencygroupIdorg。springframework。bootgroupIdspringbootstarterwebartifactIddependencydependencygroupIdcom。sankuai。inf。leafgroupIdleafbootstarterartifactIdversion1。0。1RELEASEversiondependencydependencygroupIdorg。apache。curatorgroupIdcuratorframeworkartifactIdversion5。2。0versiondependencydependencygroupIdorg。apache。curatorgroupIdcuratorrecipesartifactIdversion5。2。0versiondependencydependenciesproject在classpath也即是resource根目录下新建leaf。properties文件,同时开启号段模式和雪花算法,配置信息如下leaf。namecom。sankuai。leaf。opensource。testleaf。segment。enabletrueleaf。segment。urljdbc:mysql:192。168。3。117:3306leaf?autoReconnecttrueuseUnicodetruecharacterEncodingUTF8leaf。segment。usernameleafleaf。segment。passwordleaf123leaf。snowflake。enabletrueleaf。snowflake。address192。168。3。117leaf。snowflake。port2181新建一个controller用于测试,提供号段和雪花算法测试接口packagecom。itxs。controller;importcom。sankuai。inf。leaf。common。Result;importcom。sankuai。inf。leaf。service。SegmentService;importcom。sankuai。inf。leaf。service。SnowflakeService;importorg。springframework。beans。factory。annotation。Autowired;importorg。springframework。web。bind。annotation。GetMapping;importorg。springframework。web。bind。annotation。PathVariable;importorg。springframework。web。bind。annotation。RequestMapping;importorg。springframework。web。bind。annotation。RestController;RestControllerRequestMapping(valueuid)publicclassLeafUidController{AutowiredprivateSegmentServicesegmentService;AutowiredprivateSnowflakeServicesnowflakeService;GetMapping(snowflake)publicStringsnowflake(){returnString。valueOf(this。snowflakeService。getId(test));}GetMapping(valuesegment{key})publicResultgetSegment(PathVariable(key)Stringkey)throwsException{returnthis。segmentService。getId(key);}}新建SpringBoot启动类,在启动类上标注EnableLeafServer开启LeafServer的注解,启动SpringBoot程序,默认是使用8080端口packagecom。itxs;importcom。sankuai。inf。leaf。plugin。annotation。EnableLeafServer;importorg。springframework。boot。SpringApplication;importorg。springframework。boot。autoconfigure。SpringBootApplication;SpringBootApplicationEnableLeafServerpublicclassLeafApplication{publicstaticvoidmain(String〔〕args){SpringApplication。run(LeafApplication。class,args);}}
  访问号段uid获取接口:http:localhost:8080uidsegmentitxs,放回id结果如下
  访问雪花算法uid获取接口:http:localhost:8080uidsnowflake,返回id结果如下
  滴滴(TinyID)概述
  官方GitHub地址https:github。comdiditinyid
  Tinyid是用Java开发的一款分布式id生成系统,基于数据库号段算法实现,关于这个算法可以参考美团leaf或者tinyid原理介绍。Tinyid扩展了leafsegment算法,支持了多db(master),同时提供了javaclient(sdk)使id生成本地化,获得了更好的性能与可用性。Tinyid在滴滴客服部门使用,均通过tinyidclient方式接入,每天生成亿级别的id。性能http方式访问,性能取决于httpserver的能力,网络传输速度javaclient方式,id为本地生成,号段长度(step)越长,qps越大,如果将号段设置足够大,则qps可达1000w可用性依赖db,当db不可用时,因为server有缓存,所以还可以使用一段时间,如果配置了多个db,则只要有1个db存活,则服务可用使用tinyclient,只要server有一台存活,则理论上可用,server全挂,因为client有缓存,也可以继续使用一段时间特性全局唯一的long型id趋势递增的id,即不保证下一个id一定比上一个大非连续性提供http和javaclient方式接入支持批量获取id支持生成1,3,5,7,9。。。序列的id支持多个db的配置,无单点
  适用场景:只关心id是数字,趋势递增的系统,可以容忍id不连续,有浪费的场景
  不适用场景:类似订单id的业务(因为生成的id大部分是连续的,容易被扫库、或者测算出订单量)推荐使用方式tinyidserver推荐部署到多个机房的多台机器多机房部署可用性更高,http方式访问需使用方考虑延迟问题推荐使用tinyidclient来获取id,好处如下:id为本地生成(调用AtomicLong。addAndGet方法),性能大大增加client对server访问变的低频,减轻了server的压力因为低频,即便client使用方和server不在一个机房,也无须担心延迟即便所有server挂掉,因为client预加载了号段,依然可以继续使用一段时间注:使用tinyidclient方式,如果client机器较多频繁重启,可能会浪费较多的id,这时可以考虑使用http方式推荐db配置两个或更多:db配置多个时,只要有1个db存活,则服务可用多db配置,如配置了两个db,则每次新增业务需在两个db中都写入相关数据原理和架构tinyid是基于数据库发号算法实现的,简单来说是数据库中保存了可用的id号段,tinyid会将可用号段加载到内存中,之后生成id会直接内存中产生。可用号段在第一次获取id时加载,如当前号段使用达到一定量时,会异步加载下一可用号段,保证内存中始终有可用号段。(如可用号段11000被加载到内存,则获取id时,会从1开始递增获取,当使用到一定百分比时,如20(默认),即200时,会异步加载下一可用号段到内存,假设新加载的号段是10012000,则此时内存中可用号段为2001000,10012000),当id递增到1000时,当前号段使用完毕,下一号段会替换为当前号段。依次类推。
  nextId和getNextSegmentId是tinyidserver对外提供的两个http接口nextId是获取下一个id,当调用nextId时,会传入bizType,每个bizType的id数据是隔离的,生成id会使用该bizType类型生成的IdGenerator。getNextSegmentId是获取下一个可用号段,tinyidclient会通过此接口来获取可用号段IdGenerator是id生成的接口IdGeneratorFactory是生产具体IdGenerator的工厂,每个biztype生成一个IdGenerator实例。通过工厂,我们可以随时在db中新增biztype,而不用重启服务IdGeneratorFactory实际上有两个子类IdGeneratorFactoryServer和IdGeneratorFactoryClient,区别在于,getNextSegmentId的不同,一个是DbGet,一个是HttpGetCachedIdGenerator则是具体的id生成器对象,持有currentSegmentId和nextSegmentId对象,负责nextId的核心流程。nextId最终通过AtomicLong。andAndGet(delta)方法产生。简单使用创建表导入源码根目录下面tinyidtinyidserverdb。sql的数据库脚本,两张表一张存储每个业务类型的token授权信息,一张存储业务类型ID的号段模式起始值和步长,通过version也即是数据库乐观锁实现原子操作。cdtinyidtinyidservercreatetablewithdb。sql(mysql)
  配置dbcdtinyidserversrcmainresourcesofflineviapplication。propertiesdatasource。tinyid。namesprimarydatasource。tinyid。primary。driverclassnamecom。mysql。jdbc。Driverdatasource。tinyid。primary。urljdbc:mysql:ip:portdatabaseName?autoReconnecttrueuseUnicodetruecharacterEncodingUTF8datasource。tinyid。primary。usernamerootdatasource。tinyid。primary。password123456启动tinyidserver将源码放在一个linux主机上,当然得有Jdk和Maven环境,在tinyidserver目录下执行脚本编译并启动编译好的jar包。并启动tinyidserver程序cdtinyidservershbuild。shofflinejavajaroutputtinyidserverxxx。jar
  或者将tinyid源码导入idea中,同样配置db,然后启动tinyidserver
  通过初始化sql脚本中的授权码和biztype,访问本地的RestApi接口测试,结果如下
  接下来我们使用基于java客户端的方式,这也是官方推荐的,性能最好,我们这里就直接使用客户端源码工程的测试代码导入MavendependencydependencygroupIdcom。xiaoju。uemc。tinyidgroupIdtinyidclientartifactIdversion{tinyid。version}versiondependency配置客户端信息tinyidclient。propertiestinyid。serverlocalhost:9999tinyid。token0f673adf80504e2eaa552f5d791b644c(tinyid。serverlocalhost:9999gateway,ip2:port2prefix,。。。)编写代码,test为业务类型LongidTinyId。nextId(test);ListLongidsTinyId。nextId(test,10);
  我们再看数据库表的信息,发现maxid已经变为200001,也即是每个客户端通过步长申请号段放在内存中,然后更新数据库表为下一次申请id段的起始值
  看到这里,以后如果遇到需要使用分布式ID的场景,你会选择和使用了吗?

看山西古代民族融合看发展之轨迹如今的山西是仅次于江西省汉民族比例最高的省份,山西作为北部省份也是中华文明的发源地之一。其中的汾河平原孕育出了灿烂而又独特的三晋文化,同时山西自古是多民族聚居融合之地。剥……水西彝族土司后裔安健安健是贵州最大的一个部水西部的彝族土司后裔,少年时在安顺府上私塾,曾考起秀才。在贵阳学习期间,受到了民主革命的思想熏陶,并亲眼目睹了清朝官吏的贪污腐败及对民残暴,预谋反清活动,……藏族的文字是谁创造的?我们藏族同胞的文字,是谁创造的呢?藏文字的来历,是这样的:公元7世纪的时候,西藏这个地方,是一个强大的帝国,名叫吐蕃帝国。吐蕃帝国的皇帝,名叫干布。对,就是娶……大放异彩的古代游牧民族回望鲜卑之一文:建宇打开中华民族绵长厚重、悠远绚烂的历史文化画卷,作为迭兴迭衰的草原族群之一鲜卑族群无疑留下了浓重墨彩的一笔。晋室东迁,衣冠南渡,北方中国便陷入长期的纷乱状态中,史称……抗日战争胜利了吗抗日战争中国真的赢了吗?为何日本不肯谢罪甚至其政要多不承认侵略?为何中国要放弃对日本要求赔款?为什么有钓鱼岛争执?为什么作为战胜国的中国领土损失面积比战败国日本还大?抗日……解放战争时期鲜为人知的十纵曾充当刘邓大军的辎重队刘邓大军老战士侯洪恩回忆录之二十五口述侯洪恩;整理玉河微澜1947年8月,刘邓大军千里挺进大别山,由于是没有后勤后勤保障的一次战略进攻,出发时虽然自身携带了大量给养……黑人为何在中国越来越多,我们又该如何应对呢?看看日本的做法人们习惯从肤色将人类分成三大人种,黄种人也就是我们的模样,白种人也就是欧美,而黑人则是非洲等地的人种。因为非洲常年处于赤道直射,所以肤色焦黑,因为这可以防止紫外线的伤害。……为何日军在中国打仗时,如同禽兽一样?看看他们的妻子就知道了如果说中国现代是一首高昂向上的赞歌,那么中国近代一定是一首慢声低吟的苦诗。中国近代时期,日寇发动九一八事变后,开始逐步侵占中国。而我国人民奋勇反抗,书写一篇篇不朽传奇。当……张爱玲在美国凄凉离世,弟弟却每天大敞房门我不想重蹈她的覆辙张子静晚年1995年9月8日,张爱玲死在洛杉矶西木区寓所,直到一周后才被人发现,享年75岁。这位在文坛中独领风骚的才女晚景如此凄凉,不禁令人唏嘘。她的弟弟在姐……浙江省唯一!这位女教授取得重大科研进展,获批国家级重点立项近日,国家体育总局公布了2022年决策咨询研究项目立项名单,浙大城市学院传媒与人文学院郭晴教授的课题国际大型赛事舆情应对研究获重点项目立项,系浙江省唯一获评重点立项的高校。此前……Saylor表示比特币正在获胜Saylor指出,自从MicroStrategy将其列为国库资产以来,比特币的表现优于所有其他主要资产类别。在MicroStrategy(MSTR)第三季度财报电话会议上……华为P50系列价格再次刷新解读配置后,竞争价值还大吗?不可否认,即使外界重压,华为品牌依旧自带buff加成,每次带来新品或者是新功能的时候都会被用户进行追捧,认为其核心技术又进行了一定程度的上升。但是,华为发布4G产品之后还……
怀孕哪个阶段,胎宝长得快?孕期多喝3款汤,促进胎宝大脑发育若问什么事情带给人最大的希望,两道杠一定能上榜。像我第一次怀孕就特别地激动和期待,想着自己终于有孩子了,特别的兴奋。但怀胎十月也并不容易,孕期各种反应折磨着我,我又特别害怕孩子……老刀海南,服务意识很落伍行走笔记头条创作挑战赛【行走笔记】海南,只有知道自己的不足,并勇于改进,才可能不负国家的大力扶助,不负时代与时机!行走海南三叹之一:海南,服务意识很落伍武汉老刀……她是努尔哈赤的小妾,生下两个儿子,孙子被康熙下令绞杀说到努尔哈赤的后妃,我们比较熟悉的有元妃佟佳氏、继妃富察氏、侧妃叶赫那拉氏(孝慈高皇后)与大妃乌拉那拉氏,此外,努尔哈赤还有数位侧妃与庶福晋,共击16位后妃。其中有一位姓钮祜禄……老照片上的1983年中国,每一张都是满满的回忆80年代史学在新时期史学发展过程中有着重要的作用,1983年前后中国历史学的重要转变,对于新时期史学的发展更是有着承前启后的作用。1983年史学在承传建国后十七年史学的基础上,……春节老照片27张以前中国人是这样过年的上图是上世纪20年代的时候,在北京的街头,春节将到的时候人们纷纷在街上买年货。很是热闹。上图为上世纪40年代的时候,地点是南京的夫子庙,大家在过年的时候逛庙会,可以看到拉……天京迷案攻克金陵后,曾国荃是否侵吞了太平天国的巨额财富盛夏炽热的阳光里,空气中仍然弥漫着挥之不去的死尸恶臭,秦淮河畔的六朝烟雨,雕梁画栋的千年帝都,在炮火硝烟中化作了一片狼藉。同治三年(1864)六月廿五日,距离吉字营攻破太……原来,如果身边出现这三人三事,来年会更有福运古人有诗云:自古人皆望,年来又一年。一日可见昼夜更替,一月可见人间百态,一年可见四季轮转。时光匆匆流逝,春夏逐渐散去,晚秋不再,只见寒冬袭来。寒冬的到来,就证明岁末……伪满洲国发行的货币,你了解多少?前面我和大家聊了东北九省流通券,也就是以前的东北地区(东三省)在日本人投降以后,1945年开始发行的纸币。那么在日本人强占东北期间,东三省使用的是哪种货币呢?在日本……1983年美苏核战一触即发,一个男人抗压28分钟,成功拯救全二战结束后不久,美国和苏联这两大超级大国,迅速陷入到新一轮的比拼当中,竭力争夺世界第一霸主的地位。这场比拼旷日持久,直到苏联解体才正式结束。在近半个世纪的斗争中,美苏两国……苹果一个密码锁卖到548元适用MacStudio,五年保修苹果在去年3月发布了MacStudio主机,搭载M1MaxM1Ultra处理器,售价为14999起,为防止MacStudio被人撞掉或是丢失,日前苹果在官网上架了一款新品Ken……赵荣声潜伏卫立煌身边10年,对方突然问道我参加共产党行吗中国抗战史上有很多抗日英雄的名字,卫立煌却是其中一个特殊的存在。作为蒋介石手下的一员大将,然而他的政治立场却成谜。1938年国民党第一战区的司令卫立煌突然对秘书说到……出生率下滑婴配粉收入减少,2022年上半年飞鹤营收利润双降7月22日,中国飞鹤发布了上半年业绩预警,据公告,2022年上半年,飞鹤营收约为95亿元至98亿元人民币,同比减少约14。9到17。4;期内净利润约22亿元至25亿元,同比减少……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网