如何设计一个分布式环境下全局唯一的发号器
一、如何设计一个分布式环境下全局唯一的发号器
1、UUID
常见的方式。可以利用数据库也可以利用程序生成,一般来说全球唯一。
优点:
简单,代码方便。 生成ID性能非常好,基本不会有性能问题。 全球唯一,在遇见数据迁移,系统数据合并,或者数据库变更等情况下,可以从容应对。
缺点:
没有排序,无法保证趋势递增。 UUID往往是使用字符串存储,查询的效率比较低。 存储空间比较大,如果是海量数据库,就需要考虑存储量的问题。 传输数据量大 不可读。
2、数据库自增长序列或字段
最常见的方式。利用数据库,全数据库唯一。
优点:
简单,代码方便,性能可以接受。 数字ID天然排序,对分页或者需要排序的结果很有帮助。
缺点:
不同数据库语法和实现不同,数据库迁移的时候或多数据库版本支持的时候需要处理。 在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成。有单点故障的风险。 在性能达不到要求的情况下,比较难于扩展。 如果遇见多个系统需要合并或者涉及到数据迁移会相当痛苦。 分表分库的时候会有麻烦。
优化方案:
针对主库单点,如果有多个Master库,则每个Master库设置的起始数字不一样,步长一样,可以是Master的个数。比如:Master1 生成的是 1,4,7,10,Master2生成的是2,5,8,11 Master3生成的是 3,6,9,12。这样就可以有效生成集群中的唯一ID,也可以大大降低ID生成数据库操作的负载。
3、数据库sequence表以及乐观锁
我们可以单独设置一张表,来存储所有表的下一个主键的值,例如现在有A、B、C三个表,sequence表结构如下
表名(name) |
下一个主键(id) |
A |
10 |
B |
100 |
C |
500 |
然后,每当需要获取下一个主键值的时候,首先使用select语句获取主键,然后使用数据库的乐观锁机制去update这个sequence表,更新成功则说明获取主键成功,更新失败则说明存在并发,当前主键被别的机器抢走了,需要重新select出新的主键,载update。例如要获取表B的下一个主键,需要发送sql
select id from sequence where name=B//获得id=100,更新sequence表update sequence set id=id+1 where name=B and id=100
复制代码
优点:
操作简单,使用乐观锁可以提高性能 生成的id有序递增,连续 可适用于分布式环境,可以进行分库分表
缺点:
需要单独设置一张表,浪费存储空间 数据库更新比较频繁,写压力太大
改进方案:
可以将每次获取一个主键,改为每次获取500个或者更多,然后缓存再当前机器中,用完这500个后,再去请求数据库,做更新操作,可以减少数据库的读写压力,但是会造成主键的不连续
4、Redis生成ID
当使用数据库来生成ID性能不够要求的时候,我们可以尝试使用Redis来生成ID。这主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID。可以用Redis的原子操作 INCR和INCRBY来实现。
可以使用Redis集群来获取更高的吞吐量。假如一个集群中有5台Redis。可以初始化每台Redis的值分别是1,2,3,4,5,然后步长都是5。各个Redis生成的ID为:
A:1,6,11,16,21 B:2,7,12,17,22 C:3,8,13,18,23 D:4,9,14,19,24 E:5,10,15,20,25
这个,随便负载到哪个机确定好,未来很难做修改。但是3-5台服务器基本能够满足器上,都可以获得不同的ID。但是步长和初始值一定需要事先需要了。使用Redis集群也可以方式单点故障的问题。
另外,比较适合使用Redis来生成每天从0开始的流水号。比如订单号=日期+当日自增长号。可以每天在Redis中生成一个Key,使用INCR进行累加。
优点:
不依赖于数据库,灵活方便,且性能优于数据库。 数字ID天然排序,对分页或者需要排序的结果很有帮助。
缺点:
如果系统中没有Redis,还需要引入新的组件,增加系统复杂度。 需要编码和配置的工作量比较大。
5、Twitter的snowflflake算法
snowflflake 是 twitter 开源的分布式ID生成算法,其核心思想为,一个long型的ID:
- 41 bit 作为毫秒数 - 41位的长度可以使用69年
- 10 bit 作为机器编号 (5个bit是数据中心,5个bit的机器ID) - 10位的长度最多支持部署1024个节点
- 12 bit 作为毫秒内序列号 - 12位的计数顺序号支持每个节点每毫秒产生4096个ID序号
Snowflflake图示
算法单机每秒内理论上最多可以生成1000*(2^12),也就是400W的ID,完全能满足业务的需求。
snowflflake算法可以根据自身项目的需要进行一定的修改。比如估算未来的数据中心个数,每个数据中心的机器数以及统一毫秒可以能的并发数来调整在算法中所需要的bit数。
优点:
不依赖于数据库,灵活方便,且性能优于数据库。 ID按照时间在单机上是递增的。
缺点:
在单机上是递增的,但是由于涉及到分布式环境,每台机器上的时钟不可能完全同步,也许有时候也会出现不是全局递增的情况。
注:snowflake是一种流行的发号器,但是很难直接使用。推荐的发号器是vesta。
6、vesta
Vesta是一款通用的唯一流水号产生器,它具有全局唯一、粗略有序、可反解和可制造等特性,它支持三种发布模式:嵌入发布模式、中心服务器发布模式、REST发布模式,根据业务的性能需求,它可以产生最大峰值型和最小粒度型两种类型的ID,它的实现架构使其具有高性能,高可用和可伸缩等互联网产品需要的质量属性,是一款通用的高性能的发号器产品。
优点:
通用的唯一流水号产生器,它具有全局唯一、粗略有序、可反解和可制造等特性。 支持三种发布模式:嵌入发布模式、中心服务器发布模式、REST发布模式。 可以产生最大峰值型和最小粒度型两种类型的ID 具有高性能,高可用和可伸缩等互联网产品需要的质量属性 机器ID:总共可以有1024台服务器 粗略有序、可反解、可制造
基于Java开发,其体验地址 在此
注:vesta,暂时还没用过,等用到了再分享如何使用,优缺点等内容。
作者:llsydn
链接:
https://juejin.cn/post/7082212125908664356
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处
如何设计一个分布式环境下全局唯一的发号器相关推荐
- 全局唯一ID发号器的几个思路
标识(ID / Identifier)是无处不在的,生成标识的主体是人,那么它就是一个命名过程,如果是计算机,那么它就是一个生成过程.如何保证分布式系统下,并行生成标识的唯一与标识的命名空间有着密不可 ...
- 10.算法进阶之分布式篇——分布式环境下如何生成唯一ID——UUID
UUID--全局唯一ID--universally unique identifie. 一般来说常用的基于时间进行排序,因为时间是自然递增的.但是全局唯一ID的两个核心要求是: 全局唯一 粗略有序 在 ...
- 分布式数据库中全局唯一主键
[相关文章] <分布式数据库中全局唯一主键生成策略的设计与实现> <activiti5.10解决分布式集群部署的主键问题> <分布式环境下数据库主键方案> < ...
- 分布式环境下,互斥性与幂等性问题,分析与解决思路
欢迎关注方志朋的博客,回复"666"获面试宝典 随着互联网信息技术的飞速发展,数据量不断增大,业务逻辑也日趋复杂,对系统的高并发访问.海量数据处理的场景也越来越多.如何用较低成本实 ...
- 分布式--生成数据库全局唯一ID--方法/方案
原文网址:分布式--生成数据库全局唯一ID--方法/方案_IT利刃出鞘的博客-CSDN博客 简介 本文介绍分布式项目中如何生成全局的唯一ID,通常是将其作为数据库的主键来使用的. 生成全局唯一ID有这 ...
- 如何设计一个分布式ID生成器
应用场景(Scenario) 现实中很多业务都有生成唯一ID的需求,例如: 用户ID 微博ID 聊天消息ID 帖子ID 订单ID 需求(Needs) 这个ID往往会作为数据库主键,所以需要保证全局唯一 ...
- 如何设计一个分布式定时任务系统
以前在美团有crane可用,现在得自己考虑以下两种场景了: 1.定时任务指定集群中的一台机器执行 2.如何修改cron参数,且修改永久有效 当然直接用quartz来实现肯定最棒,但设计的配置太多,小公 ...
- C#session共享+redis_Shiro权限管理框架(二):Shiro结合Redis实现分布式环境下的Session共享...
精品推荐 国内稀缺优秀Java全栈课程-Vue+SpringBoot通讯录系统全新发布! Docker快速手上视频教程(无废话版)[免费] 作者:夜月归途 转载自: https://www.cnblo ...
- 分布式精华问答:分布式环境下如何保持数据一致性的?| 技术头条
分布式开发的时代实际上早已悄悄地成为了时代的主流,今天,我们就来看看关于分布式的精华问答吧! 1 Q:分布式系统中主要是用到了服务化,消息中间件,数据库拆分,便于横向扩展和维护,但分布式系统中的拆分的 ...
最新文章
- B - Networking - poj 1287
- 使用ViewBag传送数据从控制器至视图
- libevent-signal(2)
- 隧道接口工具airtun-ng
- 工控攻防演示——从外网到内网控制系统设备的入侵
- Field XXXX input value is longer than screen field-BDC
- boost::incremental_components用法的测试程序
- 基于java的打砖块游戏_cocos creator 制作的打砖块游戏
- Linux下如何手动搭建论坛?
- Python实现一键打开/关闭防火墙
- 200行Python实现简单的区块链系统
- list类型的extend与append方法
- 构建之法1,5,17章学习心得
- 53.创建线程_beginthread
- Python应用|绘制任意正态分布曲线
- 让你的专属博客更加漂亮
- Golang的高并发
- oracle常见日期函数
- 什么是小波?小波是什么?
- Android ListView 和 ***Adapter 从本地/网络获取歌曲列表