即时消息技术剖析与实战
袁武林
微博研发中心技术专家
立即订阅
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讲)
结束语 | 真正的高贵,不是优于别人,而是优于过去的自己
即时消息技术剖析与实战
登录|注册

08 | 智能心跳机制:解决网络的不确定性

袁武林 2019-09-13
你好,我是袁武林。
在前面的章节里,我讲到了在即时消息场景中非常重要的两个特性:“可靠投递”和“实时性”。
为了让消息能更加实时、可靠、快速地触达到接收方,大部分 IM 系统会通过“长连接”的方式来建立收发双方的通信通道,这些基于 TCP 长连接的通信协议,在用户上线连接时,会在服务端维护好连接到服务器的用户设备和具体 TCP 连接的映射关系,通过这种方式服务端也能通过这个映射关系随时找到对应在线的用户的客户端,而且这个长连接一旦建立,就一直存在,除非网络被中断。
因为“长连接”方式相比“短连接轮询”,不仅能节约不必要的资源开销,最重要的是能够通过“服务端推送”,提供更加实时的消息下发。
同样,对于发送方来说,如果发送消息也能通过“长连接”通道把消息给到 IM 服务端,相对于短连接方式,也能省略 TCP 握手和 TLS 握手的几个 RTT 的时间开销,在用户体验和实时性上也会更好。

为什么需要心跳机制

