im即时通讯消息id的设计
im即时通讯消息id的设计
消息id的特性
在im通讯中,消息的id在项目的功能实现中具有非常重要的作用。例如:消息接受顺序的保证,客户端消息重传时的去重,离线消息拉取的定位,以及消息幂等操作的判断等。因此消息id设计中,需要具备 递增
,唯一
消息id生成策略
对于递增、唯一有许多的设计策略,例如有:
主键自增:数据插入后不能获取消息id,需要再次查询获得插入的消息id
时间戳+UUID:长度太长,索引性能差。分布式下对时钟一致要求
雪花算法:使得高并发。但长度过长,可能出现丢失精度
使用redis自增
良好的消息id可使项目功能实现可为简洁,对此我参考的IM融云的消息id设计并对此进行的实现。
融云消息id的设计
融云消息id为16字符的字符串,字串中每个字符由5bit的数据编码而来,即消息id是由80bit的数据转换而来:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X4VVp4qh-1660895848977)(C:\Users\86139\AppData\Roaming\Typora\typora-user-images\image-20220819121831978.png)]
- 时间戳:最高位的时间戳保证了id的唯一性。相比于雪花算法41位时间戳,42位的时间戳延长使用到2019年保证了使用。
- 自旋ID:在高并发场景下,同一时间戳可能有多个消息id生成。自旋id对这一时刻的消息进行自增编号,避免id的重复。12bit最多可表示4096条消息
- 会话类型:即表示会话类型:单聊、群聊、客户、聊天室等
- 会话id:如群聊id,聊天室id等
消息id的实现
这里使用Java进行实现,由于Java中64bit的long并不能存储80bit的数据,所以要对80bit的数据进行分段:
- 64bit : 时间戳 42bit | 自旋ID 12bit | 会话类型4bit | 会话ID高位6bit
- 16bit:会话ID低位
前64bit获取
/*** @param type 会话类型* @param highCid 会话id高位6bit* @return 高位64bit数据*/private static long createHighBits(int type, int highCid) {long highBits = System.currentTimeMillis(); // 获取时间戳int spinId = createSpinId(); // 获取自旋id// 依次移位highBits = highBits<<12 | spinId; highBits = highBits<<4 | (type&0xF); highBits = highBits<<6 | (highCid&0x3F);return highBits;}
后16bit获取
long lowCid = (int) (cid&0xFFFF);
自旋ID获取
并发条件下,自旋ID获取要具有唯一性。这里采用AtomicInteger的cas机制获取
/*** 获取自旋id : 0 ~ 0xFFF(4095)*/private final static int SPIN_ID_LIMIT = 0xFFF; // 最高值限制private final static AtomicInteger INCR = new AtomicInteger(0); // 递增值private static int createSpinId() {int ret = INCR.getAndIncrement();if(INCR.get() >= SPIN_ID_LIMIT) {INCR.set(0);}return ret;}
编码
对两段数据进行32位编码(5bit > 1char
// 编码转为字符串:5 bit > 1 charprivate final static char[] CHS = {'2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};private static String createStrId(long highBit, long lowCid) {char[] arr = new char[16];int pos = 15;while(pos >= 0) {int tmp = 0;if(pos>=13) {tmp = (int) (lowCid&0x1F);lowCid>>=5;} else if(pos == 12) {tmp = (int) ((highBit&0xF)<<1 | lowCid);highBit >>= 5;} else {tmp = (int) (highBit&0x1F);highBit >>= 5;}arr[pos--] = CHS[tmp];}return new String(arr);}
测试
多个线程去获取消息id。判断是否具有递增,唯一,以及同一时刻获取的id是否唯一?
public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(10);for(int i=0; i<10; i++) {executorService.submit(new Runnable() {@Overridepublic void run() {for(int i=0; i<10; i++)log.debug("生成id : {}", createId(0xF,0x3FFFFF));}});}}
测试结果
16:14:46.557 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz4i22zzzzz
16:14:46.558 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz4n29zzzzz
16:14:46.562 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6a2czzzzz
16:14:46.562 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6a2dzzzzz
16:14:46.563 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2ezzzzz
16:14:46.563 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2fzzzzz
16:14:46.558 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz4n28zzzzz
16:14:46.558 [pool-1-thread-2] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz4i23zzzzz
16:14:46.563 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2gzzzzz
16:14:46.558 [pool-1-thread-5] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz4n26zzzzz
16:14:46.557 [pool-1-thread-8] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz522bzzzzz
16:14:46.558 [pool-1-thread-10] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz4n2azzzzz
16:14:46.557 [pool-1-thread-6] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz4n27zzzzz
16:14:46.557 [pool-1-thread-1] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz4i24zzzzz
16:14:46.557 [pool-1-thread-4] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz4i25zzzzz
16:14:46.563 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2izzzzz
16:14:46.563 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2hzzzzz
16:14:46.563 [pool-1-thread-4] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2szzzzz
16:14:46.563 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2tzzzzz
16:14:46.563 [pool-1-thread-2] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2jzzzzz
16:14:46.563 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2uzzzzz
16:14:46.563 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2wzzzzz
16:14:46.563 [pool-1-thread-4] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2vzzzzz
16:14:46.563 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2kzzzzz
16:14:46.563 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2yzzzzz
16:14:46.563 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2zzzzzz
16:14:46.563 [pool-1-thread-4] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e32zzzzz
16:14:46.563 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e35zzzzz
16:14:46.563 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e34zzzzz
16:14:46.563 [pool-1-thread-4] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e36zzzzz
16:14:46.563 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e37zzzzz
16:14:46.563 [pool-1-thread-5] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2mzzzzz
16:14:46.563 [pool-1-thread-8] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2nzzzzz
16:14:46.563 [pool-1-thread-4] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e39zzzzz
16:14:46.563 [pool-1-thread-10] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2pzzzzz
16:14:46.563 [pool-1-thread-5] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3bzzzzz
16:14:46.563 [pool-1-thread-8] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3czzzzz
16:14:46.563 [pool-1-thread-6] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2qzzzzz
16:14:46.563 [pool-1-thread-10] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3ezzzzz
16:14:46.563 [pool-1-thread-5] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3fzzzzz
16:14:46.563 [pool-1-thread-1] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2rzzzzz
16:14:46.563 [pool-1-thread-6] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3hzzzzz
16:14:46.563 [pool-1-thread-10] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3izzzzz
16:14:46.563 [pool-1-thread-5] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3jzzzzz
16:14:46.563 [pool-1-thread-1] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3kzzzzz
16:14:46.563 [pool-1-thread-2] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e2xzzzzz
16:14:46.563 [pool-1-thread-10] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3nzzzzz
16:14:46.563 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e33zzzzz
16:14:46.563 [pool-1-thread-1] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3qzzzzz
16:14:46.563 [pool-1-thread-10] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3szzzzz
16:14:46.563 [pool-1-thread-9] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e38zzzzz
16:14:46.563 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3tzzzzz
16:14:46.563 [pool-1-thread-1] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3uzzzzz
16:14:46.563 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3azzzzz
16:14:46.563 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3wzzzzz
16:14:46.563 [pool-1-thread-1] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3xzzzzz
16:14:46.563 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3yzzzzz
16:14:46.563 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3zzzzzz
16:14:46.563 [pool-1-thread-1] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e42zzzzz
16:14:46.563 [pool-1-thread-4] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3dzzzzz
16:14:46.563 [pool-1-thread-8] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3gzzzzz
16:14:46.564 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i44zzzzz
16:14:46.563 [pool-1-thread-6] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3mzzzzz
16:14:46.563 [pool-1-thread-5] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3pzzzzz
16:14:46.563 [pool-1-thread-2] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3rzzzzz
16:14:46.563 [pool-1-thread-10] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e3vzzzzz
16:14:46.564 [pool-1-thread-5] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i4azzzzz
16:14:46.564 [pool-1-thread-7] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6e43zzzzz
16:14:46.564 [pool-1-thread-10] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i4czzzzz
16:14:46.564 [pool-1-thread-1] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i45zzzzz
16:14:46.564 [pool-1-thread-4] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i46zzzzz
16:14:46.564 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i48zzzzz
16:14:46.564 [pool-1-thread-8] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i47zzzzz
16:14:46.564 [pool-1-thread-4] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i4gzzzzz
16:14:46.564 [pool-1-thread-6] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i49zzzzz
16:14:46.564 [pool-1-thread-3] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i4hzzzzz
16:14:46.564 [pool-1-thread-6] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i4kzzzzz
16:14:46.564 [pool-1-thread-2] INFO com.wcw.lowchat.util.MyIdGenerator - 生成id : 83dcctz6i4bzzzzz
...
参考文章
http://www.52im.net/thread-1998-1-1.html
http://www.52im.net/thread-2747-1-1.html
https://www.cnblogs.com/jiangxinlingdu/p/8440413.html
im即时通讯消息id的设计相关推荐
- IM即时通讯-消息id(五)
单独拎一个小节来讲消息id,悟了吧 消息id在整个IM即时通讯中,有着关键的作用,消息唯一性.时序性都是依赖消息id完成. 在IM即时通讯中,怎样生成一个消息id? 这不是很简单吗,毫秒级的时间戳就可 ...
- QQ即时通讯消息群发例子,QQ机器人开发学习资料
QQ即时通讯消息群发例子,QQ机器人开发学习资料 using System; using System.Collections.Generic; using System.Linq; using Sy ...
- 兼具高效与易用,融云 IM 即时通讯长连接协议设计思路
无论是 PC 端还是移动端,接入网络实现通信都需要建立双端的连接.关注[融云全球互联网通信云]了解更多 客户端和服务端建立连接后不断开,然后进行通信(也就是发送报文)的方式就是长连接. 与之相反,短连 ...
- WEB即时通讯/消息推送
写在前面 通常进行的Web开发都是由客户端主动发起的请求,然后服务器对请求做出响应并返回给客户端.但是在很多情况下,你也许会希望由服务器主动对客户端发送一些数据. 那么,该如何实现这个需求,或者说该如 ...
- php环信发送消息,环信即时通讯 —— 消息、会话
标签: 1.消息EMMessage 环信支持文字.图片.位置.语音.视频.文件.透传.自定义八种消息构造.消息,即IM交互实体,在SDK中对应的类型是 **EMMessage**,EMMessage可 ...
- 即时通讯技术的架构设计
一.WEB端实时通信技术对比 在WEB端的实时通信技术中,主要有以下几种方式: 1)轮询技术 轮询是最简单的一种实时通信技术,易于实现,非常适用于一些小型的应用.其基本原理是这样的,先在客户端设定一个 ...
- IM即时通讯-从0到1的实践(一)
先立个小目标:实现单聊 何为单聊呢:两个人之间的聊天,相对群聊而言 麻雀虽小五脏俱全,虽然说单聊是个小目标,但也在纵向上实现了IM即时通讯,也就是说包含了IM即时通讯必要的知识点. 需求细化: 1. ...
- im即时通讯开发:消息模型、万人群、已读回执、消息撤回功能
企业微信作为一款办公协同的产品,聊天消息收发是最基础的功能.消息系统的稳定性.可靠性.安全性尤其重要. 消息系统的构建与设计的过程中,面临着较多的难点.而且针对toB场景的消息系统,需要支持更为复杂的 ...
- 【原创】轻量级移动设备即时通讯技术MobileIMSDK的常见问题解答
申明:MobileIMSDK 目前为个人原创开源工程且已发布,现整理了一些有关MobileIMSDK的常见的问题,希望对需要的人有用,谢谢.如需与作者交流,见文章底部个人签名处,互相学习. Mobil ...
最新文章
- 不同的source control下配置DiffMerge
- AI教父Hinton胶囊模型又出新作——胶囊如何表示视觉层次结构
- linux下安装php扩展模块gettext
- ZOJ - 4114 Flipping Game(dp+组合数学)
- php sdk微信,GitHub - swayer/wechat-php-sdk: 微信公众平台 PHP SDK
- C# 利用系统剪贴板 保存 自定义对象
- struts2实现文件查看、下载
- topcoder SRM712 Div1 LR
- 微博计数:从关系服务到访问计数, Redis 持续优化支撑万亿级访问(含 PPT)
- c++ 编译添加dll_Windows下osg编译
- SIFT: Distinctive Image Features from Scale-Invariant Keypoints
- 推荐8款Windows装机必备下载神器【建议收藏】
- 工业机器人市场2018年热点回顾与2019年展望
- Reeder 5 for Mac(RSS阅读器)
- BGP——基本概念3(路由聚合)
- 2021周更06:春节假期开始
- Win10 - 注册表获取权限的方法
- 微信js 已经填写JS接口安全域名了,仍然报invalid url domain
- 联想台式电脑一键恢复后桌面没有计算机了,联想笔记本一键恢复功能使用教程...
- Android MVC、MVP和MVVP的概念、运用及区别
热门文章
- char与signed char, unsigned char的区别
- android锁屏界面快捷键,Funtouch新特性 锁屏快捷键可以自定义
- 出现Whitelabel Error Page的解决方法(持续更新带图并总结了其他博文)
- k8s数据持久化之statefulset的数据持久化,并自动创建PV与PVC
- 计算机中存储的数据类型
- 一群小朋友在玩老鹰捉小鸡
- 利用Filezilla在局域网内搭建自己的FTP服务器
- git报错 failed: The TLS connection was non-properly terminated
- 微信第三方平台开发,component_verify_ticket的接收
- 银行账号和身份证号的数据有效性设置