热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

场景之心跳应用

一、心跳概述常见的IM类应用,比如游戏,直播,聊天室或者客服系统,一般都要依靠服务端做消息中转,将从发送方接受的消息推送给接收方,为保证可靠,快速到达对端,⼤部分IM使⽤长连接建⽴

一、心跳概述

常见的IM类应用,比如游戏,直播,聊天室或者客服系统,一般都要依靠服务端做消息中转,将从发送方接受的消息推送给接收方,为保证可靠,快速到达对端,⼤部分IM使⽤长连接建⽴通道,并且建⽴TCP连接和用户设备的映射关系,长连接⼀旦建⽴,就会⼀直存在,除非意外被中断,并依靠该链接接受和推送消息。

心跳机制存在的意义:这个长连接并不是物理意义上的连接,⽽是⼀个无感知的虚拟TCP连接,即使断开两端也不会感知,因此心跳机制来让连接在出现问题的时候,迅速的让对端感知到,心跳要做的就是快速不间断的识别来探测连接可⽤性。


1、心跳机制在长连接维护的必要性



  • 降低服务端维持连接的开销:服务端除了维持⽹络连接和用户设备的映射之外,还会保存⼀些包括app版本号,os系统类型等信息,这些信息第⼀次建立连接发送,以后都维持到服务端缓存,如果存在⼤量的断开的连接,就会造成具柄和缓存的浪费,因此⼼跳机制保证了在连接断开后尽早的清理服务端连接使⽤的资源。



  • ⽀持客户端断线重连:⼀般移动设备连接的都是运营商的内网,⽽IPv4地址总共约为43亿个,因此为了节省IP地址资源,运营商通常会采⽤NAT⼿段,为联⽹设备分配内⽹IP,变成了内网IP:port-外网IP:port的映射,使得内网IP的⼿机能和外网联通,但为了提⾼IP利⽤率,如果⼀个连接⼀段时间没有数据收发,运营商就会把这个映射从NAT映射表清除掉,为了避免长连接被被运营商下掉,就需要长跳机制定期发送⼀些数据对连接让运营商以为这个链接还在用从而进行保活。




2、心跳实现方式

一般有三种:



  • TCP层⾯的keep-alive,发送端在发送完数据给接收方之后,接收方会启动一个超时计时器,每当计时器超时就会发送探测报⽂给发送方,心跳包不携带数据,累计10次心跳包没有回应则认为链接失效断开了。协议栈实现使⽤资源最少,但是心跳间隔设置不灵活,TCP的keep-Alive只代表链接层,不代表应⽤层可⽤,比如代码死锁,同样tcp链接可用,但是服务已经不可用了。

  • 应⽤层心跳:应⽤层⼼跳实际上就是客⼾端每隔⼀定时间间隔,向IM服务端发送⼀个业务层的数据包告知自⾝存活。相比TCP心跳,更灵活设置心跳间隔和更可⽤状态的保活。

  • 智能心跳:避免NAT超时,只能将心跳间隔设置为小于所有网络环境下NAT超时的最短时间。但是定期心跳,会有CPU和网络流量的浪费,因此提出智能心跳,根据网络环境自动调整心跳间隔的时间,逐渐逼近NAT超时临界点,优化心跳间隔。


3、总结

⼼跳作⽤:



  • 降低服务端连接维护⽆效连接的开销

  • ⽀持客⼾端快速识别⽆效连接,快速重连

  • 连接保活,防⽌被运营商NAT超时端开。

问题:可否结合TCP的keep-Alive和应⽤层心跳使⽤?

tcp的keep-alive解决网络可⽤性,应⽤层keep-alive解决⽹络和服务可⽤性,但是应⽤层无法区分网络还是服务问题,因此加上tcp心跳包可以进⼀步区分,tcp心跳探测到链接正常,而此时应用层通信出现问题,则可能是服务出现问题。


二、心跳实现示例


1、注册中心

微服务项目中为了让客⼾端知道具体服务部署的地址,通常要使用服务注册中心。


(1)、注册中心解决问题



  • 提供服务地址的存储

  • 存储内容发⽣变化,变更内容推送到客⼾端

