分布式websocket即时通信(IM)系统保证消息可靠性【第八期】

b站上面本期视频版本,观看视频食用更佳!点击即可跳转,找不到视频可以直接搜索我 目前叫 呆呆呆呆梦

目前已经写的文章有。并且有对应视频版本。
git项目地址 【IM即时通信系统(企聊聊)】点击可跳转
sprinboot单体项目升级成springcloud项目 【第一期】
前端项目技术选型以及页面展示【第二期】
分布式权限 shiro + jwt + redis【第三期】
给为服务添加运维模块 统一管理【第四期】
微服务数据库模块【第五期】
netty与mq在项目中的使用(第六期)】
分布式websocket即时通信(IM)系统构建指南【第七期】

前言

上一篇中说了一下项目的构成,比较枯燥,一些基本构造方面,这一片呢,一定会更加枯燥。这一篇讲报文协议。后端嘛,不像前端花里胡哨,就是更有内涵一点。为什么这块需要着重说呢,因为聊天系统中需要设计一套保证消息可靠的机制。否则消息都不知道发过去了没有。需要通过报文去保证这些。这些都是需要去设计的。具体设计思路如下。

1.如何保证两个用户之间消息可靠

主要有参考这个
IM消息送达保证机制实现
这篇文章有详细明确了一下消息可靠性的保证;

1.1 正常逻辑

在这里插入图片描述
这个是正常的发送逻辑。客户A发送给服务器,服务器发送给客户B。这个是之前的逻辑,就是正常的发送逻辑;msg:A用于确认客户端消息发送到服务器。但是在这种逻辑中,客户A是不清楚客户B是否收到消息的;,所以由此引入一个确认机制。

1.2带有确认机制

client-B向im-server发送一个ack请求包,即ack:R
im-server在成功处理后,回复client-B一个ack响应包,即ack:A
则im-server主动向client-A发送一个ack通知包,即ack:N

你会发现,一条消息的发送,分别包含(上)(下)两个半场,即msg的R/A/N三个报文,ack的R/A/N三个报文。一个应用层即时通讯消息的可靠投递,共涉及6个报文,这就是im系统中消息投递的最核心技术(如果某个im系统不包含这6个报文,不要谈什么消息的可靠性)。

理论知识讲解完毕,下面是实战演练;

2.具体实践

在这里插入图片描述

如果没有收到ack消息,涉及到消息的重发。
然后中间涉及到消息的重发,在报文中需要字段来确认是否是消息的重发。直接实操一遍看一下经过的报文吧。然后看具体的报文;

0 注册消息报文

{"type":7,"params":{"openid":"56C02DF0516B4B079ABFCEC08169E577","userName":"123","loginStatus":"1"}}

1 用户A:发送消息报文

{
	"type": 1,
	"params": {
		"msgid": "17301",
		"toMessageId": "1879878-NKCNO-NKNK",
		"message": "我要发消息啦",
		"fileType": 0,
		"isretry": false
	}
}

2 用户A:客户端确认

{
	"type": -1,
	"params": {
		"date": "Thu Jan 18 18:38:27 CST 2024",
		"msgid": "17301",
		"online": true,
		"message": "我要发消息啦",
		"isretry": "false"
	},
	"status": 200
}

3 用户B:收到消息

{
	"activeTime": 1705574308625,
	"from": "system",
	"messageId": "17301",
	"msg": {
		"type": 2,
		"params": {
			"fromUser": {
				"openid": "56C02DF0516B4B079ABFCEC08169E577",
				"loginStatus": "1",
				"userName": "123"
			},
			"message": "我要发消息啦",
			"fileType": "0"
		},
		"status": 200
	},
	"msgType": 1,
	"requestId": "08808d38-3d4c-4b80-9f9c-9c19dfe1163e",
	"sessionId": "192.168.56.1:8084_1879878-NKCNO-NKNK_20240118183556",
	"to": ["1879878-NKCNO-NKNK"],
	"trigger": 1
}

4 用户B:发送ACK

{"type":15,"params":{"from":"client","msgid":"17301","fromUser":"56C02DF0516B4B079ABFCEC08169E577","toUser":"1879878-NKCNO-NKNK"}}

5 用户B:收到服务器确认消息

{"type":16,"params":{"date":"Thu Jan 18 18:38:28 CST 2024","message":"17301"},"status":200}

6 用户A:客户端收到ack消息 流程结束

{
	"activeTime": 1705574308647,
	"from": "system",
	"messageId": "17301",
	"msg": {
		"type": 17,
		"status": 200
	},
	"msgType": 1,
	"requestId": "85a16365-6a1d-4ce1-8f99-c49a583ed1d0",
	"sessionId": "192.168.56.1:8084_56C02DF0516B4B079ABFCEC08169E577_20240118183655",
	"to": ["56C02DF0516B4B079ABFCEC08169E577"],
	"trigger": 1
}

7 消息落库报文

{
	"activeTime": 1705574309525,
	"from": "system",
	"messageId": "17301",
	"msg": {
		"type": 18,
		"status": 200
	},
	"msgType": 1,
	"requestId": "4ad1af60-56e4-4718-a668-8d94243a2173",
	"sessionId": "192.168.56.1:8084_56C02DF0516B4B079ABFCEC08169E577_20240118183655",
	"to": ["56C02DF0516B4B079ABFCEC08169E577"],
	"trigger": 1
}

基本步骤如上.

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式 Websocket 是指在集群环境下,实现多台机器之间共享 Websocket 连接和消息推送的方案。在单机情况下,由于用户已经与 Websocket 服务建立连接,消息推送是可以成功的。但在集群环境下,用户与 Websocket 服务建立连接的服务可能与需要给用户推送消息的服务不一致,这就需要解决分布式环境下的 Websocket 连接共享问题。 针对分布式 Websocket 的解决方案,可以考虑以下几种思路: 1. 将 Websocket Session 序列化并存储到 Redis,实现数据共享。在 Spring 集成的 Websocket 中,每个 WS 连接都有一个对应的 Session,称为 WebSocketSession。但是,由于 WS Session 无法直接序列化到 Redis,无法将所有 WebSocketSession 缓存到 Redis 进行 Session 共享。 2. 使用中间件或消息队列来实现分布式消息推送。可以使用诸如 RabbitMQ、Kafka 等消息队列服务,将需要推送的消息发送到消息队列,然后由各个 Websocket 服务订阅相应的消息队列,实现消息的分发和推送。 3. 使用负载均衡器和会话粘性(session affinity)来保证用户的 Websocket 连接始终与同一台服务器保持连接。负载均衡器负责将用户的请求分发到不同的服务器上,而会话粘性则会保证用户的后续请求都会路由到与其最初连接的服务器上,从而保持连接的连贯性。 在实现分布式 Websocket 的过程中,需要根据具体的应用场景和需求选择适合的方案,并结合实际情况进行实现和调优。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值