1、引言
很多人一想到IM应用开发,第一印象就是“长连接”、“socket”、“保活”、“协议”这些关键词,没错,这些确实是IM开发中肯定会涉及的技术范畴。
但,当你真正开始编写第一行代码时,最现实的问题实际上是“聊天消息ID该怎么生成?”这个看似微不足道的小事情。说它看似微不足道,是因为在IM里它太平常了,处处可见它的身影。不过,虽然看似微不足道,但实际却很重要,因为它的生成算法和生成策略的优劣在某种意义上来说,决定了你的IM应用层某些功能实现的难易度。
有签于此,即时通讯网专门整理了“IM消息ID技术专题”系列文章,希望能带给你对这个看似微小但却很重要的技术点有更深刻的理解和最佳实践思路。
本文是专题系列文章的第5篇,专门介绍百度开源的分布式消息ID生成器UidGenerator的算法逻辑、实现思路、重点源码解读等,或许能带给你更多的启发。
2、基本介绍
全局ID(常见的比如:IM聊天系统中的消息ID、电商系统中的订单号、外卖应用中的订单号等)服务是分布式服务中的基础服务,需要保持全局唯一、高效、高可靠性。有些时候还可能要求保持单调,但也并非一定要严格递增或者递减。
全局ID也可以通过数据库的自增主键来获取,但是如果要求QPS很高显然是不现实的。
UidGenerator(备用地址)工程是百度开源的基于Snowflake算法的唯一ID生成器(百度对Snowflake算法进行了改进),引入了高性能队列高性能队列disruptor中RingBuffer思想,进一步提升了效率。
UidGenerator是Java语言实现的,它以组件形式工作在应用项目中,支持自定义workerId位数和初始化策略,,从而适用于docker等虚拟化环境下实例自动重启、漂移等场景。
在技术实现上,UidGenerator有以下关键特性:
1)UidGenerator通过借用未来时间来解决sequence天然存在的并发限制;
2)采用RingBuffer来缓存已生成的UID, 并行化UID的生产和消费;
3)同时对CacheLine补齐,避免了由RingBuffer带来的硬件级「伪共享」问题。
基于以上技术特性,UidGenerator的单机压力测试数据显示,其QPS可高达600万。
依赖的环境:
1)Java8及以上版本(代码中使用了函数式编程语句等新特性,请见:uid-generator源码在线版);
2)MySQL(内置WorkerID分配器, 启动阶段通过DB进行分配; 如自定义实现, 则DB非必选依赖)。
以下是UidGenerator工程的相关资源:
1)完整源码地址:https://github.com/baidu/uid-generator
2)备用源码地址:https://github.com/52im/uid-generator
3)源码在线阅读:http://docs.52im.net/extend/docs/src/uid-generator/(推荐)
3、什么是Snowflake算法?
3.1 SnowFlake算法原理
友情提示:本节文字内容摘选自《IM消息ID技术专题(四):深度解密美团的分布式ID生成算法》一文,如果您想了解美团对于SnowFlake算法的理解和应用情况,可详细阅读之。
SnowFlake 算法,是 Twitter 开源的分布式 ID 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 ID。
这 64 个 bit 中,其中 1 个 bit 是不用的,然后用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 ID,12 bit 作为序列号。
SnowFlake的ID构成:
(本图引用自《IM消息ID技术专题(四):深度解密美团的分布式ID生成算法》)
SnowFlake的ID样本:
(本图引用自《IM消息ID技术专题(四):深度解密美团的分布式ID生成算法》)
给大家举个例子吧,如上图所示,比如下面那个 64 bit 的 long 型数字: