1、写在前面

1.1、引言

如果在没有太多经验可借鉴的情况下,要设计一套完整可用的移动端IM架构,难度是相当大的。原因在于,IM系统(尤其是移动端IM系统)是多种技术和领域知识的横向应用综合体:网络编程、通信安全、高并发编程、移动端开发等,如果要包含实时音视频聊天的话,则还要加上难度更大的音视频编解码技术(内行都知道,把音视频编解码及相关技术玩透的,博士学位都可以混出来了),凡此种种,加上移动网络的特殊性、复杂性,设计和开发难度不言而喻。

本文分享了一套完整的海量在线用户的移动端IM架构设计,来自于作者的真实项目实践总结,包含了详细的算法原理图、数据结构定义、表结构定义等等。

即时通讯网注:本文中的架构设计从实际应用的角度看,其实并不完美,多处设计对于高吞吐高并发的IM应用来说也是存在单点性能瓶颈的(比如:提供消息交换逻辑的msg_logic服务、提供全局用户状态查询的单点Redis等),另外IM协议设计可能也稍显混乱(但这是仁者见仁智者见者的事了,不能一概而论)。但文章中的大部分算法原理、协议设计等都是值得借鉴的,总之没必要照搬,但至少能给你自已的方案设计带来灵感,我想这也是本文或即时通讯网的其它类似文章的真正价值所在。

1.2、参考资料

浅谈IM系统的架构设计
简述移动端IM开发的那些坑:架构设计、通信协议和客户端
一套原创分布式即时通讯(IM)系统理论架构方案
从零到卓越:京东客服即时通讯系统的技术架构演进历程
蘑菇街即时通讯/IM服务器开发之架构选择
腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT
微信技术总监谈架构:微信之道——大道至简(演讲全文)
如何解读《微信技术总监谈架构:微信之道——大道至简》
快速裂变:见证微信强大后台架构从0到1的演进历程(一)
17年的实践:腾讯海量产品的技术方法论
>> 更多同类文章 ……

2、服务器端设计

2.1、总体架构设计

总体架构包括5个层级,具体内容如下图:

各层级的说明如下:

  • 用户端:
    移动端重点是移动端,支持IOS/Android系统,包括IM App,嵌入消息功能的瓜子App,未来还可能接入客服系统;
  • 用户端API:
    针对TCP协议,提供IOS/Android开发SDK。对于H5页面,提供WebSocket接口;
  • 接入层:
    接入层主要任务是保持海量用户连接(接入)、攻击防护、将海量连接整流成少量TCP连接与逻辑层通讯;
  • 逻辑层:
    逻辑层负责IM系统各项功能的核心逻辑实现。包括单聊(c2c)、上报(c2s)、推送(s2c)、群聊(c2g)、离线消息、登录授权、组织机构树等等内容;
  • 存储层:
    存储层负责缓存或存储IM系统相关数据,主要包括用户状态及路由(缓存),消息数据(MySQL也可采用NoSql,如MangoDB),文件数据(文件服务器)。

2.2、典型算法逻辑

典型算法逻辑部分描述IM系统核心组件及其协作关系,结构图如下:

客户端从Iplist服务获取接入层IP地址(也可采用域名的方式解析得到接入层IP地址),建立与接入层的连接(可能为短连接),从而实现客户端与IM服务器的数据交互;业务线服务器可以通过服务器端API建立与IM服务器的联系,向客户端推送消息;客户端上报到业务服务器的消息,IM服务器会通过mq投递给业务服务器。

以下将对各子业务的工作原理进行逐一介绍。

2.2.1登录授权(auth)流程原理

  • 1、客户端通过统一登录系统实现登录,得到token。
  • 2、客户端用uid和token向msg-gate发起授权验证请求。
  • 3、msg-gate同步调用msg-logic的验证接口
  • 4、msg-logic请求sso系统验证token合法性
  • 5、msg-gate得到登录结果后,设置session状态,并向客户端返回授权结果。

2.2.2登出(logout)流程原理

  • 1、客户端发起logout请求,msg-gate设置对应Peer为未登录状态。
  • 2、Msg-gate给客户端一个ack响应。
  • 3、Msg-gate通知msg-logic用户登出。

