业务系统需要什么样的ID生成器

业务系统需要什么样的ID生成器

ID 生成器在微博我们一直叫发号器,微博就是用这样的号来存储,而我微博里讨论的时候也都是以发号器为标签。它的主要目的确如平常大家理解的“为一个分布式系统的数据object产生一个唯一的标识”,但其实在一个真实的系统里可能也可以承担更多的作用。概括起来主要有以下几点:

  1. 唯一性
  2. 时间相关
  3. 粗略有序
  4. 可反解
  5. 可制造

下面我会分别讲每个作用后面的考虑和权衡,也会对比介绍一下业界已知的几种 ID 设计。

  1. 要唯一性,是否需要全局唯一?

    说起全局唯一,通常大家都会在想到发号器服务,分布式的通常需要更大空间,中心式的则需要在一个合适的地方在会聚。这就可能涉及到锁,而锁意味着成本和性能的下降。所以当前的系统是否需要全局的唯一性,就是一个需要考虑的问题。

    比如在通讯系统里,聊天消息可能就未必需要全局,因为一条消息只是某一个人发出,系统只要保证一个人维度的唯一性即可。本质上而言,这里利用了用户 ID 的唯一性,因为唯一性是可以依赖的,通常我们设计系统也都是基于类似的性质,比如后面降到的使用时间唯一性的方式。

  2. 用时间来做什么?千万年太久,只争朝夕?

    前面说到唯一性可以依赖,我们需要选择的是依赖什么。通常的做法可以选择数据库自增,这在很多数据库里都是可以满足ACID 的操作。但是用数据库有个缺点,就是数据库有性能问题,在多机房情况下也很难处理。当然,你可以通过调整自增的步长来设计,但对于一个发号器而言,操作和维护都略重了。

    而时间是天然唯一的,因此也是很多设计的选择。但对于一个8Byte的 ID 而言,时间并没有那么多。你如果精确到秒级别,三十年都要使用30bit,到毫秒级则要再增加10bit,你也只剩下20bit 可以做其他事情了。之所以在8Byte 上捣鼓,因为8Byte 是一个Long,不管在处理器和编译器还是语言层面,都是可以更好地被处理。

    然而三十年够么?对于一个人来说,可能不够,但对一个系统而言,可能足够。我们经常开玩笑,互联网里能活三十年的系统有多少呢?三十年过去,你的系统可能都被重写 N 遍了。这样的信心同样来自于摩尔定律,三十年后,计算性能早就提高了上千倍,到时候更多Byte 都不会是问题了。

  3. 粗略有多粗略,秒还是毫秒?

    每秒一个或者每毫秒一个ID明显是不够的,刚才说到还有20bit 可以做其他事情,就包括一个SequenceID。如果要达到精确的有序,就要对 Sequence 进行并发控制,性能上肯定会打折。所以经常会有的一个选择就是,在这个秒的级别上不再保证顺序,而整个 ID 则只保证时间上的有序。后一秒的 ID肯定比前一秒的大,但同一秒内可能后取的ID比前面的号小。这在使用时非常关键,你要理解,系统也要接受才可以。

    那时间用秒还是毫秒呢?其实不用毫秒的时候就可以把空出来的10bit 送给 Sequence,但整个ID 的精度就下降了。峰值速度是更现实的考虑。Sequence 的空间决定了峰值的速度,而峰值也就意味着持续的时间不会太久。这方面,每秒100万比每毫秒1000限制更小。

  4. 可反解,解开的是什么?

    一个 ID 生成之后,就会伴随着信息终身,排错分析的时候,我们需要查验。这时候一个可反解的 ID 可以帮上很多忙,从哪里来的,什么时候出生的。 跟身份证倒有点儿相通了,其实身份证就是一个典型的分布式 ID 生成器。

    如果ID 里已经有了时间而且能解开,在存储层面可能不再需要timestamp 一类的字段了。微博的 ID 还有很多业务信息,这个后面会细讲。

  5. 可制造,为什么不用UUID?

    互联网系统上可用性永远是优先指标。但由于分布式系统的脆弱,网络不稳定或者底层存储系统的不可用,业务系统随时面临着失败。为了给前端更友好的响应,我们需要能尽量容忍失败。比如在存储失败时,可能需要临时导出请求供后续处理,而后续处理时已经离开了当时的时间点,顺序跟其他系统错开了。我们需要制造出这样的ID 以便系统好像一直正常运行一样,可制造的 ID 让你可以控制生产日期(汗,有点儿假冒伪劣的意思了),然后继续下面的处理。

    另一个重要场景就是数据清洗。这个属于较少遇到,但并不罕见的情况,可能是原来 ID 设计的不合理,也可能由于底层存储的改变,都可能出现。这样一个可制造的 ID 就会带来很多操作层面的便利。

    这也是我们不用 UUID 的一个原因。UUID 标准可以保证在某时某地生成,但如果要控制生成一个特定时间的 UUID,可能需要底层库的改动。经验告诉我们,能在上层解决的问题不要透到下层,这种库的维护成本是非常高的。

