IM协议设计

Wesley13
• 阅读 486

IM协议设计

在实际开发中,为了及时的通知APP端一些事情,我们会借助第三方平台,进行推送。今天,我们来分析一下推送系统协议。

推送系统遇到的问题

在设计协议之前,我们考虑一些实际的问题:

  1. APP没有一个固定的网络地址,只能通过主动连接服务器,建立TCP长链接,来进行推送。

  2. 移动环境下,APP断网是非常普遍的,即推送任务会失败

  3. 在大并发的情况下,服务器宕机也是非常有可能的。

  4. APP可能不会随时连上服务器,而服务器需要保存一些非常重要的消息,等待APP连接上,推送给APP

  5. 移动环境下,节省流量也是非常重要的,毕竟不是人人都有4G

  6. 网络安全问题,日益严重,我们需要安全的推送

  7. 协议的兼容性

  8. 由于GSM网关,所以需要发送心跳包,避免NET转换被剔除

如何解决

可以发现,一个好的推送协议设计,还是非常困难的。总结下来,我们遇到的问题大致如下:

  1. 节约流量:采用protobuf这种二进制协议进行推送,但是也可以考虑JSON + UTF-8的方式

  2. 推送失败处理:无论服务器还是APP,都采用日志先行的策略,如果发送失败,则进行RETRY,直到到达推送极限次数后,报告错误。

  3. 安全性:采用SSL/TLS连接,基本上能解决安全链接的问题,如果条件比较拮据,可以把证书放在APP端。

  4. 协议兼容:可以参考APP兼容性设计中的协议兼容部分。

  5. 心跳包:一般来说,因为移动网络和互联网之间存在一个NET网关,它的有效时间为6分钟左右,所以APP端需要定时的发送心跳包到服务器,一般间隔时间为3-5分钟。同时,通过心跳包,服务器可以发现已经死掉的链接,及时的释放资源。

RETRY机制

在上述问题中,其他问题都比较好解决,但是消息重发机制,还是比较难以实现的。 这几介绍一下RETRY机制的设计:

  1. 加入UUID作为该消息的唯一ID,且在服务器端保留最后的100条该用户的消息,当APP端把消息推送到服务器的时候,服务器先去重,避免接受到相同的消息进行推送。

  2. 当APP连接上网络后,首先检测待发送的消息列表中是否为空,如果不为空,则根据FIFO来提取待发送的消息。直到服务器返回OK后,才把本条消息从待发送队列中删除。

  3. 发送失败的延迟推送算法,建议采用TCP的重发时间机制,也就是指数退避算法。

协议具体设计

这里使用JSON描述

{
    MODULE:PUSH
    VERSION:1 //版本号
    ID: UUID  //消息UUID
    TYPE: GROUP | PRIVATE | SYSTEM //消息会话类型
    TARGET_ID: STRING  //消息要发送到的目标ID,如果是GROUP,则是群的ID
    TIME:LONG //消息发送时间
    USER_ID : STRING //发送该该消息的用户ID
    CONTENT:{
        TYPE : STRING -> TEXT | IMAGE //消息的内容类型
        [DATA]: STRING -> BASE64_IMAGE | TEXT //消息的具体内容,可选
    }
}

一些实际问题

粘包

在使用TCP的过程中,会遇到粘包的问题,其根本原因是TCP是面向流链接的,所以,在传输一消息的时候,需要在开始处添加 该消息的长度 , 建议采用 [TCP长度,固定4byte + TCP报文]的格式。

消息有序性

在推送消息的时候,我们需要考虑消息的有序性。所以,在APP推送到服务器,或者服务器推送到APP端的时候,需要按序推送,只有前一条消息推送成功后,才能推送后一条。

总结

可以发现IM协议的设计和TCP协议是非常类似的,额外的添加了消息持久化的功能。对于消息有序性这个问题,引发的同一时间只有一条消息发送这个问题,可以考虑TCP的滑动窗口机制。

参考

Netty系列之Netty百万级推送服务设计要点

微信、陌陌等著名IM软件设计架构详解

点赞
收藏
评论区
推荐文章
秃头王路飞 秃头王路飞
4个月前
webpack5手撸vue2脚手架
webpack5手撸vue相信工作个12年的小伙伴们在面试的时候多多少少怕被问到关于webpack方面的知识,本菜鸟最近闲来无事,就尝试了手撸了下vue2的脚手架,第一次发帖实在是没有经验,望海涵。languageJavaScript"name":"vuecliversion2","version":"1.0.0","desc
浅梦一笑 浅梦一笑
4个月前
初学 Python 需要安装哪些软件?超级实用,小白必看!
编程这个东西是真的奇妙。对于懂得的人来说,会觉得这个工具是多么的好用、有趣,而对于小白来说,就如同大山一样。其实这个都可以理解,大家都是这样过来的。那么接下来就说一下python相关的东西吧,并说一下我对编程的理解。本人也是小白一名,如有不对的地方,还请各位大神指出01名词解释:如果在编程方面接触的比较少,那么对于软件这一块,有几个名词一定要了解,比如开发环
技术小男生 技术小男生
4个月前
linux环境jdk环境变量配置
1:编辑系统配置文件vi/etc/profile2:按字母键i进入编辑模式,在最底部添加内容:JAVAHOME/opt/jdk1.8.0152CLASSPATH.:$JAVAHOME/lib/dt.jar:$JAVAHOME/lib/tools.jarPATH$JAVAHOME/bin:$PATH3:生效配置
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Stella981 Stella981
1年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
1年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序selectfromtable_nameorderiddesc;2.按照指定(多个)字段排序selectfromtable_nameorderiddesc,statusdesc;3.按照指定字段和规则排序selec
Wesley13 Wesley13
1年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
3A网络 3A网络
4个月前
开发一个不需要重写成 Hive QL 的大数据 SQL 引擎
开发一个不需要重写成HiveQL的大数据SQL引擎学习大数据技术的核心原理,掌握一些高效的思考和思维方式,构建自己的技术知识体系。明白了原理,有时甚至不需要学习,顺着原理就可以推导出各种实现细节。各种知识表象看杂乱无章,若只是学习
3A网络 3A网络
4个月前
理解 virt、res、shr 之间的关系(linux 系统篇)
理解virt、res、shr之间的关系(linux系统篇)前言想必在linux上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?通常我们可以通过t
helloworld_34035044 helloworld_34035044
6个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为