实战spring-boot-starter-websocket之断网心跳续期实践

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实战spring-boot-starter-websocket之断网心跳续期实践相关的知识,希望对你有一定的参考价值。

参考技术A

业务中需要应用到Websocket长连接进行数据传输,由于服务使用的是Zuul1.0版本,对ws协议支持较弱,后续尝试使用了 spring-boot-starter-websocket 来完成的。关于怎么集成的话网上有非常多的文章了,我就不多费口舌了。

我们目前实现的功能是可以通过WebSocket调用接口发送埋点,另外还需要监听用户离开的事件为这个埋点画上一个终止访问时间。目前测试下场景有:

前4点触发了任意操作,服务端都会监听到 DISCONNECT 离开事件。但是第5点直接断网, 服务端竟然是无感知的,这个时候产生的问题就是客户断网了,服务端是认为在线的,如果不重新联网登录的话,那么这个用户将会一直一直在线,埋点会一直计算。完了个蛋~

至于为什么断网之后,ws会认为他是在线的, 可能管道打开了之后由于断网导致断开时间发送不出去吧。

我目前能够想到比较简单的办法就是: 心跳续约

捋清了思路,大概就知道如何做了。

然后特意看了下 spring-boot-starter-websocket 的源码,发现其实他有提供此功能。

先说下如何实现:

我们是在在实现了 DelegatingWebSocketMessageBrokerConfiguration 的配置类中重写 configureMessageBroker 方法。

比较关键就是 setTaskScheduler 和 setHeartbeatValue 一个负责调度、一个负责配置间隔。
这俩要么都填要么都不填。

配置了这俩参数之后,服务启动的时候会触发一个 HeartbeatTask 线程来专门维持心跳。

我们可以看看他的流程是如何运转的。

核心任务调度类: org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.HeartbeatTask

服务端在启动的时候 SimpleBrokerMessageHandler 在初始化完成之后会回调 start 的方法,然而他会触发一个 startInternal 开始调度任务,判断依据就是有没有配置 TaskScheduler ( 对应的就是配置类中的setTaskScheduler ),一旦启动之后,会根据你给的心跳数组 serverHeartbeat ,来选择调度时间。

org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler

检测心跳、超过间隔则剔除、并且定期回写心跳给客户端。

还有一点需要注意的是读的间隔时间:
假设用户网络不好,心跳漏发了一次,这个时候如果按照本次的逻辑而言,该用户的最后心跳时间肯定会超时。而它的做法是, 将设定的读超时时间 3 ,就相当于有3次机会*。

这个在创建session的时候 SessionInfo 里面就已经做好了处理:
org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.SessionInfo#SessionInfo

所以这个时候,你可能需要根据业务能够接受的时长去配置,也别忘了这个事。

还有很关键的一点就是让客户端的心跳发送间隔和服务端尽可能保持一致,不然有可能出现莫名其妙的下线情况,尽可能还是在这种地方加好日志。

好了,希望在遇到断网问题的时候,能够帮助到你。

如果有疑问请留言,我会尽快答复。

spring-boot-starter-web包,会导致Gateway启动抛出异常

最近在用springcloud搭建一个web应用时,发现如果添加不要引入spring-boot-starter-web包,会导致Gateway启动抛出异常,故使用

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
就不需要添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--<version>2.1.1.RELEASE</version>-->
</dependency>


网上查了一下发现:Spring Cloud Gateway 是使用 netty+webflux 实现因此不需要再引入 web 模块。










以上是关于实战spring-boot-starter-websocket之断网心跳续期实践的主要内容,如果未能解决你的问题,请参考以下文章

使用 spring-boot-starter-web “找不到可接受的表示”

spring-boot-starter-tomcat 与 spring-boot-starter-web

带有 spring-boot-starter-web 的 Spring Cloud Gateway

无法启动 bean 'webServerStartStop';无法启动嵌入式 Tomcat 服务器 - spring-boot-starter-web

SpringBoot入坑-spring-boot-starter-web配置文件使用

@CrossOrigin 不适用于 spring-boot-starter-web 2.5.2