分布式发号器设计与实现


一. 概述

       分布式系统中很多场景都需要唯一标识,比如消息、订单号、券号等。服务化、分布式已成为当下系统开发的首选,高并发操作在数据存储时,需要一套id生成器服务,来保证分布式情况下全局唯一性,以确保系统的订单创建、交易支付等场景下数据的唯一性,否则将造成不可估量的损失.

二. 需求

  • 全局唯一

  • 高性能

  • 高可用

  • 趋势递增

  • 全局递增

三.常见方案&思路

1.UUID(Universally Unique Identifier)

       UUID 经由一定的算法机器生成,为了保证 UUID 的唯一性,规范定义了包括网卡 MAC 地址、时间戳、名字空间 (Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成 UUID 的算法(uuid实现也有多种版本).

特点:

  • 本地生成 ID,不需要进行远程调用,时延低,性能高

  • 长度固定128位,字段较长、无序、可读性差(不适合做db索引)

  • 并非绝对唯一,参考:https://www.zhihu.com/question/34876910#answer-31004674

场景:

  • 日志跟踪

  • 普通的唯一标识(message id)

2.基于数据库自增主键

       数据库递增主键是天然的递增“发号器”,每次插入数据即可获得递增id.

特点:

  • 实现简单,使用数据库已有的功能

  • 能够保证唯一性,能够保证递增性

  • 性能一般(每次访问DB)、可用性较差(主库挂了,数据一致性能以保证)

  • 单点、扩展性有待提升

3.基于数据库自增升级版V1

       为了解决单点问题和性能问题,可以采用多个数据库实例,每台机器设置不同的初始值,且步长和机器数相等.比如有两台机器。设置步长step为3,server1的初始值为1(1,4,7…)、server2的初始值为2(5,8,11…),server3则为(3,6,9…) 这样错开就可以得到唯一id.

特点:

  • 能够保证唯一性,能够保证趋势递增

  • 分布式,高可用

  • 性能一般(每次都写DB)、扩容麻烦(水平扩容后,步长和初始值都需要重新设置)

4.基于数据库自增升级版V2

        核心思想是批量获取id(segment),减少DB写次数,实操可有多种方式.参考美团公司级发号器leaf做法:

       首先设置字段maxId和step,每次批量取一定数量的可用ID在内存中,使用完后,再请求数据库重新获取下一批可用ID,每次获取的可用ID数量由step控制,实际业务中可根据使用速度进行配置step大小,同时增加一个业务标识字段,隔离各个业务系统的ID.

特点:

  • 大大降低数据库写压力,数据库不再是性能瓶颈,生成ID性能大幅度提高,因为获取一个可用号段后在内存中直接分配,相对于每次读取数据库性能提高了几个量级

  • 强依赖数据库,当数据库异常时整个系统不可用(DB短时间内挂了可以接受)

  • 单服务内id递增,多节点整体趋势递增,服务重启会导致id空洞

5. 基于缓存实现

       类似方案2,利用redis原子递增操作(incr)获取id.(17年酒店订单发号器:两套缓存+db兜底)

特点:

  • 全局递增

  • 高性能

  • 强依赖缓存、可靠性较低,需要兜底方案

6. 类snowflake算法

       snowflake核心思想是:一个long型的ID,使用其中41bit作为毫秒数,10bit作为机器编号,12bit作为毫秒内序列号,借鉴snowflake的思想,结合各业务逻辑和并发量,可以增加一些trick实现自己的分布式ID生成算法.

特点:

  • 41位的时间戳能够用到约69年,241 毫秒转换成时间为2039-9-7 23:47:35,如果机器数量较少机器标识可以人工处理, 12bit序列号表示单机每毫秒最大发号4096个

  • 性能高、扩展性强

  • 多台服务时钟同步可能会时钟回拨,这是snowflake算法要解决的问题( linux软件时间会随着服务器的长时间运行会出现漂移,最终会越来越不准确)

  • 闰秒问题(https://coolshell.cn/articles/7804.html) ,简单说几年会出现一次00:59秒持续2秒的情况

四.业界参考

1.美团leaf

       leaf实现了两套方案:基于数据库自增升级版V2和snowflake算法,目前代码没有开源,技术细节可以参考美团点评技术团队博文,讲的非常清楚,之前找leaf团队的同学要repository的时候,他们也说后续会开源.

2.支付宝Vesta

       Vesta基于snowflake算法做了改造,详情参考官方文档.



本作品由 zhans 创作,采用 CC BY-NC-SA 3.0 许可协议 进行许可。

Comments