自研IM系统之监听ChannelInactive触发用户下线的一个坑

最近在一套自研的IM系统上遇到了一些意外的bug,本文特地记录下遇到的场景,并且和大家分享下。

原有im设计

主播用户进入到直播间内时候,正好和im服务器建立了长连接,但是由于主播那边可能会存在一些网络抖动情况,导致im的长连接意外中断重连。而由于im连接在中断之后,会触发Netty的 io.netty.channel.ChannelInboundHandlerAdapter#channelInactive 函数。

而原先的im会在这个 channelInactive 函数的回调处去识别用户已经断线,然后移除相关连接信息,并且发送mq通知给到业务后台处理。

自研IM系统之监听ChannelInactive触发用户下线的一个坑

这种场景就会导致一个特殊的情况,如果用户正好在一个直播间中参与直播,然后因为一瞬间的网络抖动,导致通知给了业务方用户离开了直播间,从而触发了其他业务操作,例如将直播间进行回收,提示其他用户直播间结束等行为。所以为了能对这类网络抖动情况能够做好支持,我们需要设计出对应的解决方案。

支持连接超时

设计一个连接超时器的概念,当某个连接初次断开的时候,可以移除掉本的记录,但是不要立马发送mq通知给到业务方。

可以在连接初次断开的时候,在Redis中记录一个标记,类似String的方式,记录下某个用户刚断开了连接,缓存的有效期是3min。接着发送一个RocketMQ的延迟消息,时隔60s后延迟消息返回消费的时候,判断下这个标记是否还存在。如果客户端在60s内重新建立了连接,那么就需要将这个缓存标记给清空,让RocketMQ的延迟消息在消费的时候查询不到缓存标记。如果延迟消息回来消费的时候,发现缓存标记依然存在,那么就证明客户端正式断线了,然后此时再使用mq通知给到业务方。

基于心跳包检测机制

原先的IM系统中,会采用10000个zset去分散存储用户心跳数据的内容,我们可以通过扫描心跳包的方式,来判断用户是否存活。例如用户连续3个心跳包时间间隔内,没有发送心跳数据给到IM这段,就算用户断线。

这种设计就需要有一个扫描器的概念,定期去这批zset中扫描过期的心跳包对应的userId,然后给这批userId发送下线的MQ通知。

看到这里,你可能还会有有所疑惑,如果我希望用户下线行为能够立马通知到业务方,这种场景要如何实现呢?

制订专门的下线消息包

确实有部分业务场景,需要在用户端下线后,立马发送断线通知给到业务方,例如用户实时会议这类场景。

那么针对这类场景的话,可以让客户端来发起一个特殊的信号包,告知给到IM,说自己要下线了,那么针对这种特殊类的消息包,我们就采取MQ立即发送通知的操作。

自研IM系统之监听ChannelInactive触发用户下线的一个坑

小结

上边是我目前能想到的策略,其实实现起来都比较简单。

第一套,基于MQ的延迟消息去做连接超时检测机制,利用自身的MQ消费去判断是否还有重连行为发生。

第二套,对心跳时间进行扫描,这里需要对Redis做过多的遍历操作,IO开销稍大。

希望看完本文后,能够对你有所帮助。

作者:Danny idea
来源:Idea的技术分享
原文:https://mp.weixin.qq.com/s/lGAFuQlxaaaI0L8Rdkkl3g

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论