设计细节

UUID 就不说了, 其他公开出来的这里说下SnowFlake、Weibo以及 Ticktick 的设计。

  1. SnowFlake

    41bit留给毫秒时间,10bit给MachineID,也就是机器要预先配置,剩下12位留给Sequence。代码虽然露出来了,但其实已经不可用了,据说是内部改造中。

  2. Weibo

    微博使用了秒级的时间,用了30bit,Sequence 用了15位,理论上可以搞定3.2w/s的速度。用4bit来区分IDC,也就是可以支持16个 IDC,对于核心机房来说够了。剩下的有2bit 用来区分业务,由于当前发号服务是机房中心式的,1bit 来区分热备。是的,也没有用满64bit。

  3. Ticktick

    也就是当前在环信系统里要用到的。使用了30bit 的秒级时间,20bit 给Sequence。这里是有个考虑,第一版实现还是希望到毫秒级,所以20bit 的前10bit给了毫秒来用,剩下10bit给 Sequence。等到峰值提高的时候可以暂时回到秒级。

    前面说到的三十年问题,因此我在高位留了2bit 做 Version,或者到时候改造使用更长字节数,用第一位来标识不同 ID,或者可以把这2bit 挪给时间用,可以给系统改造留出一定的时间。

    剩下的10bit 留给 MachineID,也就是说当前 ID 生成可以直接内嵌在业务服务中,最多支持千级别的服务器数量。最后有2bit 做Tag 用,可能区分群消息和单聊消息。同时你也看出,这个 ID 最多支持一天10亿消息,也是怕系统增速太快,这2bit 可以挪给 Sequence,可以支持40亿级别消息量,或者结合前面的版本支持到百亿级别。

    修正:评论里指出上面一个计算错误,不挪借的话应该是支持一天约千亿级别。对比当前 Whatsapp 的600亿和腾讯 QQ 的200亿,已经足够了。

后记

自己实现一个发号器非常简单,所以Ticktick 怎么实现并不重要。不过呐,我还是有 demo 源码的,见https://github.com/ericliang/ticktick

如果你有其他想法,欢迎到微博来讨论@一乐

http://ericliang.info/what-kind-of-id-generator-we-need-in-business-systems/

时间: 2024-08-27 23:05:29

业务系统需要什么样的ID生成器的相关文章

业务系统需要怎样的全局唯一ID? #Ticktick#(环信首席架构师:一乐)

ID 生成器在微博我们一直叫发号器,微博就是用这样的号来存储,而我微博里讨论的时候也都是以发号器为标签.它的主要目的确如平常大家理解的"为一个分布式系统的数据object产生一个唯一的标识",但其实在一个真实的系统里可能也可以承担更多的作用.概括起来主要有以下几点: 1. 唯一性 2. 时间相关 3. 粗略有序 4. 可反解 5. 可制造 下面我会分别讲每个作用后面的考虑和权衡,也会对比介绍一下业界已知的几种 ID 设计. 1. 要唯一性,是否需要全局唯一? 说起全局唯一,通常大家都会

分布式全局ID生成器设计

项目是分布式的架构,需要设计一款分布式全局ID,参照了多种方案,博主最后基于snowflake的算法设计了一款自用ID生成器.具有以下优势: 保证分布式场景下生成的ID是全局唯一的 生成的全局ID整体上是呈自增趋势的,也就是说整体是粗略有序的 高性能,能快速产生ID,本机(I7-6400HQ)单线程可以达到每秒生成近40万个ID 只占64bit位空间,可以根据业务需求扩展在前缀或后缀拼接业务标志位转化为字符串. UUID方案 UUID:UUID长度128bit,32个16进制字符,占用存储空间多