“长连接”方式给我们带来了众多好处,那么要让消息通过“长连接”实现可靠投递,最重要的环节就在于如何维护好这个“长连接”。
由于这个“长连接”底层使用的 TCP 连接并不是一个真正存在的物理连接,实际上只是一个无感知的虚拟连接,中间链路的断开连接的两端不会感知到,因此维护好这个“长连接”一个关键的问题在于能够让这个“长连接”能够在中间链路出现问题时,让连接的两端能快速得到通知,然后通过“重连”来重新建立新的可用连接,从而让我们这个“长连接”一直保持“高可用”状态。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《即时消息技术剖析与实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(18)

  • tcp keepalive解决网络可用性,应用层keepalive解决网络和服务可用性,应用层无法区别网络还是服务问题,加上tcp心跳包可以进一步区分,有助于客户端做动态调整
    2019-09-13
    14
  • 王棕生
    解答问题:如果从实现功能角度看,传输层和应用层的心跳机制没有结合的必要,因为传输层的心跳探测连接可用性,应用层的心跳机制也可以完成探测; 但从debug角度看,应用层的心跳探测机制无法定位是网络的问题还是系统的问题,此时由传输层辅助就非常好,但实现会相对复杂!

    作者回复: 是的👍

    2019-09-14
    10
  • newzai
    智能心跳,采用什么算法逼近或者选择心跳周期?如何感知当前的心跳周期是否太小?因为一旦太大就会导致连接断开

    作者回复: 比较常见的有二分法。

    2019-09-13
    4
  • 云师兄
    服务端在进行推送时候,假设判断用户连接有效,即用户在线,此时推送是同时推与客户端应用保持的长连接和apns等多条通道吗?然后在客户端去重?还是每次只会选择一条通道?

    作者回复: 会双推,走APNs不会直接落地app的db,苹果会根据应用在前台还是在后台来决定要不要展示APNs走通知栏的消息。现在也有很多应用支持应用在前台时也展示通知栏的消息,看具体需求。

    2019-09-13
    2
  • rfyiamcool
    能简单说下 二分法来进行心跳探测 的逻辑么?

    作者回复: 其实就是下一次动态调整的心跳间隔是:当前已经确认的安全的心跳间隔最大值 和 已经确认的心跳探测过大的最小值 的中间均值。比如上一次心跳间隔是4分钟,而且连续N次都成功ack了,那么当前已经确认的安全的心跳间隔是4分钟,假设已经确认10分钟时心跳间隔过大了,那么下一次调整的心跳就是 4 + 10 / 2 = 7分钟。

    2019-10-24
    1
    1
  • Csquare
    如果用了长连接,怎么支持显示用户在线状态的功能了,保活机制会让用户一直在线吧?

    作者回复: 在线状态可以在用户完成上线操作后记录到uid维度的存储里供使用。保活机制不一定能保证用户一直在线,只是能降低运营商NAT超时导致连接被强制中断的概率,同时通过心跳保活还能及时发现连接是否可用,从而快速进行重连,来提升连接的可用性。

    2019-10-24
    1
  • Geek_e7834d
    看流程图,服务器检查心跳并不是定时的, 而只是推送的时候检测?

    作者回复: 具体是哪个图呀,理解不太对,心跳和推送是独立的,并不会在推送的时候进行检测,一般会由独立的定时器来根据一定时间内socket中是否有数据收发来定时触发的。

    2019-10-17
    1
  • 隰有荷
    看了老师的讲解,在理论上是明白了,但是具体实践上该如何操作?比如:tcp的keepalive该如何通过具体的代码语言去实现。这些具体操作性的知识,不知道本课程后面是否有涉及到?

    作者回复: tcp的keepalive开启比较简单,比如netty下可以通过如下代码开启:

    ServerBootstrap bootstrap = new ServerBootstrap();
    bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);

    另外tcp keepalive的心跳间隔的配置也需要修改一下系统的/etc/sysctl.conf,类似下面:

    net.ipv4.tcp_keepalive_time=120
    net.ipv4.tcp_keepalive_intvl=30
    net.ipv4.tcp_keepalive_probes=3

    2019-09-20
    1
  • 花指令
    老师好,我用go的tcpsocket,有一端异常退出时,另一端会触发掉线通知。所以我不明白的是,socket是不是不需要心跳?还是是因为我是在局域网测试,和公网情况不一样?

    作者回复: 因为tcp本身是一个虚拟连接,中间链路断开的话另一端是感知不到的,另外,移动运营商的NAT会对一段时间没有数据传输的连接切断,所以对于维护高可用的一条长连接心跳是必不可少的。

    2019-09-16
    3
    1
  • dongdong
    请问老师,我这里使用应用层发心跳包,很奇怪在内网测试环境,网页一直不操作都不会断线,但在外网同套代码,不操作1,2个小时后,网页的长链接就会断线,WS脚本重连也连不上,但只要重新刷新页面就可以连上了,这是什么原因?

    作者回复: 心跳间隔是多少?外网的中间路由环节和运营商网络都可能在 一个连接一段时间没有数据传输的时候 从NAT表删除这个连接的映射。所以心跳间隔最好不要大于5分钟。

    2019-09-16
    1
  • Geek_e986e3
    智能心跳的算法是咋样的

    作者回复: 一般可以采用二分法来进行心跳探测。

    2019-09-15
    1
  • A:春哥大魔王
    老师 客户端或服务端心跳实现是在客户端维持一个轮训服务吗?这样会不会有浪费客户端资源的问题,有没有什么好方法解决轮训定时器这种资源浪费问题

    作者回复: 一种方式是客户端采用固定timer来定时发送心跳包,也可以在客户端没有消息收发后的一段时间才可以发送心跳包,这样能节约一些流量。

    2019-09-14
    1
  • wuhaka
    老师您好,您这节只讲了tcp的心跳机制,我觉得可以采用类似QUIC协议,自定义connection id判断逻辑连接状态,无需通过通信五元组来判断是否为同一连接,这样可以避免各种NAT设备,或nginx代理等出现的映射失效问题,在复杂网络环境中不用在频繁断线重连节省开销

    作者回复: 是个好想法,不过QUIC之所以能够实现抽象的connection id应该也是得益于底层依赖的UDP是无状态传输协议,基于TCP之上要解决连接迁移的问题估计会很难。要是你有一些思路咱们可以继续探讨一下。

    2019-10-31
  • leslie
    我觉得可以:毕竟不是完全基于同一层;TCP Keepalive是基于传输层,应用层心跳是基于应用层的,关键在于如何合理组合使用,中间如何去处理。
           昨天某个完课的课程老师告诉我一定要注意知识的关联性:这门课程看了一遍其实是反向再来看的-觉得自己当时没注意一些知识,根据七层网络协议各层分别相互交付而言我认为是可以的;其实关键问题就在于TCP Keepalive的部分事情如何和应用层心跳合理结合-这才是问题处理的难点。
          这个就像早期我们做软件直接CS或BS架构:现在数据系统层往往会多一个No sql DB,用的合理是能解决很多问题-关键难点就在如何合理使用;这是我的个人理解。任何架构做不好完美,不过使用合理可以增强效果/正确率。

    作者回复: 结合使用是没问题的,tcp keepalive和应用层心跳配合使用,当出现消息收发问题的时候,能够协助我们发现是网络层问题还是应用层问题。

    2019-09-16
  • 一步
    我看上图 心跳处理流程,只有客户端当判断连接无效的时候才会进行 连接重连,重连的这个动作服务端不会进行吗? 如果这样的话服务端还要发送心跳消息进行心跳检测做什么呢?服务端是不是可以这样处理,当一段时间没有收到客户端的心跳包的时候就判断与该客户端的心跳连接断开了,直接释放对应的资源不就可以了吗?

    作者回复: 服务端不知道客户端的固定连接地址呀,所以重连一般都是由客户端发起。服务端一般不需要发送心跳,是由客户端来发送心跳,服务端一段时间没有收到客户端的心跳包的时候就可以判断连接异常,主动断开等客户端重连上线就可以了。

    2019-09-14
  • lorancechen
    文章中指出的心跳监测的时间间隔是发送

    作者回复: 是指客户端发送心跳包的间隔。

    2019-09-13
  • 卫江
    问题:心跳机制是不是可以结合tcp的keepalive和应用层的心跳协议?当然可以,不过只使用应用层的心跳协议就可以了,因为一旦应用层的心跳出现问题意味着连接出问题或服务处理不过来,不论什么问题,它更能反应应用真实的整体情况,比如负载均衡与后端服务器之间的应用心跳就能更客观的反应应用情况而便于进一步处理,比如摘除这个后端服务器并报警,而如果只是使用tcp的keepalive的反应的问题就比较片面,只是针对于网络的,而不能反应应用整体的情况,而如果应用整体出问题,连接没有问题也没有什么意义。不过从实现角度来说,tcp的keepalive和使用tcp的应用心跳一起使用并不会增加应用处理网络事件的复杂度,因为基于tcp,我们都是通过read和write来获取连接状态的,所以一起开启也无所谓。
    2019-09-13
  • 老师,有没有应用层心跳包的设计规范及要求的文章推荐的

    作者回复: 心跳包的设计貌似没有固定的设计规范,目的就是尽量精简,比如只包括通用Header的空包,或者body内容是当前心跳间隔(智能心跳可能需要用到)。

    2019-09-13
收起评论
18
返回
顶部