定义IM

为用户提供即时消息服务,这里面有三个关键词:用户,消息,服务;下面根据三个关键词来展开总结,先从消息开始。

消息

消息分类

对消息分类,很简单但是重要,方便后面业务的拆分。

  1. 注册
  2. 登录
  3. 用户信息
  4. 聊天消息
  5. 群组
  6. 好友
  7. 文件
  8. 版本
  9. 内部服务器之间消息
  10. 客户端诊断
  11. 其他业务消息

信息语义描述

在互联网和移动互联网时代常见有以下几种方式:

  1. XML
  2. 文本
  3. MQTT
  4. 自定义二进制(这里一般默认为google protobuf)

这四种类型比较如下表所示:

比较项 XML 文本 MQTT 自定义二进制
可读性
通用性 标准协议,易通用 支持通用http协议,也可自定义 通用标准协议 私有协议,无法通用
扩展性 易扩展,支持第三方 易扩展 可扩展 仅协议可扩展,不支持第三方
流量消耗 极大
处理效率 一般
网络适应性 一般 较好 较好
业内应用 新浪微博/GTalk MSN facebook messenger QQ/weixin

再补充说一点,采用二进制协议,在网络带宽及消息存储方面可以节约成本,特别用户量达到千万级以上

参考业内应用和移动互联网需求,二进制协议应该是不二选择。这里强烈推荐google protobuf,理由如下:

  1. 亲爹是google
  2. 支持多种编程语言(C++, JAVA, PYTHON, GO,PHP,C#),支持多种平台
  3. 自定义且灵活
  4. 支持数据压缩
  5. 完整的技术生态,以及多年的应用实践

消息可扩展性

自定义二进制消息(google protobuf)可扩展性方面的一些经验:

  1. 采用T(ype)L(ength)V(alue)
  2. 数据结构中的成员不要使用变长数据类型,例如long,在32位系统中占4Bytes,在64位系统占用8Bytes
  3. 不删除消息体的数据成员
  4. 消息类型递增,不删除消息类型,即使不再使用也保留
  5. 消息头带上版本号,客户端无需要关心版本变化,由服务器完成不同版本的兼容适配处理
  6. 消息头与消息体的设计统一管理,不允许任何人私自修改
  7. 除非确定,protobuf消息字段尽量使用optional,由代码逻辑确定是否需要相应字段
  8. 考虑业务需求与变化,为未来留有应对变化的空间,同时保证消息的简洁

消息存储

  1. 初期简单点,采用mysql,同时利用mysql主备部署解决单点故障问题,分布式存储后面再说了,针对大量的消息存储后面考虑
  2. 对用户之间的聊天消息分表
  3. 对群信息等利用redis缓存
  4. 对于热点数据可以直接加载到内存

消息转发

  1. 消息从用户到用户(单播)
  2. 消息从用户到服务器 (单播)
  3. 消息从用户到群组 (组播)
  4. 消息从服务器到用户(单播)
  5. 消息从服务器到群组(组播)

消息传输

相对于PC互联网情况下,移动互联网情况下,丢包概率高,传输延迟大,问题自然就比较多,这方面优化请参考手机QQ的移动网络实践之路

消息安全

  1. 防修改 消息检查或校验
  2. 防窃听 消息加密
  3. 防泄漏 系统防入侵,系统加固
  4. 防丢失 消息请求与回应机制,消息重传与幂等性
  5. 防损坏 多副本,分布式存储
  6. 防伪装 身份验证,签名

消息描述

消息由消息头和消息体组成,消息头参考如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12

#pragma pack(1)
typedef struct {
    uint16_t    type;         // msg type 
    uint16_t    length;       // the whole pdu length
    uint32_t    version;      // pdu version number
    uint32_t    magic;        // magic number
    uint32_t    reserve;
    //后面为消息体
} UserPduHeader_t;
#pragma pack()

后记

由于个人水平有限,有什么不足与错误,敬请指正!