一、技术选型
有些小伙伴可能不太了解咱们分布式IM即时通讯系统使用了哪些技术和框架,请允许我再唠叨下分布式IM即时通讯系统的技术选型,我们主要使用的技术栈和中间件,整体如下所示。
- 开发框架:SpringBoot、SpringCloud、SpringCloud Alibaba、Dubbo。
- 缓存:Redis分布式缓存+Guava本地缓存。
- 数据库:MySQL、TiDB、HBase。
- 流量网关:OpenResty+Lua。
- 业务网关:SpringCloud Gateway + Sentinel(后续替换成自研网关)。
- 持久层框架:MyBatis、Mybatis-Plus。
- 服务配置、服务注册与发现:Nacos。
- 消息中间件:RocketMQ。
- 网络通信:Netty。
- 文件存储:Minio。
- 日志可视化治理:ELK。
- 容器化管理:Swarm、Portainer。
- 监控:Prometheus、Grafana。
- 前端:Vue。
- 单元测试:Junit。
- 基准测试:JMH。
- 压力测试:JMeter。
在之前的文章中,跟大家透露过:业务网关后续会计划替换成星球的自研网关,这个网关的专栏和视频教程即将给大家安排,值得一提的是,这个网关项目是一个能够应对真实超高并发场景的生产级项目,经实际对比压测,其性能甚至比某些成熟的开源项目还要高,关于网关项目暂时就跟大家透漏这么多,我们拭目以待,哈哈。
为了更好的理解整个分布式IM即时通讯系统如何同时支持发送文本消息、表情消息、图片消息、文件消息、语言消息和双向视频通话,也为了更好的理解消息在整个分布式IM即时通讯系统中的流程过程,在正式演示双向视频通话前,我们再来看看在分布式IM即时通讯系统中消息收发的流程、单聊的交互链路以及群聊的交互链路。
二、消息收发的流程
在分布式IM即时通讯系统中,我们忽略掉其他一些细节信息,重点关注下发送消息的交互链路逻辑。不管是单聊还是群聊,最终都需要通过IM即时通讯服务将消息推送给用户的终端。此时发送消息的流程如下图所示。
图片
可以看到,用户在分布式IM即时通讯系统发送消息时,不管是单聊还是群聊,最终的消息都会推送到用户登录的终端设备上。
假设此时用户A给用户B发送消息,或者用户A和用户B在同一个群组,用户A向群组发送消息,用户B接收消息的主要流程如下。
(1)用户A调用后端平台的接口向用户B发送消息,并且发送的消息中会带有用户B的ID以及终端信息。
(2)后端平台将消息缓存起来,并且会将消息异步写入消息库。
(3)后端平台从Redis中获取用户B连接的IM即时通讯服务的ID。
(4)后端平台获取到用户B连接的IM即时通讯服务的ID后,会向RocketMQ中用户B连接的IM即时通讯服务ID对应的Topic发送消息。
(5)IM即时通讯服务会监听自身服务ID对应的RocketMQ中Topic的消息,此时,用户B连接的IM即时通讯服务会接收到消息。
(6)IM即时通讯服务接收到消息后,会根据用户B的ID以及终端信息从缓存中获取用户B与IM即时通讯服务建立的连接,并且通过这个连接向用户B推送消息。
要实现如上发送消息的流程,前提是要满足如下条件。
(1)后端平台满足分布式条件,可随时横向扩展。
(2)IM即时通讯服务满足分布式条件,可随时横向扩展。
(3)每个启动的IM即时通讯服务实例在集群中都有一个唯一的ID。
(4)每个IM即时通讯服务,都只监听自身ID对应的RocketMQ中Topic的消息。
(4)用户登录分布式IM即时通讯系统后,会与IM即时通讯服务建立长连接,并且会根据用户ID和所在的终端缓存长连接,同时会根据用户ID和所在的终端将连接的IM即时通讯服务的ID缓存到Redis。
(6)用户发送消息时,会根据目标用户的ID和终端从Redis中获取IM即时通讯服务的ID,进而向当前IM即时通讯服务的ID对应的RocketMQ的Topic发送消息。
(7)对应的IM即时通讯服务监听并接收到RocketMQ消息后,会根据目标用户的ID和终端从缓存中获取到用户的连接信息,向目标用户推送消息。
三、单聊交互链路
单聊就是在分布式IM即时通讯系统中,一个用户直接与另外一个用户聊天,也就是一对一的聊天。在这种场景下,很有可能单聊的两个用户中,出现用户不在线的情况。
例如,用户A给用户B发送消息时,用户B可能不在线。此时,我们就需要将用户A向用户B发送的消息存储起来。其实,在我们实现的分布式IM即时通讯系统中,无论把用户B是否在线,都会存储消息记录。当用户B登录系统后,将消息同步给用户B,如下图所示。
图片
可以看到,用户A向用户B发送消息时,如果用户B在线,就可以按照发送消息的交互链路向用户B发送消息了。
如果用户B不在线,此时就无法向用户B正常推送消息。当用户B登录分布式IM即时通讯系统后,就会调用大后端平台的接口拉取所有未读消息,并通过用户B在线流程向用户B推送消息。
四、群聊交互链路
群聊就是在分布式IM即时通讯系统中,多个用户在同一个群组中进行聊天,此时在发送消息时,我们可以通过群组ID找出群内所有在线的用户,将消息即时发送给在线的用户。那些未在线的用户就按照单聊未在线的用户进行处理,如下图所示。
图片
可以看到,群聊的交互链路流程如下所示。
(1)用户调用后端平台的接口向群组发送消息。
(2)后端平台将消息缓存并异步写入消息库。
(3)由于是向群组发送消息,群里有多个用户,此时就会从Redis中获取所有用户连接的IM即时通讯服务ID列表。
(4)对用户按照服务ID分组,将相同服务ID下的用户分在同一个逻辑分组里,方便后续推送消息,并且会记录未在线的用户列表。
(5)循环向每个服务ID对应的RocketMQ中的Topic发送消息。
(6)广播处理未在线用户的未读消息ID。
(7)IM即时通讯服务会监听自身服务ID对应的Topic,会随时接收推送到自身服务的消息。
(8)当IM即时通讯服务接收到消息后,此时用户掉线,或者用户不在线,向用户推送消息就会失败,或者未查询到用户与IM即时通讯服务建立的连接,就不会向用户推送消息。
(9)当用户登录分布式IM即时通讯系统后,会从后端平台拉取历史(离线)消息,并通过用户在线的流程,向用户推送消息。
五、双向视频通话
没错,再说一遍:分布式IM即时通讯系统已经上线双向视频通话功能,至此,已完全支持发送文本消息、表情消息、图片消息、文件消息、语言消息和双向视频通话。所有的功能从需求、原型、设计、架构、编码,到测试、部署、运维,冰河都为你安排的妥妥的。
5.1 原型草稿
我们先来看看分布式IM即时通讯系统设计双向视频通话时的原型草稿,像群组、单聊、群聊等等模块的设计和实现,大家可以到星球通过 专栏+视频+小册+源码+答疑 的方式进行学习,这里不再赘述。
在聊天框上方添加视频呼叫的图标,作为视频呼叫的入口,聊天页面添加视频呼叫按钮的原型设计草稿如下图所示。
图片
当视频呼叫拨通后,好友接受视频呼叫时,双方正在视频通话的原型设计草稿如下图所示。
图片
5.2 展示效果
这里,就拿几个视频通话的效果给大家展示下,像群组、单聊、群聊等等模块的设计和实现效果,大家同样可以到星球通过 专栏+视频+小册+源码+答疑 的方式进行学习,这里不再赘述。
注意:这里我是在同一台电脑不同浏览器上进行测试,由于电脑只有一个摄像头,无法同时显示主动呼叫方画面和被动呼叫方画面,大家可以在不同的电脑上进行测试,由一台电脑的用户呼叫另一台电脑的用户,即可同时看到主动呼叫方画面和被动呼叫方画面。
聊天页面添加视频呼叫按钮如下图所示。
图片
视频通话过程中主动发出视频呼叫的用户画面如下图所示。
图片
视频通话过程中接受视频呼叫的用户画面如下图所示。
图片
再说一遍,哈哈:这里我是在同一台电脑不同浏览器上进行测试,由于电脑只有一个摄像头,无法同时显示主动呼叫方画面和被动呼叫方画面,大家可以在不同的电脑上进行测试,由一台电脑的用户呼叫另一台电脑的用户,即可同时看到主动呼叫方画面和被动呼叫方画面。