2.2.3踢人(kickout)流程原理

用户请求授权时,可能在另一个设备(同类型设备)开着软件处于登录状态,这种情况需要系统将那个设备踢下线,如下图:

  • 1-5步,参看Auth流程。
  • 6、Logic检索Redis,查看是否该用户在其他地方登录。
  • 7、如果在其他地方登录,发起kickout命令。(如果没有登录,整个流程结束)
  • 8、Gate向用户发起kickout请求,并在短时间内(确保客户端收到kickout数据)关闭socket连接。

2.2.4上报(c2s)流程原理

  • 1、客户端向gate发送数据;
  • 2、Gate回一个ack包,向客户端确认已经收到数据;
  • 3、Gate将数据包传递给logic;
  • 4、Logic根据数据投递目的地,选择对应的mq队列进行投递;
  • 5、业务服务器得到数据。

2.2.5推送(s2c)流程原理

  • 1、业务线调用push数据接口sendMsg
  • 2、Logic向redis检索目标用户状态。如果目标用户不在线,丢弃数据(未来可根据业务场景定制化逻辑);如果用户在线,查询到用户连接的接入层gate
  • 3、Logic向用户所在的gate发送数据
  • 4、Gate向用户推送数据。(如果用户不在线,通知logic用户不在线)
  • 5、客户端收到数据后向gate发送ack反馈
  • 6、Gate将ack信息传递给logic层,用于其他可能的逻辑处理(如日志,确认送达等)

2.2.6单对单聊天(c2c)流程原理

  • 1、App1向gate1发送信息(信息最终要发给App2)
  • 2、Gate1将信息投递给logic
  • 3、Logic收到信息后,将信息进行存储
  • 4、存储成功后,logic向gate1发送ack
  • 5、Gate1将ack信息发给App1
  • 6、Logic检索redis,查找App2状态。如果App2未登录,流程结束
  • 7、如果App2登录到了gate2,logic将消息发往gate2
  • 8、Gate2将消息发给App2(如果发现App2不在线,丢弃消息即可,这种概率极低,后续离线消息可保证消息不丢)
  • 9、App2向gate2发送ack
  • 10、Gate2将ack信息发给logic
  • 11、Logic将消息状态设置为已送达。

注:在第6步和第7步之间,启动计时器(DelayedQueue或哈希环,时间如5秒),计时器时间到后,探测该条消息状态,如果消息未送达,考虑通过APNS、米推、个推进行推送。

2.2.7群聊(c2g)流程原理

采用扩散写(而非扩散读)的方式。

群聊是多人社交的基本诉求,一个群友在群内发了一条消息:

  • 1)在线的群友能第一时间收到消息;
  • 2)离线的群友能在登陆后收到消息。

由于“消息风暴扩散系数”的存在,群消息的复杂度要远高于单对单消息。

群基础表:用来描述一个群的基本信息
im_group_msgs(group_id, group_name,create_user, owner, announcement, create_time)

群成员表:用来描述一个群里有多少成员
im_group_users(group_id, user_id)

用户接收消息表:用来描述一个用户的所有收到群消息(与单对单消息表是同一个表)
im_message_recieve(msg_id,msg_from,msg_to, group_id,msg_seq, msg_content, send_time, msg_type, deliverd, cmd_id)

用户发送消息表:用来描述一个用户发送了哪些消息
im_message_send (msg_id,msg_from,msg_to, group_id,msg_seq, msg_content, send_time, msg_type, cmd_id)

业务场景举例:

  • 1)一个群中有x,A,B,C,D共5个成员,成员x发了一个消息;
  • 2)成员A与B在线,期望实时收到消息;
  • 3)成员C与D离线,期望未来拉取到离线消息。

群聊流程如下图所示:

