zoukankan      html  css  js  c++  java
  • 移动APP的IM后台架构浅析

    IM(InstantMessaging 即时通讯)作为一项基础功能,很多APP都有,比如:手机QQ、微信、易信、钉钉、飞信、旺旺、咚咚、陌陌等。而IM如同我们日常生活中的水和电一样,必不可少,也是很多“社交”类APP必不可少的基础功能,而上面这些APP里面,微信最为出色。

    如果作为一名创业者需要用到IM的功能,我建议是直接使用第三方提供的服务,比如:易信(网易的童鞋们记得要给我打赏哇,我看过它提供的DEMO和服务,确实很赞~),为什么不自己开发?你有单聊那就需要群聊吧,而在移动互联网时代,因为移动互联网的特点,导致对技术的门槛比PC上的IM要高不少,而IM做为基础功能又至关重要,传闻很多公司内部是不允许使用QQ的(原因是怕因为信息外泄,360肯定是不用QQ的,具体用啥我也不清楚了)。扯了这么多,准备切入正题...

    移动互联网的一些特性:

    1、弱网络
    2、对电量、流量敏感;
    如果你的APP提供的IM服务,一是慢、经常丢失消息二是还特别费流量、电量,你觉得用户有什么理由不卸载你的APP呢?而光解决弱网络这个问题就是一个比较深的坑,所以没有一定的技术积累或是资源投入还是建议不要往这里面跳了。

    IM的基本原则:

    1、消息收、发尽可能快(不快、不实时就不叫即时通讯了);
    2、不能丢失消息(你把消息都丢失了,谁还敢用,跟钱存银行钱可能会丢差不多);

    网络传输协议的选择

    APP上的IM传输协议以TCP主为,同时支持HTTP,而PC上的QQ主要采用UDP协议(历史原因),手机QQ是否也采用了UDP还不太确定。如果要实现像微信一样,支持web版,可以用HTTP/HTTPS来实现comet或者直接使用websocket(低版本的浏览器不支持)

    消息协议的选择

    几个原则:
    1、传输信息体积尽可能小,越小才能传的越快,失败重传的可能性也越低;
    2、传输的数据是安全、可靠的,你不能明文传输吧,而序列化、反序列化又会影响你的性能(Java在序列化、反序列化上性能问题尤为突出);
    3、易于扩展、可维护(产品加一项功能,不能说后端更新了,APP端无法解析就会更种报错,无法使用);

    常用的聊天协议:
    1、XMPP
    基于XML的消息协议,调试方便,抓到XML能大概看懂什么意思,缺点就是太臃肿了,虽然方便扩展,但是太费流量,强烈不建议使用,用它实现的APP收发消息不会快到哪去;
    2、自定义的二进制协议
    二进制肯定是比XML的体积要小的,建议是自定义的二进制协议 + protobuf

    协议的定制的话,可以参考MySQL或者Redis的协议格式,这里给出一个参考的格式(类MySQL的):
    数据包长度(4 byte)+ 协议头(2 byte)+ 协议版本(2 byte) + 错误码(2 byte)+ 回执码(2 byte)+ 消息体(data body)

    为了安全和性能方面的平衡,可以考虑将消息体进行简单的加密处理(可以简单的将指定的位置的字节进行顺序调整,比如第一位与最后一位进行对调都可以)。这样在传输的过程中不用反序列化就很容易知道当前这条消息它的消息头是什么,提升一些业务逻辑的处理效率。客户端在接收数据时,为了解决粘包的总是,肯定会有一个缓冲池(可能是环形缓冲池),而数据包的长度能避免粘包的问题。

    简单的收发架构

    连接层(主要维护客户端的连接与消息的中转)
    逻辑层(用户会话的验证,业务逻辑验证,消息存取,异步的消息队列)
    持久层(数据的存储,热冷数据,灾备)

    基本的消息收发流程:发 -> 存 -> 推送通知 -> 拉取消息,同时消息采用基于版本号的设计来保证消息的顺序。

    注:图片来自从0到1:微信后台系统的演进之路

    === 关于连接层
    陌陌之前对外的PPT里讲到单台压测连接数达到70W,这个跟配置、带宽有很大的关系,而蘑菇街的技术博客提到他们单机并发连接10万用户,我觉得单台并发10万相对靠谱一些。

    因为移动网络的不稳定性,比如iPhone来个电话或者按了电源键几秒后,网络都会中断,会导致socket的重连同时也产生非常多的TCP half-open,而防止TCP的half-open通常采用心跳包的机制,而心跳包的频率也是非常有讲究,假设使用移动网络,频率高了费流量不说,还会导致信令风暴【参见 从微信信令风暴谈起】。而时间太长就会导致服务端过多的连接消耗。而心跳的频率具体应该定为多少,建议的话20s左右,具体的时间还跟ISP运营商的策略有关,一条通道多长时间不用就要被回收掉,而如果重新建立一条通道这个时间就会变的比较漫长。

    而服务端如何及时的清理half-open的连接呢
    一种用轮询的方式,每一个连接发消息过来时更新最后收到心跳包的时间,每一少都定时检测所有的连接,超时了就主动断开连接,因为要循环所有连接所以系统性能受影响比较大。
    另外一各就是每一个连接都有一个定时器,超时了自动就断开了,但这会导致系统的资源消耗过高,十万个连接就得有十万个定时器,明显不合理嘛。
    还有一种就是时间轮片(Timing Wheel),详情可参考这里:基于时间轮 (Timing-Wheel) 方式实现的定时器

    而关于连接这一块的优化,可以参考腾讯云提供的维纳期服务
    https://www.qcloud.com/product/wns.html

    后面二块非我所长,我就不具体深入写了,重点可参考微信的那篇文章。针对个人,微信为每一个人同步数据时产生一个唯一、递增的序列号,在高并发的场景下,这个又是如何设计的呢,有兴趣可以参考这篇文章,讲的非常详细:万亿级调用系统:微信序列号生成器架构设计及演变

  • 相关阅读:
    springboot2 整合雪花算法,并兼容分布式部署
    docker 在 linux 搭建私有仓库
    jdbc 几种关系型数据库的连接 和 driver_class,以及简单的使用
    springboot2 整合发送邮件的功能
    oracle 唯一新约束 和 逻辑删除的 冲突处理办法
    oracle 一些常见操作方法
    spring-cloud-stream 整合 rabbitmq
    springboot2 整合 rabbitmq
    docker 安装 rabbitmq 消息队列
    网络统计学目录
  • 原文地址:https://www.cnblogs.com/meteoric_cry/p/5863381.html
Copyright © 2011-2022 走看看