首页 > 其他分享 >分布式唯一id生成器

分布式唯一id生成器

时间:2022-10-09 22:26:10浏览次数:48  
标签:方案 生成器 步长 id 并发 号段 ID 分布式

分布式唯一ID要求

  1. 唯一性:生成的ID全局唯一,在特定范围内冲突概率极小。
  2. 有序性:生成的ID按某种规则有序,便于数据库插入及排序递增
  3. 可用性:可保证高并发下的可用性, 确保任何时候都能正确的生成ID。
  4. 自主性:分布式环境下不依赖中心认证即可自行生成ID。
  5. 安全性:不暴露系统和业务的信息, 如:订单数,用户数等。

mysql方案

专门单库单表,用来生成id

优点:超级简单
缺点:单库单表,高并发支持不住,没有高可用,需要定期删除数据,不适合上生产。大数据低并发,用flickr的数据库唯一id生成方案。

UUID方案

优点:无压力
缺点:mysql会页分裂,查询效率低,不适合做分布式唯一id(其它场景的唯一id可以)

snowflake雪花id方案

核心思想,用long的64个bit位,最高位是0,41位放时间(最多可以用69年),10位放机器标识(最多1024台机器),12位放序号(每毫秒,每台机器,可以顺序生成4096个ID)

优点:高性能,高并发,分布式,可伸缩,可以保证局部递增
缺点:有很多生产问题需要自行处理,如时钟回拨问题,需要独立部署维护

Redis自增方案

核心思想:redis单线程,绝对有序自增;内存高性能,集群部署可以支持高并发高可用,根据集群找到机器并计算步长(如5台机器,初始值为1 2 3 4 5,步长自增为5,第一台存的值为1 6 11 16...第二台存的值为2 7 12 17...直到第5台机器是5 10 15 20)

优点:不需要额外开发,可以直接用公司提供的redis集群
缺点:客户端需要写死Redis机器数量,每次获取id都需要找到一台机器,然后根据步长去incrby,返回给系统;伸缩麻烦,抗不住不好改,需要改步长,id需要重新来搞,id方案不好搞

场景:一般不用,分库分表后,一万左右的并发,单机部署,但需要用主从同步+哨兵(异步备份,有id重复的问题)

时间戳+业务id的组合

核心思想:比如打车,时间戳+起点编号+车牌号;电商,时间戳+用户id,一般手点不会重复,还能加下单渠道、第一个商品id等等组合

优点:实现简单,没有额外成本,没有并发之类的扩容问题
缺点:有的场景会有小概率重复,有的场景没法组合成唯一id

场景:部分生产可用,能用尽量用。

flickr数据库mysql唯一id方案

原始方案

需要找一个库建一张表,作为id表

CREATE TABLE `uid_sequence` (  
  `id` bigint(20) unsigned NOT NULL auto_increment,  
  `stub` char(1) NOT NULL default '',  
  PRIMARY KEY  (`id`),  
  UNIQUE KEY `stub` (`stub`)  
) ENGINE=MyISAM;


REPLACE INTO uid_sequence (stub) VALUES ('test');  
SELECT LAST_INSERT_ID();  

REPLACE INTO 表里只有一行数据,LAST_INSERT_ID是connection级别,所以select在多个客户端之间不会有问题

支持多业务的优化点,可以把 value 的值作为一个值(业务字段),那么可以select id from table where stub=业务字段,就可以对每个业务有自己的全局自增id

mysql必须双机,主从,高可用方案,两个库的要设置不同的起始位置和步长,保证两个库的id唯一

优点:高可用,表数据量小,多业务
场景:低并发场景

flickr相对高并发变种方案

阿里有一个TDDL中间件的唯一ID生成方案,思想也是号段思想。
mysql获取的只是号段,每个号段有一定范围,如1代表1-1000,2代表1000-2000……
每台服务启动后,先获取mysql的号段,用AtomLong来自增,当超过了最大值,就重新获取号段

缺点:没有自增到最大id,会浪费,需要做号段本地持久化。再特殊高并发场景下,数据库还是扛不住,比如1000为步长,每秒有1000的并发,相当于每秒都需要取数据库获取号段。数据库难以扩容。

snowflake 雪花id方案的优化

示例代码,就是位运算,网上有很多

机器id的获取

通过zk,比如给一个顺序节点,分布式id服务启动后就获取,获取到可以持久化到本地磁盘上。在扩容后就重新获取。

时钟回拨问题解决

当发生时钟回拨时,回拨时间

  1. 1s以内,在本机内存中存储1秒内每一毫秒生成的所有的id,回到多少秒就根据原来的记录递增
  2. 1-10s,返回请求其它的状态码,让客户端去请求其它机器
  3. 10s以上,主动注册中心下线该节点,等恢复了再重新注册

服务宕机解决

异步持久化,是一个方案,但是过于麻烦,可靠性不好,最好的方案是:
通过zk重新生成一个机器码。

标签:方案,生成器,步长,id,并发,号段,ID,分布式
From: https://www.cnblogs.com/richardhaha/p/16770985.html

相关文章

  • Terms in Autosar -MemMap File / IDT / Ports & Port Interfaces
    MemMapFileMemMapfileisa headerfile (MemMap.h)usedtomapfunctionsorvariablestospecificmemorylocationsinFlashmemoryorRAM,toavoidwastage......
  • 《C语言 —— void*的作用》
    1.void*类型指针void指针可以指向任意类型的数据,就是说可以用任意类型的指针对void指针对void指针赋值。int*a;void*p;p=a;a=(int*)p 如果要将void指针......
  • Android进阶笔记-7. Context详解
    Context数量Activity数量+Service数量+1(1为Application)Context的继承关系Context下有两个子类,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现......
  • Android——application全局类的使用
    目录 ​​1.概述​​​​2.Application基类​​​​3.自定义Application类​​​​4.Application的生命周期​​​​5.Application对象的回调函数​​​​6.Application对......
  • Android日志的过滤方法
    Android应用启动之后,有时候根据项目需要,我们只需要指定的日志,过滤掉多余的日志,方式如下......
  • Mybatis——plus 代码生成器
    MybatisPlus 给我们提供了更加强大的代码生成器  ## 代码生成器的简单的对比  MybatisPlus 给我们提供的代码生成器,不仅仅可以生成dao层,还可以生成 Service层,Cont......
  • The valid characters are defined in RFC 7230 and RFC 3986
    Invalidcharacterfoundintherequesttarget.ThevalidcharactersaredefinedinRFC7230andRFC3986@BeanpublicConfigurableServletWebServerFactorywebSe......
  • Raid
    Raid:独立冗余磁盘阵列Raid0:多块物理硬盘绑在一起,数据分成几块写入各个物理硬盘中。读写性能提高数倍。任意一块坏了就全部坏了Raid1:镜像,增加数据的安全性,但是可利用率只......
  • IDEA中的实体类能不能不写get set还有toString
    使用一个插件:先安装在pom文件里边添加依赖<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>在实......
  • springboot——数据访问——Druid&配置数据源监控
     在开发中会用Druid,因为它有成套的数据源监控想要使用需要做以下的操作: 在pom文件中引入依赖在application.yml里边添加配置想要在yml里边配置更多,则需要: 但是这并不能起......