群聊流程详细说明:

  • 1、X向gate发送信息(信息最终要发给这个群,A、B在线)
  • 2、Gate将消息发给logic
  • 3、存储消息到im_message_send表,按照msg_from水平分库
  • 4、回ack
  • 5、回ack
  • 6、Logic检索数据库(需要使用缓存),获得群成员列表
  • 7、存储每个用户的消息数据(用户视图),按照msg_to水平分库(并发、批量写入)。
  • 8、查询用户在线状态及位置
  • 9、Logic向gate投递消息
  • 10、Gate向用户投递消息
  • 11、App返回收到消息的ack信息
  • 12、Gate向logic传递ack信息
  • 13、向缓存(Hash)中更新收到ack的时间。然后在通过一个定时任务,每隔一定时间,将数据更新到数据库(注意只需要写入时间段内有变化的数据)。

2.2.8拉取离线消息流程原理

下图中,将gate和logic合并为im-server,拉取离线消息流程如下:

  • 1、App端登录成功后(或业务触发拉取离线消息),向IM系统发起拉离线消息请求。传递3个主要参数,uid表明用户;msgid表明当前收到的最大消息id(如果没收到过消息,或拿不到最大消息id则msgid=0)即可;size表示每次拉取条数(这个值也可以由服务器端控制)。
  • 2、假设msgid==0,什么都不做。(参看第6步骤)
  • 3、Im-server查询用户前10条离线消息
  • 4、将离线消息推给用户。假设这10条离线消息最大msgid=110。
  • 5、App得到数据,判断得到的数据不为空(表明可能没有拉完离线数据,不用<10条做判断拉完条件,因为服务端需要下下次拉离线的请求来确定这次数据已送达),继续发起拉取操作。Msgid=110(取得到的离线消息中最大的msgid)。
  • 6、Im-server删除该用户msgid<110的离线消息(或者标记为已送达)。
  • 7、查询msgid>110的钱10条离线数据。
  • 8、返回给App
  • ……
  • N-1、查询msgid>140的离线数据,0条(没有离线数据了)。
  • N  、将数据返回App,App判断拉取到0条数据,结束离线拉取过程。

2.3、后台PUSH(推送)

ISO采用APNS,Android真后台保活,同时增加米推、个推。基本思路:push提示信息,App通过拉离线获得真实消息。

3、协议设计

3.1、IM协议总体定义

TCP的数据协议如下图所示,包括header和body两部分:

消息头总共20个字节,具体信息如下表:

3.2、各具体的IM协议体定义

消息体协议采用ProtocolBuffer(谷歌)协议(详见文章《Protobuf通信协议详解:代码演示、详细原理介绍等》),版本3.0.0,该协议在序列化效率、压缩、可扩展方面都具有优势。以下为主要流程涉及的协议。

认证(auth) :

登出(logout) :

踢人(kickout) :

心跳(keepalive,noop):
心跳包消息体为空。

单对单聊天(c2c):
 

群聊(c2g):
 

拉离线(pull):

控制类(ctrl)协议:
 

4、存储设计

4.1、MySQL数据库

MySQL数据库采用utf8mb4编码格式(emoji字符问题)。

4.2、主要表结构

发送消息表:
保存某个用户发送了哪些消息,用于复现用户聊天场景(消息漫游功能需要)。

推送消息表:
保存某个用户收到了哪些消息。

群基本信息表:

群用户关系表:

4.3、水平分库

4.4、Redis缓存

用户状态及路由信息:
Redis缓存以uid为key,检索channel(socketid),last_packet_time等。
Gate层,session以channel(socketed)为key,检索uid,及其他信息。
交互接口:gate->logic,通过将channel转换为uid作为key。
logic->gate,将uid转换为channel作为key。

其他缓存信息:
你觉得该怎么存就怎么存。

4.5、文件及图片存储

采用商用云存储。

4.6、数据归档

