Code-Life
Code-Life copied to clipboard
IM 架构
跟着 @hanggegreat 一起学习 && 实战 简单的IM
跟着 @hanggegreat 一起学习 && 实战 简单的IM
饼爷yyds
基础篇
完整的IM的需求
- 实时性
- 可靠性 (不重复,不丢)
- 一致性 (消息有序,多终端同步消息一致)
- 安全性
消息收发架构
消息存储在哪里
- 为方便检索,store at client。
- 未读消息,多端信息同步,store at server
消息存储及索引
- 消息存储需要 message_id, from_user_id, to_user_id, message, message_type, timestamp
- 消息索引需要 from_user_id, to_user_id, message_id
消息发送与接收
send client -> IM server -> receive client
未读
- 某人的总未读数
- 某人和另外一个人的会话未读数
实时性
- 短轮询
- 长轮询
- 边缘触发(状态发生改变,产生io事件
- websocket
可靠性
- 大部分场景和实际实现中,通过业务层的 ACK 确认和重传机制,能解决大部分推送过程中消息丢失的情况。
- 通过客户端的去重机制,屏蔽掉重传过程中可能导致消息重复的问题,从而不影响用户体验。
- 针对重传消息不可达的特殊场景,我们还可以通过“兜底”的完整性检查机制来及时发现消息丢失的情况并进行补推修复,消息完整性检查可以通过时间戳比对,或者全局自增序列等方式来实现。
一致性
- 分布式自增id, 需要保证群组内的消息一致性, 可以先按照
groupid
hash到一台发号器,然后利用snowflake
算法去生成有序的id - 服务端多个tcp包合并,按照业务id进行排序再推送
- 接收端也需要根据业务id进行排序然后展示
- 全局自增id会存在单点性能问题
安全性
- 端到端的加密
- 内容安全(文字,语音,图片校验)
事务
- 分布式事务(保证多个操作的原子性)
- 分布式锁(依赖redis or zk 数据库,存在单点瓶颈,影响吞吐)
心跳
心跳解决了以后三方面问题
- 降低服务端无效链接的开销
- 支持客户端快速识别无效链接,自动断线重连
- 链接保活,便面被运营商NAT超时断开
心跳探测方式
- TCP keepalive
- 应用层心跳
场景篇
多终端消息漫游
- 在线
- 服务端对用户所有的设备维护状态,然后将一条消息推送到所有设备
- 离线
- 设备在线后,再推送离线消息(有offset)
峰值流量的应对
- 在线状态本地化维护,降低远程资源依赖,提升单机处理能力。
- 对服务整体进行拆分,区分核心和非核心服务,隔离“容易出现瓶颈”的服务。
- 通过收集业务和机器两类指标,建立容量评估模型,自动进行服务扩缩容。
- 根据后端机器负载水平调度全局,接入服务入口,解决扩容后新接入流量在新扩容机器和旧机器间流量不均衡的问题。
- 对于长连接的网关服务(有状态),我们缩容是只需要禁止新的建连请求接入,已存在的长连接尽量等用户自动断开后关闭,对于剩余的少量的长连接可以采取强制断开方式,等待客户端断连重连即可。