zookeepeer ID生成器 (一)

目录 写在前面 1.1. ZK 的分布式命名服务 1.1.1. 分布式 ID 生成器的类型 UUID方案 1.1.2. ZK生成分布式ID 写在最后 疯狂创客圈 亿级流量 高并发IM 实战 系列 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之 -25[ 博客园 总入口 ] 写在前面 ? 大家好,我是作者尼恩.目前和几个小伙伴一起,组织了一个高并发的实战社群[疯狂创客圈].正在开始高并发.亿级流程的 IM 聊天程序 学习和实战 ? 前面,已经完成一个高性能的 Java 聊天程序的四件大

实现业务系统中的用户权限管理--实现篇

在设计篇中,我们已经为大家阐述了有关权限管理系统的数据库设计,在本篇中,我们将重点放在其实现代码部分.为了让你能够更直接更有效的看到全部动作的代码,我们使用"动作分解列表"的方式来陈述每个动作以及相关资源. 实现权限管理功能的动作 动作分解 动作名 相关表名 操作集类型 (S,U,I,D,SQL) 表单 模组 字符资源 是否分页? 返回提示? 权限检测 权限初始化安装 setup 无 无 无 setup setupok 否 否 否 显示添加管理组界面 addnewgroup 无 无 a

业务系统-呼叫中心二次开发(已完结)

一. 批量筛号: 1.输入:案件批次号 输出:该批次的所有电话号码(非有效状态),进行批量筛号,将未知状态的号码标志为有效和无效. 2.Table: Call_Filter_Task     =(Id, Step, Status, BatchId,  CateGoryId, TaskType, TotalNum, Creator, CreateTime, RunBeginTime, RunEndTime) Call_Filter_Send_Batch    = (Id, Status, Filt

银行综合储蓄业务系统,水平为学了一年C语言

银行综合储蓄业务系统 #include <stdio.h> #include<string.h> int acccunt = 0; char name[10],pw[10]; struct user   //定义结构体 { int ID; char userName[10]; char userPwd[10]; float money; int status;  // 状态 1:正常 2. 挂失 0:销户 }users[60]; int kk = 0; // 记录编号,和已添加用户

实现业务系统中的用户权限管理--设计篇

B/S系统中的权限比C/S中的更显的重要,C/S系统由于具有特殊的client,所以訪问用户的权限检測能够通过client实现或通过client+server检測实现,而B/S中,浏览器是每一台计算机都已具备的,假设不建立一个完整的权限检測,那么一个"非法用户"非常可能就能通过浏览器轻易訪问到B/S系统中的全部功能.因此B/S业务系统都须要有一个或多个权限系统来实现訪问权限检測,让经过授权的用户能够正常合法的使用已授权功能,而对那些未经授权的"非法用户"将会将他们彻

整合Activiti Modeler到业务系统(或BPM平台)

http://www.kafeitu.me/activiti/2013/03/10/integrate-activiti-modeler.html 1. 为什么要整合 Activiti 5.10版本把原本独立的Activiti Modeler模块整合到了Activiti Explorer中,两者相结合使用起来很方便,通过Modeler设计的流程模型可以直接部署到引擎,也可以把已经部署的流程转换为Model从而在Modeler中编辑. 在实际应用中也有这样的需求,把Modeler整合到业务系统中可

(转)业务系统实现记住密码和自动登录功能

公司的业务系统本来是受域控的,用户不需要登录可以直接访问系统.当然,虽然不用人工登录,系统本身会读取电脑的用户名为登录标识,对系统操作权限和记录也是以电脑名.近段时间,由于系统要牵到云端,也就是不受域控了,那就需要每人手头上都有账号和密码了,这个和一般的业务系统没什么区别.但是由于用户之前的习惯是不用登录的,而且每天打开关闭的次数较多.OK,一般的系统登录都会有个记住密码的功能,但是,这还满足不了用户的需求,那么我们给用户增加多一个自动登录功能,类似QQ那样,我上次访问勾选了自动登录功能,然后再