[java] 分布式id生成方案
1、UUID
实现方式
String uuid = UUID.randomUUID().toString().replaceAll("-","");
优点:
- 生成简单,本地生成无网络消耗,具有唯一性
缺点:
- 无序的字符串,不具备趋势自增特性
- 没有具体的业务含义
- 长度过长,存储以及查询对MySQL的性能消耗较大。
2、数据库自增id
实现方式
需要一个单独的MySQL表用来生成ID
CREATE DATABASE `SEQ_ID`;
CREATE TABLE SEQID.SEQUENCE_ID (id bigint(20) unsigned NOT NULL auto_increment, stub char(10) NOT NULL default '',PRIMARY KEY (id),UNIQUE KEY value(stub)
) ENGINE=MyISAM;begin:
replace into SEQUENCE_ID(stub) VALUES('anyword');
select last_insert_id();
commit;
优点:
- 实现简单,ID单调自增,数值类型查询速度快
缺点:
- DB单点存在宕机风险,无法扛住高并发场景
那如果采用基于数据库的主从或者多主模式,就能够解决上面的高并发场景了吗,答案是否定的
问题
- 主从复制间存在延时,主机刚刚插入一个新的id,还没有同步到从机就挂机了。从机变为主机后会生成重复id
- 多主模式下要设置起始值和自增步长,且不利于后续扩容,而且实际上单个数据库自身压力还是大,依旧无法满足高并发场景。
3、基于数据库的号段模式
号段模式是当下分布式ID生成器的主流实现方式之一,号段模式可以理解为从数据库批量的获取自增ID,每次从数据库取出一个号段范围,例如 (1,1000] 代表1000个ID,具体的业务服务将本号段,生成1~1000的自增ID并加载到内存。表结构如下:
CREATE TABLE id_generator (id int(10) NOT NULL,max_id bigint(20) NOT NULL COMMENT '当前最大id',step int(20) NOT NULL COMMENT '号段的步长',biz_type int(20) NOT NULL COMMENT '业务类型',version int(20) NOT NULL COMMENT '版本号',PRIMARY KEY (`id`)
)
- biz_type :代表不同业务类型
- max_id :当前最大的可用id
- step :代表号段的长度
- version :是一个乐观锁,每次都更新version,保证并发时数据的正确性
等这批号段ID用完,再次向数据库申请新号段,对max_id字段做一次update操作,update max_id= max_id + step
,update成功则说明新号段获取成功,新的号段范围是(max_id ,max_id +step]。
update id_generator set max_id = #{max_id+step}, version = version + 1 where version = # {version} and biz_type = XXX
由于多业务端可能同时操作,所以采用版本号version乐观锁方式更新,这种分布式ID生成方式不强依赖于数据库,不会频繁的访问数据库,对数据库的压力小很多
4、基于Redis模式
Redis也同样可以实现,原理就是利用redis的 incr命令实现ID的原子性自增。
优点:
- 不依赖于数据库,灵活方便,且性能优于数据库。
- 数字ID天然排序,对分页或者需要排序的结果很有帮助。
缺点:
如果系统中没有Redis,还需要引入新的组件,增加系统复杂度。
防止redis挂机需要配置集群,RDB方式会有延时,而AOF恢复的时间较长(要执行较多的incr命令)
5、雪花算法(Snowflake)模式
Snowflake生成的是Long类型的ID,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特。
- 第一个bit位(1bit):代表正负,正数是0,负数是1,默认为0。
- 时间戳部分(41bit):毫秒级的时间,(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位大概使用69年
- 工作机器id(10bit):机房或者机器号组合都可以。
- 序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID
优点:
- 不依赖于数据库,灵活方便,且性能优于数据库。
- ID按照时间在单机上是递增的。
缺点:
- 在单机上是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可能完全同步,也许有时候也会出现不是全局递增的情况。
6、百度的uid-generator
uid-generator是基于Snowflake算法实现的,与原始的snowflake算法不同在于,uid-generator支持自定义时间戳、工作机器ID和 序列号 等各部分的位数,而且uid-generator中采用用户自定义workId的生成策略。
workId,占用了22个bit位。需要与数据库配合使用,需要新增一个WORKER_NODE表。当应用重启时会向数据库表中去插入一条数据,插入成功后返回的自增ID就是该机器的workId,应用运行时workId不变
时间占用了28个bit位,时间的单位改成了秒
序列化占用了13个bit位
解决时钟回拨问题
- synchronized保证线程安全;
- 如果时间有任何的回拨,那么直接抛出异常;
- 如果当前时间和上一次是同一秒时间,那么sequence自增。如果同一秒内自增值超过2^13-1,那么就会自旋等待下一秒(getNextSecond);
- 如果是新的一秒,那么sequence重新从0开始;
7、美团(Leaf)
美团的Leaf也是一个分布式ID生成框架。它非常全面,即支持号段模式,也支持snowflake模式。号段模式这里就不介绍了,和上面的分析类似。
Leaf中的snowflake模式和原始snowflake算法的不同点,也主要在workId的生成,Leaf中workId是基于ZooKeeper的顺序Id来生成的,每个应用在使用Leaf-snowflake时,在启动时都会都在Zookeeper中生成一个顺序Id,相当于一台机器对应一个顺序节点,也就是一个workId。
[java] 分布式id生成方案相关推荐
- 面试官:你会几种分布式 ID 生成方案???
1. 为什么需要分布式 ID 对于单体系统来说,主键 ID 常用主键自动的方式进行设置.这种 ID 生成方法在单体项目是可行的,但是对于分布式系统,分库分表之后就不适应了.比如订单表数据量太大了,分成 ...
- easyui treegrid获取父节点的id_超简单的分布式ID生成方案!美团开源框架介绍
目录 阐述背景 Leaf snowflake 模式介绍 Leaf segment 模式介绍 Leaf 改造支持 RPC 阐述背景 不吹嘘,不夸张,项目中用到 ID 生成的场景确实挺多.比如业务要做幂等 ...
- 超简单的分布式ID生成方案!美团开源框架介绍
目录 阐述背景 Leaf snowflake 模式介绍 Leaf segment 模式介绍 Leaf 改造支持 RPC 阐述背景 不吹嘘,不夸张,项目中用到 ID 生成的场景确实挺多.比如业务要做幂等 ...
- 常见分布式ID生成方案
文章目录 一.为什么要用分布式ID 1.什么是分布式ID 2.那么分布式ID需要满足哪些条件 二. 分布式ID有哪些生成方式 1.基于UUID 2.基于数据库自增ID 3.基于数据库集群模式 4.基于 ...
- 分布式 ID 生成方案
不管我们是不是有身份的人,我们一定是有身份证的人,身份证上面的号码就是我们的 ID,理论上这个 ID 是全国唯一的,而且通过这个号码,我们还可以得到一些个人信息,比如前两位可以确定我们第一次申请身份证 ...
- 分布式ID生成方案(二):SnowFlake雪花算法
雪花算法(SnowFlake) 是twitter公司内部分布式项目采用的ID生成算法,开源后广受国内大厂的好评,在该算法影响下各大公司相继开发出各具特色的分布式生成器. SnowFlake算法生成id ...
- 分布式ID详解(5种分布式ID生成方案)
分布式架构会涉及到分布式全局唯一ID的生成,今天我就来详解分布式全局唯一ID,以及分布式全局唯一ID的实现方案@mikechen 什么是分布式系统唯一ID 在复杂分布式系统中,往往需要对大量的数据和消 ...
- 一线大厂的分布式唯一ID生成方案是什么样的?
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 一.前言 分布式系统中我们会对一些数据量大的业务进行分拆,如:用户 ...
- 一起学习下一线大厂的分布式唯一ID生成方案!
来源 | http://www.toutiao.com/i6682672464708764174 一.前言 分布式系统中我们会对一些数据量大的业务进行分拆,如:用户表,订单表.因为数据量巨大一张表无法 ...
最新文章
- Ubuntu 及其衍生版安装使用录屏工具【SimpleScreenRecoder】
- Redis安装(CentOS7/tar.gz)
- 使用 gperf 实现高效的 C/C++ 命令行处理
- android自定义渐变色,Android设置背景渐变色
- Flask 蓝图机制及应用
- Django:ORM基本操作-CRUD,管理器对象objects,----->新增
- BaseRecyclerViewAdapterHelper: 灵活强大的循环适配器
- 量体裁衣:将DevOps转型融入到企业文化
- 34.了解那些算法要求使用排序的区间作为参数
- 《微处理器体系结构》1.1 汇编语言与机器语言及应用
- 关于Win10家庭版安装VirtualBox时的一些问题(e.g.报错2203)
- 一本通1645Fibonacci
- hdu-5761 Rower Bo(数学)
- 密码加盐原理及其实现
- 利用百度地图API接口自制地图
- 《Spring揭秘》读书笔记 3:Spring MVC
- CSS进阶-Less
- n-queens(n皇后问题)
- Flutter:加载本地Html、WebView与JS交互
- 终端连接工具Tabby的下载、安装与配置
热门文章
- 程序员的吐槽大会,动机何在?
- java计算机毕业设计后勤招标采购管理系统2021源码+mysql数据库+系统+lw文档+部署
- (转)CSS 基本知识
- Error: Could not create the Java Virtual Machine.Error: A fatal exception has occurred. Progra
- ssci源刊里有开源期刊吗_计算机类SCI检索源刊,期刊影响因子排名
- 工业企业数字化转型中的数据治理
- 几种图像颜色特征空间
- 被讨厌的勇气-思维导图
- 技术写作:如何编写软件文档
- 从零开始实现k线图走势图绘制(iOS理论篇)