分布式 ID 生成策略

  1. MongoDB  objectid数据库

    ObjectId 是"_id" 的默认类型。它设计成轻量型的,不一样的机器都能用全局惟一的同种方法方便地生成它。这是MongoDB 采用ObjectId,而不是其余比较常规的作法(好比自动增长的主键)的主要缘由,由于在多个服务器上同步自动增长主键值既费力还费时。MongoDB 从一开始就设计用来做为分布式数据库,处理多个节点是一个核心要求。后面会看到ObjectId 类型在分片环境中要容易生成得多。

    ObjectId 使用12 字节的存储空间,每一个字节两位十六进制数字,是一个24 位的字符串。因为看起来很长,很多人会以为难以处理。但关键是要知道这个长长的ObjectId 是实际存储数据的两倍长。


    若是快速连续建立多个ObjectId,会发现每次只有最后几位数字有变化。另外,中间的几位数字也会变化(要是在建立的过程当中停顿几秒钟)。这是ObjectId 的建立方式致使的。12 字节按照以下方式生成:
    服务器

    前4 个字节是从标准纪元开始的时间戳,单位为秒。这会带来一些有用的属性。时间戳,与随后的. 5 个字节组合起来,提供了秒级别的惟一性。
    因为时间戳在前,这意味着ObjectId 大体会按照插入的顺序排列。这对于某些方面颇有用,如将其做为索引提升效率,可是这个是没有保证的,仅仅是“大体”。
    这4 个字节也隐含了文档建立的时间。绝大多数驱动都会公开一个方法从ObjectId 获取这个信息。
    由于使用的是当前时间,不少用户担忧要对服务器进行时间同步。其实没有这个必要,由于时间戳的实际值并不重要,只要其老是不停增长就行了(每秒一次)。
    接下来的3 字节是所在主机的惟一标识符。一般是机器主机名的散列值。这样就能够确保不一样主机生成不一样的ObjectId,不产生冲突。
    为了确保在同一台机器上并发的多个进程产生的ObjectId 是惟一的,接下来的两字节来自产生ObjectId 的进程标识符(PID)。
    前9 字节保证了同一秒钟不一样机器不一样进程产生的ObjectId 是惟一的。后3 字节就是一个自动增长的计数器,确保相同进程同一秒产生的ObjectId 也是不同的。同一秒钟最多容许每一个进程拥有2563(16 777 216)个不一样的ObjectId并发

  2. @宇智波唐嫣     的实现方案 学习一下app

    目前我正在写的 ID 生成服务的基本思路是这样的:
    优势是逻辑简单,生成的 ID 短小,单个进程维护起来方便。缺点是知道生成的 ID 的上限(能够用很大的块部分解决)。
    分布式

    ID 生成服务管理多个不一样名字的 ID 池 (pool)。学习

        每种不一样类型的 ID 属于不一样的 ID 池,好比知乎会有用户 ID 池、回答 ID 池等等。spa

       每一个 ID 池由多个定长 ID 块 (block) 构成。设计

       每一个 ID 块包含一段连续的 ID,好比第一块是从 0~1023,第二块从 1024~2047,以此类推。日志

       每一个 ID 块并不彻底分配,而是按照一个给定的填充率 (fill ratio) 随机选择来分配,好比假设填充率是 50%,那么每一个 ID 块中只有大约一半的 ID 会被分配。也就是说每一个 ID 块是有随机空洞的。索引

        若是某个 ID 块中可用 ID 被分配完毕,服务会自动生成下一个新的 ID 块,并按照填充率去掉不可用 ID。生成新的 ID 块时须要记录下最后一个 ID 块的起始 ID。

        已经分配过的 ID 会写入一个 append-only 日志。新的 ID 块生成时会建立一个新的 append-only 日志(由于旧的已经不须要了)。

        服务从新启动的时候先拿到最后一个 ID 块的起始 ID,再读取 append-only 日志将已经分配过的 ID 剔除,再剔除掉部分未分配的 ID 以维持填充率。

         客户端发送请求访问 ID 生成服务。服务端返回 ID 作为回复。

相关文章
相关标签/搜索