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的数据进行分段:

  1. 64bit : 时间戳 42bit | 自旋ID 12bit | 会话类型4bit | 会话ID高位6bit
  2. 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的设计相关推荐

  1. IM即时通讯-消息id(五)

    单独拎一个小节来讲消息id,悟了吧 消息id在整个IM即时通讯中,有着关键的作用,消息唯一性.时序性都是依赖消息id完成. 在IM即时通讯中,怎样生成一个消息id? 这不是很简单吗,毫秒级的时间戳就可 ...

  2. QQ即时通讯消息群发例子,QQ机器人开发学习资料

    QQ即时通讯消息群发例子,QQ机器人开发学习资料 using System; using System.Collections.Generic; using System.Linq; using Sy ...

  3. 兼具高效与易用,融云 IM 即时通讯长连接协议设计思路

    无论是 PC 端还是移动端,接入网络实现通信都需要建立双端的连接.关注[融云全球互联网通信云]了解更多 客户端和服务端建立连接后不断开,然后进行通信(也就是发送报文)的方式就是长连接. 与之相反,短连 ...

  4. WEB即时通讯/消息推送

    写在前面 通常进行的Web开发都是由客户端主动发起的请求,然后服务器对请求做出响应并返回给客户端.但是在很多情况下,你也许会希望由服务器主动对客户端发送一些数据. 那么,该如何实现这个需求,或者说该如 ...

  5. php环信发送消息,环信即时通讯 —— 消息、会话

    标签: 1.消息EMMessage 环信支持文字.图片.位置.语音.视频.文件.透传.自定义八种消息构造.消息,即IM交互实体,在SDK中对应的类型是 **EMMessage**,EMMessage可 ...

  6. 即时通讯技术的架构设计

    一.WEB端实时通信技术对比 在WEB端的实时通信技术中,主要有以下几种方式: 1)轮询技术 轮询是最简单的一种实时通信技术,易于实现,非常适用于一些小型的应用.其基本原理是这样的,先在客户端设定一个 ...

  7. IM即时通讯-从0到1的实践(一)

    先立个小目标:实现单聊 何为单聊呢:两个人之间的聊天,相对群聊而言 麻雀虽小五脏俱全,虽然说单聊是个小目标,但也在纵向上实现了IM即时通讯,也就是说包含了IM即时通讯必要的知识点. 需求细化: 1. ...

  8. im即时通讯开发:消息模型、万人群、已读回执、消息撤回功能

    企业微信作为一款办公协同的产品,聊天消息收发是最基础的功能.消息系统的稳定性.可靠性.安全性尤其重要. 消息系统的构建与设计的过程中,面临着较多的难点.而且针对toB场景的消息系统,需要支持更为复杂的 ...

  9. 【原创】轻量级移动设备即时通讯技术MobileIMSDK的常见问题解答

    申明:MobileIMSDK 目前为个人原创开源工程且已发布,现整理了一些有关MobileIMSDK的常见的问题,希望对需要的人有用,谢谢.如需与作者交流,见文章底部个人签名处,互相学习. Mobil ...

最新文章

  1. 不同的source control下配置DiffMerge
  2. AI教父Hinton胶囊模型又出新作——胶囊如何表示视觉层次结构
  3. linux下安装php扩展模块gettext
  4. ZOJ - 4114 Flipping Game(dp+组合数学)
  5. php sdk微信,GitHub - swayer/wechat-php-sdk: 微信公众平台 PHP SDK
  6. C# 利用系统剪贴板 保存 自定义对象
  7. struts2实现文件查看、下载
  8. topcoder SRM712 Div1 LR
  9. 微博计数:从关系服务到访问计数, Redis 持续优化支撑万亿级访问(含 PPT)
  10. c++ 编译添加dll_Windows下osg编译
  11. SIFT: Distinctive Image Features from Scale-Invariant Keypoints
  12. 推荐8款Windows装机必备下载神器【建议收藏】
  13. 工业机器人市场2018年热点回顾与2019年展望
  14. Reeder 5 for Mac(RSS阅读器)
  15. BGP——基本概念3(路由聚合)
  16. 2021周更06:春节假期开始
  17. Win10 - 注册表获取权限的方法
  18. 微信js 已经填写JS接口安全域名了,仍然报invalid url domain
  19. 联想台式电脑一键恢复后桌面没有计算机了,联想笔记本一键恢复功能使用教程...
  20. Android MVC、MVP和MVVP的概念、运用及区别

热门文章

  1. char与signed char, unsigned char的区别
  2. android锁屏界面快捷键,Funtouch新特性 锁屏快捷键可以自定义
  3. 出现Whitelabel Error Page的解决方法(持续更新带图并总结了其他博文)
  4. k8s数据持久化之statefulset的数据持久化,并自动创建PV与PVC
  5. 计算机中存储的数据类型
  6. 一群小朋友在玩老鹰捉小鸡
  7. 利用Filezilla在局域网内搭建自己的FTP服务器
  8. git报错 failed: The TLS connection was non-properly terminated
  9. 微信第三方平台开发,component_verify_ticket的接收
  10. 银行账号和身份证号的数据有效性设置