分布式唯一ID生成器
在应用程序中,经常需要全局唯一的ID作为数据库主键。如何生成全局唯一ID?
首先,需要确定全局唯一ID是整型还是字符串?如果是字符串,那么现有的UUID就完全满足需求,不需要额外的工作。缺点是字符串作为ID占用空间大,索引效率比整型低。
如果采用整型作为ID,那么首先排除掉32位int类型,因为范围太小,必须使用64位long型。
采用整型作为ID时,如何生成自增、全局唯一且不重复的ID?
方案一:利用数据库的自增ID,从1开始,基本可以做到连续递增。Oracle可以用SEQUENCE,MySQL可以用主键的AUTO_INCREMENT,虽然不能保证全局唯一,但每个表唯一,也基本满足需求。
数据库自增ID的缺点是数据在插入前,无法获得ID。数据在插入后,获取的ID虽然是唯一的,但一定要等到事务提交后,ID才算是有效的。有些双向引用的数据,不得不插入后再做一次更新,比较麻烦。
第二种方式是采用一个集中式ID生成器,它可以是Redis,也可以是ZooKeeper,也可以利用数据库的表记录最后分配的ID。
这种方式最大的缺点是复杂性太高,需要严重依赖第三方服务,而且代码配置繁琐。一般来说,越是复杂的方案,越不可靠,并且测试越痛苦。
第三种方式是类似Twitter的Snowflake算法,它给每台机器分配一个唯一标识,然后通过时间戳+标识+自增实现全局唯一ID。这种方式好处在于ID生成算法完全是一个无状态机,无网络调用,高效可靠。缺点是如果唯一标识有重复,会造成ID冲突。
Snowflake算法采用41bit毫秒时间戳,加上10bit机器ID,加上12bit序列号,理论上最多支持1024台机器每秒生成4096000个序列号,对于Twitter的规模来说够用了。
但是对于绝大部分普通应用程序来说,根本不需要每秒超过400万的ID,机器数量也达不到1024台,所以,我们可以改进一下,使用更短的ID生成方式:
53bitID由32bit秒级时间戳+16bit自增+5bit机器标识组成,累积32台机器,每秒可以生成6.5万个序列号,核心代码:
private static synchronized long nextId(long epochSecond) {
if (epochSecond < lastEpoch) {
// warning: clock is turn back:
logger.warn("clock is back: " + epochSecond + " from previous:" + lastEpoch);
epochSecond = lastEpoch;
}
if (lastEpoch != epochSecond) {
lastEpoch = epochSecond;
reset();
}
offset++;
long next = offset & MAX_NEXT;
if (next == 0) {
logger.warn("maximum id reached in 1 second in epoch: " + epochSecond);
return nextId(epochSecond + 1);
}
return generateId(epochSecond, next, SHARD_ID);
}
时间戳减去一个固定值,此方案最高可支持到2106年。
如果每秒6.5万个序列号不够怎么办?没关系,可以继续递增时间戳,向前“借”下一秒的6.5万个序列号。
同时还解决了时间回拨的问题。
机器标识采用简单的主机名方案,只要主机名符合host-1,host-2就可以自动提取机器标识,无需配置。
最后,为什么采用最多53位整型,而不是64位整型?这是因为考虑到大部分应用程序是Web应用,如果要和JavaScript打交道,由于JavaScript支持的最大整型就是53位,超过这个位数,JavaScript将丢失精度。因此,使用53位整数可以直接由JavaScript读取,而超过53位时,就必须转换成字符串才能保证JavaScript处理正确,这会给API接口带来额外的复杂度。这也是为什么新浪微博的API接口会同时返回id和idstr的原因。
分布式唯一ID生成器的更多相关文章
- 分布式唯一id生成器的想法
0x01 起因 前端时间遇到一个问题,怎么快速生成唯一的id,后来采用了hashid的方法.最近在网上读到了美团关于分布式唯一id生成器的解决方案, 其中提到了三种生成法:(建议看一下这篇文章,写得很 ...
- 百度开源的分布式唯一ID生成器UidGenerator,解决了时钟回拨问题
UidGenerator是百度开源的Java语言实现,基于Snowflake算法的唯一ID生成器.而且,它非常适合虚拟环境,比如:Docker.另外,它通过消费未来时间克服了雪花算法的并发限制.Uid ...
- 分布式唯一ID生成器Twitter
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种简单一 ...
- snowflake 分布式唯一ID生成器
本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn 摘要: 原文参考运维生存和开源中国上的代码整理 我的环境是pytho ...
- 分布式唯一id:snowflake算法思考
匠心零度 转载请注明原创出处,谢谢! 缘起 为什么会突然谈到分布式唯一id呢?原因是最近在准备使用RocketMQ,看看官网介绍: 一句话,消息可能会重复,所以消费端需要做幂等.为什么消息会重复后续R ...
- 分布式全局ID生成器设计
项目是分布式的架构,需要设计一款分布式全局ID,参照了多种方案,博主最后基于snowflake的算法设计了一款自用ID生成器.具有以下优势: 保证分布式场景下生成的ID是全局唯一的 生成的全局ID整体 ...
- 关于分布式唯一ID,snowflake的一些思考及改进(完美解决时钟回拨问题)
1.写唯一ID生成器的原由 在阅读工程源码的时候,发现有一个工具职责生成一个消息ID,方便进行全链路的查询,实现方式特别简单,核心源码不过两行,根据时间戳以及随机数生成一个ID,这种算法ID在分布式系 ...
- 分布式唯一ID生成方案选型!详细解析雪花算法Snowflake
分布式唯一ID 使用RocketMQ时,需要使用到分布式唯一ID 消息可能会发生重复,所以要在消费端做幂等性,为了达到业务的幂等性,生产者必须要有一个唯一ID, 需要满足以下条件: 同一业务场景要全局 ...
- 讲分布式唯一id,这篇文章很实在
分布式唯一ID介绍 分布式系统全局唯一的 id 是所有系统都会遇到的场景,往往会被用在搜索,存储方面,用于作为唯一的标识或者排序,比如全局唯一的订单号,优惠券的券码等,如果出现两个相同的订单号,对于用 ...
随机推荐
- 【GDOI2014模拟】雨天的尾巴
题目 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连 根拔起,以及田地里 ...
- 百度小程序 配置 app.json 文件
可以通过配置 app.json 文件,设置 SWAN 的界面.路径.多 TAB 等. app.json 配置项列表如下 属性 类型 必填 描述 pages Array.<string> 是 ...
- 用二叉树进行排序 x (从小到大)
先输入n,表示拥有多少个数: 第二行输入1-n个数,然后开始排序 输出从小到大的排序. ----------------------------------------------代码~------- ...
- Go实现分布式外部排序
Go实现分布式外部排序 项目路径: https://github.com/Draymonders/go_external_sort 默认读入文件: small.in 默认输出文件:small.out ...
- 【PowerOJ1738&网络流24题】最小路径覆盖问题 (最大流)
题意: 思路: [问题分析] 有向无环图最小路径覆盖,可以转化成二分图最大匹配问题,从而用最大流解决. [建模方法] 构造二分图,把原图每个顶点i拆分成二分图X,Y集合中的两个顶点Xi和Yi.对于原图 ...
- Android使用命令行操作数据库
所有的应用程序本地文件都存放在/data/data/目录下 C:\Users\nicole>adb shell * daemon not running. starting it now on ...
- Internet History, Technology, and Security(week4)——History: Commercialization and Growth
Explosive Growth of the Internet and Web: The Year of the Web 1994年后,由NCSA的老员工们构成的Netscape(网景)的成立.Ne ...
- 学习wavenet_vocoder之预处理、训练
一.预处理 1.在进行预处理时,如果不明白需要的参数,可以使用命令获取帮助,从这里我们可以看到可以具体的用法和对应的参数. python preprocess.py --help python pre ...
- JavaSE知识点:finalize,treeMap
*)finalize finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等. *)treeMap 参考 ...
- review star 评论-评分 文本分析
<!DOCTYPE html> Title 立项背景: 0-突然被限制,无法访问原amazon_asin_reviews_us数据库: 1-原数据库asin类别.厂家信息不明: 2-自然语 ...