即时消息技术剖析与实战
袁武林
微博研发中心技术专家
立即订阅
6503 人已学习
课程目录
已完结 24 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 搞懂“实时交互”的IM技术,将会有什么新机遇?
免费
基础篇 (8讲)
01 | 架构与特性:一个完整的IM系统是怎样的?
02 | 消息收发架构:为你的App,加上实时通信功能
03 | 轮询与长连接:如何解决消息的实时到达问题?
04 | ACK机制:如何保证消息的可靠投递?
05 | 消息序号生成器:如何保证你的消息不会乱序?
06 | HttpDNS和TLS:你的消息聊天真的安全吗?
07 | 分布式锁和原子性:你看到的未读消息提醒是真的吗?
08 | 智能心跳机制:解决网络的不确定性
场景篇 (4讲)
09 | 分布式一致性:让你的消息支持多终端漫游
10 | 自动智能扩缩容:直播互动场景中峰值流量的应对
11 | 期中实战:动手写一个简易版的IM系统
12 | 服务高可用:保证核心链路稳定性的流控和熔断机制
进阶篇 (10讲)
13 | HTTP Tunnel:复杂网络下消息通道高可用设计的思考
14 | 分片上传:如何让你的图片、音视频消息发送得更快?
15 | CDN加速:如何让你的图片、视频、语音消息浏览播放不卡?
16 | APNs:聊一聊第三方系统级消息通道的事
17 | Cache:多级缓存架构在消息系统中的应用
18 | Docker容器化:说一说IM系统中模块水平扩展的实现
19 | 端到端Trace:消息收发链路的监控体系搭建
20 | 存储和并发:万人群聊系统设计中的几个难点
21 | 期末实战:为你的简约版IM系统,加上功能
22 | 答疑解惑:不同即时消息场景下架构实现上的异同
结束语 (1讲)
结束语 | 真正的高贵,不是优于别人,而是优于过去的自己
即时消息技术剖析与实战
登录|注册

03 | 轮询与长连接:如何解决消息的实时到达问题?

袁武林 2019-09-02
你好,我是袁武林。
我在前面第一篇文章中,从使用场景的需求方面,讲到了 IM 系统的几个比较重要的特性。其中之一就是“消息到达的实时性”。
实时性场景是所有的 IM 系统绕不开的话题,为了支持互联网的“实时互联”的概念,大部分的 App 都需要实时技术的支持。
我们现在使用的聊天类 App、直播互动类 App 都已经在实时性方面做得很好了,消息收发延迟基本都能控制在毫秒级别。
当然这一方面得益于快速发展的移动网络,让网络延迟越来越低、网络带宽越来越高;另一个重要原因是:社交网络 App 在实时性提升方面的技术,也在不断升级迭代。
实时性主要解决的问题是:当一条消息发出后,我们的系统如何确保这条消息最快被接收人感知并获取到,并且尽量让耗费的资源较少。这里关键的几个点是:最快触达,且耗费资源少。
想好了吗?下面我们来看一看,IM 在追求“消息实时性”的架构上,所经历过的几个代表性阶段。

短轮询场景

