转载

码云推荐 | 基于 Vert.x 开发的 IM 服务端 helium

helium

IM

介绍

  • 基于Vert.x开发的IM服务端

相关原理

报文类型

  • 请求报文 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接口
  • 小文件上传、下载接口

长连接使用

  • 用户实时上下线通知
  • 实时加好友加群
  • 服务器发起的其他实时指令
原文  https://gitee.com/justlive1/helium
正文到此结束
Loading...