可考虑采用HBase,HDFS作为数据归档,或者相关云存储服务。

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)(转)的更多相关文章

  1. 百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

    本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<三>弱网优化>,感谢原作者的无私分享. 一.前言 网络优化解决的核心问题有三个 ...

  2. 百度APP移动端网络深度优化实践分享(一):DNS优化篇

    本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<一>DNS优化>,感谢原作者的无私分享. 一.前言 网络优化是客户端几大技术方 ...

  3. 百度APP移动端网络深度优化实践分享(二):网络连接优化篇

    本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<二>连接优化>,感谢原作者的无私分享. 一.前言 在<百度APP移动端网 ...

  4. 一套高可用、易伸缩、高并发的IM群聊架构方案设计实践

    本文原题为“一套高可用群聊消息系统实现”,由作者“于雨氏”授权整理和发布,内容有些许改动,作者博客地址:alexstocks.github.io.应作者要求,如需转载,请联系作者获得授权. 一.引言 ...

  5. vivo 服务端监控架构设计与实践

    一.业务背景 当今时代处在信息大爆发的时代,信息借助互联网的潮流在全球自由的流动,产生了各式各样的平台系统和软件系统,越来越多的业务也会导致系统的复杂性. 当核心业务出现了问题影响用户体验,开发人员没 ...

  6. 腾讯网移动端H5页面设计实战分享

    分享 <关于我> 分享  [中文纪录片]互联网时代                 http://pan.baidu.com/s/1qWkJfcS 分享 <HTML开发MacOSAp ...

  7. .NET应用架构设计—用户端的防腐层作用及设计

    阅读目录: 1.背景介绍 2.SOA架构下的显示端架构腐化 3.有效使用防腐层来隔离碎片服务导致显示端逻辑腐烂 4.剥离服务调用的技术组件让其依赖接口 5.将服务的DTO与显示端的ViewModel之 ...

  8. 简述移动端IM开发的那些坑:架构设计、通信协议和客户端

    1.前言 有过移动端开发经历的开发者都深有体会:移动端IM的开发,与传统PC端IM有很大的不同,尤其无线网络的不可靠性.移动端硬件设备资源的有限性等问题,导致一个完整的移动端IM架构设计和实现都充满着 ...

  9. 十万同时在线用户,需要多少内存?——Newbe.Claptrap 框架水平扩展实验

    Newbe.Claptrap 项目是笔者正在构建以反应式.Actor模式和事件溯源为理论基础的一套服务端开发框架.本篇我们将来了解一下框架在水平扩展方面的能力. 前情提要 时隔许久,今日我们再次见面. ...

随机推荐

  1. idea 配置全局 maven

    Idea默认的全局设置,如Maven等 每次使用IDEA打开一个新的项目,maven都需要重新配置,非常不开心,所以需要有个默认全局配置,打破不开心 配置完就OK了 原文链接:https://www. ...

  2. Jmeter(二十一)Jmeter常见问题及场景应用

    Jmeter作为工具来讲,已经是一个相对比较牛掰的工具,除了它能够支持那么多协议以及方法之外,更在与它的前置处理以及后置处理.同步监控的人性化.当然,所有的工具.框架都是作为业务的支撑,如果不能满足我 ...

  3. Jmeter(五)录制功能

    难得休息时间,和开发对完需求便理着Jmeter的知识的相关体系,趁闲暇功夫就记一点,希望这么坚持下去,能有很多关于Jmeter的知识点被总结,被挖掘出来,从而形成自己的一套知识体系..... 嗯,那本 ...

  4. [UE4]Break展开复杂数据结构

  5. RHEL7安装配置VNC

    RHEL7安装配置VNC 作者:Eric 微信:loveoracle11g 安装配置VNC服务程序 [root@zhouwanchun yum.repos.d]# cd ~ [root@zhouwan ...

  6. (转)Linux netstat命令详解

    简介 Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Member ...

  7. python中str相关函数

    capitalize 将字符串的首字母大写 title 每个单词的首字母大写 (不是字母隔开的单词首字母都大写) upper 所有字母大写 lower 所有字母小写 swapcase 大写变小写 co ...

  8. Android Studio设置自定义字体

    Android Studio设置自定义字体 (1)进入设置页面,File->Settings (2)自定义字体Editor->Colors&Fonts->Font (3)点击 ...

  9. Getting Physical With Memory.CPU如何操作内存

    原文标题:Getting Physical With Memory 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些国外高手的精彩文章翻译一下 ...

  10. 查看oracle用户执行的sql语句历史记录

    select PARSING_SCHEMA_NAME,COUNT(DISTINCT T.SQL_TEXT) from v$sqlarea t WHERE T.LAST_ACTIVE_TIME > ...