IM
- 基于Vert.x开发的IM服务端
- 演示地址: http://www.justlive.vip
略 (简单修改了layim的ui)
- 基于Vert.x搭建项目
- 使用Event Bus Bridge将Event Bus扩展到客户端的JavaScript运行环境
- 短连接和长连接配合
- 请求报文 R
- 应答报文 A
- 通知报文 N
用户a向b发送“你好”
- 客户端a向服务器发送请求报文 msg:R
- 服务器收到后给客户端a发送应答报文 msg:A
- 服务器给客户端b发送通知报文 msg:N
可能出现的问题
- 服务器崩溃 N未发出
- 网络波动 N包被丢弃
- 客户端b崩溃 N未接收
增加确认报文
- 客户端b向服务器发送确认请求 ack:R
- 服务器向客户端b发送确认响应 ack:A
- 服务器向客户端a发送确认通知 ack:N
消息的超时与重传
- client-A发出了msg:R,收到了msg:A之后,在一个期待的时间内,如果没有收到ack:N,client-A会尝试将msg:R重发。
- 可能client-A同时发出了很多消息,故client-A需要在本地维护一个等待ack队列,并配合timer超时机制,来记录哪些消息没有收到ack:N,以定时重发
消息的去重
- 绑定msgid
相关
- 客户端重传,保证服务端无状态
- 离线消息需要伪造 ack:N
- 离线消息拉取也要ack,发送offline:R报文拉取消息,收到offline:A后,再发送offlineack:R删除离线消息
消息接收方不在线时的典型消息发送流程
- 客户端a发送消息到服务器 msg:R
- 服务器收到后给客户端a发送应答 msg:A
- 服务器发现客户端b不在线,持久化消息
- 服务器给客户端a发送确认通知 ack:N
离线消息存储主要字段
- 消息接收者
- 消息唯一id
- 发送时间
- 消息发送者
- 消息类型
- 消息体
拉取离线消息流程
- 客户端b拉取客户端a发送的消息请求
- 服务器获取离线消息
- 服务器删除消息
- 服务器返回客户端b消息
多用户拉取离线消息优化
- 先拉各个好友离线消息数量,真正去看消息再去单独拉取
- 一次性拉取所有离线消息,客户端去分组
原因
- 时钟不一致
- 多客户端(多发送方)
- 服务集群(多接收方)
- 网络传输与多线程
方法
- 以客户端或服务器的时序为准
- 服务端生成单调递增的id
- 大部分业务可以接受误差不大的趋势递增id
- 单点序列化
单对单聊天,怎么保证发送顺序与接收顺序一致
- 发送方增加序号seq
- 潜在显示突兀问题
群聊消息,怎么保证各接收方收到顺序一致
- 服务器单点序列化来做
用户a登录时获取全部好友的在线状态
- 服务器储存所有用户在线状态
- 用户状态变更需要修改服务器储存的在线状态
- 用户a登录时,先拉取所有用户列表再去获取在线状态
用户a的好友b状态改变时如何感知
- 方式1.轮询拉取用户b的状态
- 获取不实时,有延迟
- 会有大量无效轮询请求,占用服务器资源
- 方式2.用户b退出登录后,服务器修改b的状态,推送b的反向好友
- 实时
- 在线好友量很大的时候,会扩散成N个实时通知(消息风暴扩散系数)
保持群聊状态的一致性
- 一般采用拉取模式, 消息风暴扩散系数太高
离线消息表
- 群成员表
- group_id
- user_id
- last_ack_msg_id
- 群消息表
- group_id
- send_id
- msg_id
- detail
- time
短连接使用
- 前置http的sso单点接口
- 集群im的slb接口
- 小文件上传、下载接口
长连接使用
- 用户实时上下线通知
- 实时加好友加群
- 服务器发起的其他实时指令