通过注册中心,即使需要扩容,或者摘除节点,也不⽤重启客⼾端服务器。



  • 客户端会与注册中心建⽴连接,并且告诉注册中心,它对哪⼀组服务感兴趣;

  • 服务端向注册中心注册服务后,注册中心会将最新的服务注册信息通知给客⼾端;

  • 客⼾端拿到服务端的地址之后就可以向服务端发起调⽤请求了。


(2)、服务状态如何管理

主动探测:服务要打开⼀个端口,然后由注册中心每隔⼀段时间(比如30秒)探测这些端口是否可⽤,如果不可⽤就从服务列表摘除。

问题:



  • 服务节点都需要开放⼀个统⼀端⼝给注册中心探测,端⼝可能被互相占⽤。

  • 服务器部署很多,探测对于注册中⼼的代价也很高,服务不可⽤的时候还会有延迟。

心跳机制:服务节点注册到服务中心后,会按照⼀定的时间间隔向注册中心发送心跳包,注册中心收到后会更新最新续约时间,启动⼀个定时器,如果⼀定时间还没有收到心跳,就认为服务不可⽤。服务也需要检测是否存活,那么也可以考虑使⽤心跳机制来检测


2、聊天室心跳应用和实现

在即时通信系统中,比如聊天室,一般都是采用发送方与服务器建立一条TCP连接,接收方也会与服务器建立一条TCP连接。

首先用户有⼀个登陆的过程:



  • tcp客户端与服务端通过三次握⼿建立tcp连接。

  • 基于该连接客户端发送登陆请求。

  • 服务端对登陆请求进⾏解析和判断,如果合法,就将当前用户uid和标识当前tcp连接的socket描述符(也就是fd)建⽴映射关系。

  • 这个映射关系⼀般是保存在本地缓存中。

  • 然后当服务端收到要发送给这个用户的消息时,先从缓存中根据uid查找fd,如果找到,就基于fd将消息推送出去。


(1)、心跳实现逻辑

因为要基于该TCP连接发送消息,所以要先保证该连接的可靠性,因此要使用如上中所说要通过心跳及时的探测到链接的是否仍有效。

逻辑如下:



  • 用户与服务器建立TCP连接

  • 用户每隔几秒向服务器发送心跳包

  • 服务端在收到心跳包之后,更新用户的最后在线时间

  • 服务端同时有一个定时脚本,定时脚本每隔一段时间执行一次扫描所有的用户的最后在线时间与现在时间对比,如果超过设置的超时时间,则重连或者清空相应服务端缓存资源给出对应操作。


(2)、hash结构具体实现

实现上:可以用redis的hash结构,配合记录所有的用户的最后在线时间。



hash结构中字符串是一个key对应一个value,value中通常只有一个对应key的数据,而hash中,把很多个数据(field:value)存到一个value中,Hash类型可以看成具有String Key和String Value的map容器添加和删除操作都是O(1)(平均)的复杂度,每个hash可以存储232-1 键值对(40多亿),操作复杂度和存储上限一般不会有问题。

hash的key为chat-room,表示这是聊天室key。

当用户发送心跳,设置hash字段,field为user_id,value为当前系统时间戳

hset chat-room user_id time.Now().Unix()

服务端定时脚本检测逻辑如下

res = hgetall chat-room # 将hash所有字段fields和value保存在res字典中
for field, value := range res: # 遍历所有字段,也就是查看所有用户的上一次心跳时间
if time.Now().Unix() - value > 60 * 3: # 如果上一次心跳距离现在超过3分钟,则认为连接断开,连接资源。
clearConnect()


推荐阅读
  • Centos下安装memcached+memcached教程
    本文介绍了在Centos下安装memcached和使用memcached的教程,详细解释了memcached的工作原理,包括缓存数据和对象、减少数据库读取次数、提高网站速度等。同时,还对memcached的快速和高效率进行了解释,与传统的文件型数据库相比,memcached作为一个内存型数据库,具有更高的读取速度。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
author-avatar
大眼妹PS珺珺
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有