在 PC Web 的早期时代,对于数据的获取,大部分应用采用一问一答的“请求响应”式模式,实际上,像现在我们浏览大部分门户网站的新闻,以及刷微博其实都是采用的“请求响应”模式。
但这种依赖“手动”触发的模式,在即时消息系统中当有新消息产生时并不能很好地感知并获取到,所以明显不适用于对实时性要求高的场景。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《即时消息技术剖析与实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(54)

  • 王棕生
    TCP 长连接的方式是怎么实现“当有消息需要发送给某个用户时,能够准确找到这个用户对应的网络连接”?
    答: 首先用户有一个登陆的过程: (1)tcp客户端与服务端通过三次握手建立tcp连接;(2)基于该连接客户端发送登陆请求;(3)服务端对登陆请求进行解析和判断,如果合法,就将当前用户的uid和标识当前tcp连接的socket描述符(也就是fd)建立映射关系; (4)这个映射关系一般是保存在本地缓存或分布式缓存中。
             然后,当服务端收到要发送给这个用户的消息时,先从缓存中根据uid查找fd,如果找到,就基于fd将消息推送出去。

    作者回复: 👍

    2019-09-02
    2
    33
  • 菜菜菜菜菜鸟
    TCP不是可靠的吗,为什么还需要在应用层实现ack,不应该是消息发出对方就一定可以收到的吗

    作者回复: 是个好问题。因为很多时候消息由tcp层交给应用层之后还可能出现丢失的情况,比如客户端落本地db失败了,类似这种。

    2019-09-02
    3
    10
  • 飞翔
    服务器维护一个hashmap key是 userid,value 是socket instance, 这样 用户A 发给用户B的信息里边含有用户B 的id, 用usedBid 到hashmap 里边查到 用户B的socket 就可以用socket 发送信息给用户B了,老师我还有一个问题 就是如果一台机器连接数有限, 如果需要多台机器,如果用户A的socker 和用户B的socket 不在一台机器上,这样怎么解决呀

    作者回复: 一种做法是用户上线时维护一个全局的 uid->网关机 的映射,下发的时候就能做到精确定位;另一种方式是:下发时把所有消息下发给所有机器,每台机器如果发现当前用户连接在本机就下发,其他的就丢掉,这种会有一定的资源浪费。

    2019-09-02
    8
    6
  • 魏巍
    服务器端如果突然进程被kill掉,客户端如何及时得到通知并下线?

    作者回复: 进程kill是会对socket执行close操作的哈,所以客户端是能感知到的。真要是通过拔网线的方式把服务端网络断开,这种情况客户端在发送数据时就会失败,然后短连后重连其他服务器就可以了。

    2019-09-03
    1
    4
  • yic
    客户端发送心跳包,一般多久一次比较合适? 我看老师有回复国内不超过5分钟,微信用的是4分半。这个时间有什么依据吗?

    作者回复: 以前有大厂测试过国内各家运营商的NAT超时情况,有的运营商在2/3G网络下NAT超时是5分钟。

    2019-09-08
    1
    3
  • 勇闯天涯
    轮询就是前段定时请求,这个比较了解。但长轮询第一次听说,实际开发也没用过,特别是服务器的“悬挂(hang)”怎么理解? 是HTTP协议的机制吗?

    作者回复: 和http没关系哈,实现上比如接收到一个请求后,通过while循环判断,如果请求时间和当前时间的时间差没有到达超时阈值,就继续查询后端是否有新消息,直到超时或者查询到新消息。

    2019-09-03
    3
  • Shuai
    请问,XMPP是基于 XML 格式的协议,那像微信这种成熟的IM软件的私有通信协议是基于什么格式的呢?二进制吗?

    作者回复: 据我了解微信是私有二进制协议。

    2019-09-02
    3
  • 魏巍
    客户端发送心跳包,一般多久一次比较合适?

    作者回复: 国内的话最好不要超过5分钟,微信应该是4分半。

    2019-09-03
    1
    2
  • 魏巍
    一个linux服务器可以接受多少tcp连接,如何量化这个数字?当业务层对持久化层操作响应慢时,为何客户端会频繁掉线?聊天数据的持久化与下发操作查库对数据库的读写压力如何缓解?实时聊天的数据库如果宕机,能否做自动切换数据库服务器的操作?

    作者回复: 连接数一般不是问题哈,服务端单机几百万上千万都可以的,受限于分配给每个连接的buffer占用的内存。业务层持久化会慢会导致客户端掉线这个没看懂呀,能具体一点吗?第三个问题可以做db的读写分离,第四个问题应该是说db的自动切主吧,这个是可以的哈,很成熟的方案。

    2019-09-03
    2
  • 小可
    用户使用客户端与服务器建立连接时携带了userid与clientid,连接建立成功后,服务器端记录用户、客户端及连接之间的关系。一个可以用户使用多个客户端建立连接,一般是不同类型的客户端(网页、APP),后续有消息可根据此关系进行多端推送。

    作者回复: 👍

    2019-09-02
    2
  • Geek_发现
    说一下我的猜想吧:不管是websocket全双工还是tcp有状态链接,都是应用了ack机制,用户访问服务器,ack会保存用户的信息,服务器收到ack后会开辟一块专有内存来保存所有的客户的ack信息;同理,服务器发送信息至客户,客户端也会保存服务器的ack信息。
    总的来说,客户端和服务器应该都是采用异步方式来提升效率和客户体验,并且降低服务器连接压力

    作者回复: 嗯,ack机制是确保消息被正确接收了,下节课会讲到哈

    2019-09-02
    2
    2
  • 超威丶
    请问websocket为什么能实现实时通信

    作者回复: websocket支持双向全双工的传输,所以可以做到服务端推送,让消息接收更加实时。

    2019-09-02
    3
    2
  • 探索无止境
    老师你好,为什么说一台服务器可以最多可以支持1000万的连接请求,这个数值是怎么推算出来的?

    作者回复: 不具备读写操作仅仅只是维护静态连接的话基本上就是个拼内存的活,调整tcp单连接的读写缓冲区大小到4k,优化下其他系统参数比如句柄限制啥的,建连速度稍微慢点,有个200g内存是没问题的。这里其实想说的是,不要光看单机能维护多少连接,每秒收发包数这些才是关键。

    2019-10-01
    1
  • 技术带头
    老师你好,我们也落地了一套im,服务端和本地都有存储,和用websoket。现在存在一个问题。群聊离线推送是将离线后产生的所有消息再用户上线的时候推送,还是客户端分页拉取

    作者回复: 可以考虑推拉结合,离线消息太多如果全部都推的话性能和带宽上都不太友好,可以离线推送一页,后续的再由客户端来拉取。

    2019-09-08
    1
  • Csquare
    如果产品只有Web端,TCP 长连接和WebSocket相比,还有别的优势么?

    作者回复: 那还是websocket更好一些,很多浏览器默认就支持了呀。。。

    2019-09-04
    1
  • asdf100
    对于连接安全如何搞,如只允许合法的websocket连接到服务器,不允许非法的连接。目前我们是在连接的时候传递一个加密串,在服务器进行解密,不知道是否可行?

    作者回复: 防止客户端的连接伪造是比较困难的哈,比如你的app源代码泄露了,稍微改一改就能仿冒APP连接上来。这种情况可以考虑采用人机验证(比如极验,比如手机验证码)来排除“机器行为”,更极端的可以采取网银的方式,通过客户端插入的U盾来提供真实访问的验证。

    2019-09-02
    1
    1
  • 冷笑的花猫
    请问老师,假设mqtt有两个缺点,不支持离线和群组功能,但可以修改源码增加这两类功能,而且mqtt已基本成熟,在mqtt之上开发不更方便和快捷吗?为啥要在tcp基础上自己开发呢?如果仅仅因为这些选择了了基于tcp自己开发,感觉说服力没那么强啊。
    所以请老师能详细说下这些的优缺点吗?晚上搜索到的感觉不太靠谱,谢谢。

    作者回复: 基于mqtt做二次开发是可以的呀,而且目前也有很多公司已经是这么做的了。只是说有开发能力的大厂更愿意自己来实现一套私有协议,主要是完全根据业务定制化,协议设计上会更高效一些。

    2019-09-02
    1
  • 云师兄
    多终端场景下,用户维度上的应该是一个socket列表。网关接入层是否是有状态的?在进行推送时候需要定位到某台机器?多终端要定位多台机器?

    作者回复: 可以是无状态的,一种做法是用户上线时维护一个全局的 uid->网关机 的映射,下发的时候就能做到精确定位;另一种方式是:下发时把所有消息下发给所有机器,每台机器如果发现当前用户连接在本机就下发,其他的就丢掉,这种会有一定的资源浪费。

    2019-09-02
    1
  • 川杰
    老师您好,请教两个问题:
    1、客户端和服务端只需要完成一次握手,就可以创建持久的长连接,并进行随时的双向数据传输;如果是这样的话,那是不是意味着需要服务器资源去存储这个长连接,那当客户端很多的情况下,服务器资源会不会被大量消耗。
    2、在一些不是html的场景下,如微服务中消息推送,是不是还是只能通过消息队列等方式发送消息?

    作者回复: 1. 映射关系需要服务端存储,有一定的资源开销。
    2. 和html没关系哈,微服务里面的rpc调用也是可以通过tcp长连实现,不一定需要队列。

    2019-09-02
    6
    1
  • 大土豆
    一直有一个疑问,为什么web端不能像客户端一样,用tcp呢

    作者回复: 也是可以的哈,考虑到web端很多浏览器都原生支持websocket协议,实现上更简单,而且web端对于流量相对没有那么敏感,所以web端更多的可以考虑websocket。

    2019-11-11
收起评论
54
返回
顶部