IM即时通讯-N-如何保证消息的可靠性展示

news/2024/5/4 21:48:26/文章来源:https://blog.csdn.net/IEYUDEYINJI/article/details/129265704

结论先行

客户端如何在推拉结合的模式下保证消息的可靠性展示?

  1. 原则: server拉取的消息一定是连续的
  2. 原则: 端侧记录的消息的连续段有两个作用: 1. 记录消息的连续性, 即起始中间没有断层, 2. 消息连续, 同时意味着消息是最新的,消息不是过期的。
  3. 同步协议过载(SyncGapOverflow)时,通过清空会话消息连续段的机制,可以简单粗暴有效的处理同步过载,保证了端侧的连续段一定是连续,并且是最新的
  4. 同步协议过载(SyncGapOverflow)时, 也可以通过端侧不清空连续段的方式, (多个连续段, 中间有间隔)。 会话消息做展示时, 缓存+远端的方式, 保证消息的连续性。 但是这种方式对于历史的消息,可能会存在更新丢失的case, 即消息不是最新的, 因而不推荐使用。如果要使用, 需要配套其他的解决方案。 本文不做展开。
  5. 同步协议中, 需要区分会话消息是新增消息,还是更新消息。两者处理机制不同 新增消息除了入库, 还需要处理消息的连续段; 而更新消息,如果端侧有此消息的缓存, 消息更新,不处理连续段; 没有缓存此消息时, 不需要做消息的更新。
  6. 对于App内发送消息需要特殊处理 App内发送的消息, 仅仅做上屏, 不做连续段, 连续段的更新操作是同步协议下发的此条消息,才会做处理。

引言

同步过载(GAP)指的是,同步协议同步过载,具体是指server向端侧同步时发现端侧是 “首次登录此设备” 或者“ 之前登录过这次再登录”。同步过载的处理细节对于端到端的可靠性展示的重要部分。为了能够更好的解释消息过载, 我们从消息的可靠性入手。
端到端的消息的可靠性, 指的是消息的***可靠性生产***和***可靠性消费***。
此处的消息可以理解为事件。 可靠性生产, 包含了消息不重复生产。
而可靠性消费, 指的是***消息传递时, 不丢失, 不重复, 有序,及时***。

在做及时通讯时, 除了要保证端到端的可靠性传递, 还需要保证展示给用户时, 会话的消息层面的可靠性展示。

什么是可靠性展示

可靠性展示,指的是在用户查看消息时, 展示给用户的消息是***不丢失***的,不重复***的, 并且是***有序,***最新的***的。即有序+不丢+不重+最新

以下我们从简单到复杂, 逐步设计出推拉结合的模式下会话消息的可靠性展示。

通知消息的可靠性展示(普通消费-离店概不负责)

以我们普通的非及时通讯的App为例, 都会有一个消息通知的盒子。 用于接收软件发送给我们的消息。 那么这样的通知消息, 在推拉模式下如何实现呢?

在实现前,先看下这个功能有那些细分的功能。

案例: 西游记开公司了

西游师徒四人开了家西游记的公司, 运营了西游记的App, 主要记录西游记的八十一难以及各路妖怪为什么要这么处理的幕后故事。老板是唐僧, 悟空是CTO, 八戒是运营,沙僧是一线研发。
八戒看到其他的App有通知消息, 于是告知悟空西游记的App也要增加通知消息。悟空指给了沙僧做此项目的负责人。
沙僧先后做了如下的工作,

  1. 功能细分
  2. 技术方案设计
  3. 研发上线等其他工作

细分功能

  1. 展示通知消息的未读数
  2. 展示历史消息
  3. 支持向上翻
  4. 支持实时推送新消息

技术方案

在仅有通知消息的一个单一会话时, 通过***推拉结合***的方式能够很方便的实现此功能。 为了与下文的即时通讯的会话消息的feature匹配,我们将会话单独作为一个功能。与其他篇一致,根据四个场景 用户的新设备登录暂短离线后再次在线用户长期离线后再次在线 以及***用户在线收到消息***做问题解决。

结论先行

  1. 消息的不重复, 不丢失, 有序, 通过推拉结合机制+端内缓存实现的
    不重复和不丢失, 在推送场景下通过ack实现; 在拉取场景下, 通过标记会话的gap, 以及server拉取到的消息是连续的保证的。
    有序, 在推送时保证有序, 在拉取时,保证连续和有序实现的。
  2. 消息与会话完全独立。 消息的未读数由server完全控制。client仅做同步。 如新收到一条未读消息, 那么同步协议需要产生两个事件, 一个是新消息的事件, 另外一个是会话的变更。
  3. 消息过载时,通过清空连续段的方式,可以简单的处理消息过载。即端侧缓存的消息一定是位于连续段中的, 远端仅补充缓存消息两侧消息的方式, 用于保证整体连续。
  4. 消息过载时, 也可以通过增加标记lastMsg与历史消息的连续段的方式。 会话消息做展示时, 缓存+远端的方式, 保证消息的连续性。 这种方式更加标准, 但是却更加复杂。
  5. 消息的同步事件, 仅需要包含新增消息 新增消息是可以追加到队尾的, 消息段自动是连续的。

新设备用户登录

状态图

在这里插入图片描述

具体case处理图示

单一连续段的示意图(同步过载即清空)

在这里插入图片描述

多连续段的示意图(过载不清空)

在这里插入图片描述

逻辑示意图

在这里插入图片描述

Case 用户新设备登录同步与拉取会话

端侧标记SyncGapOverflow的处理 直接在会话层面清空连续段。

Case 点击进入会话

检查是否有连续段: 对于端内没有连续段的或者连续段内的消息列表不满足一屏的, 拉取最新消息; 否则, 直接展示端内缓存的消息即可

Case 翻上一页

携带最上方一条消息的时间戳或者消息id, 做上一页的数据拉取: 直接根据时间戳, 或者最上方一条消息的msgId做分割拉取即可。

Case 实时推送

***处理时, 需要根据lastMsg以及连续段做处理***对于有连续段,并且连续段的截止的消息是lastMsg, 消息追加到前一个连续段;对于端侧没有连续段,新增连续段; 如果消息已经位于某个连续段, 不需要处理连续段; 如果消息未位于某个连续段, 新增连续段。

其他场景

  1. 暂短离线后再次在线与在线同步的逻辑一致, 不再赘述。
  2. 用户长期离线后再次在线, 处理逻辑基本一致, 除了上传的同步位点不同, 以及存储的同步位点不同。
  3. 用户在线收到消息: 同在线同步, 不再赘述。

结论

  1. 消息的不重复, 不丢失, 有序, 通过推拉结合机制+端内缓存实现的
    不重复和不丢失, 在推送场景下通过ack实现; 在拉取场景下, 通过标记会话的gap, 以及server拉取到的消息是连续的保证的。
    有序, 在推送时保证有序, 在拉取时,保证连续和有序实现的。
  2. 消息与会话完全独立。 消息的未读数由server完全控制。client仅做同步。 如新收到一条未读消息, 那么同步协议需要产生两个事件, 一个是新消息的事件, 另外一个是会话的变更。
  3. 消息过载时,通过清空连续段的方式,可以简单的处理消息过载。即端侧缓存的消息一定是位于连续段中的, 远端仅补充缓存消息两侧消息的方式, 用于保证整体连续。
  4. 消息过载时, 也可以通过增加标记lastMsg与历史消息的连续段的方式。 会话消息做展示时, 缓存+远端的方式, 保证消息的连续性。 这种方式更加标准, 但是却更加复杂。
  5. 消息的同步事件, 仅需要包含新增消息 新增消息是可以追加到队尾的, 消息段自动是连续的。

支持撤回或者更新的通知消息的可靠性展示(消费升级-退款)

案例: 西游记App出事了, “端午节快乐”的消息要更新或者撤回

八戒在端午节给大家推送了一条端午节快乐, 被老板唐僧看到后, 说端午节的祝福是端午节安康, 而不是端午节快乐。八戒这时候, 找到沙僧, 能不能将已有的推送信息更改掉? 按照一般的推送消息, 推送只能增加, 却不能删除, 或者更新, 这时候就尴尬了。 八戒找唐僧投诉, 唐僧找悟空投诉, 悟空骂你, 为何当时不支持消息更新或者消息撤回。你说当时没说要支持这个呀。。。 挨了骂, 再次重新设计下吧。

相比较普通的通知消息, 支持撤回以及已有消息的更新, 此新增 feature, 更加符合通知消息的特征。 尤其是对于出现上面的紧急情况, 有此利器, 应对自如。

技术方案

结论先行

  1. 将消息撤回 以及 消息更新的操作统一认作是更新消息,并且仅是逻辑删除, 非物理删除。更新消息,如果端侧有此消息的缓存, 做更新, 没有缓存到, 不需要做更新。
  2. 更新消息, 采用出现同步GAP时, 清空连续段的方式是简单而且有效的, 不建议采用标记多个连续段, 否则逻辑会变得特别复杂。
  3. 对于收取到的实时推送消息, 在会话没有过期时, 需要区分是新增消息还是更新消息,对于更新消息的case下, 检查本地是否存在已有的消息, 如果不存在, 忽略即可, 如果存在,更新消息, 不需要处理连续段。
  4. 其他结论: 同普通的消息通知的处理。

新设备用户登录

状态图

同上, 不变

具体case处理图示

同步过载时不清空连续段示意图

在这里插入图片描述

在上图的场景下,消息更新可以认为有两个场景:

  1. 同步协议未过载时
  2. 同步协议过载时,需要漫游处理时。

同步协议未过载时(对应的场景: 消息更新-同步协议不过载时),通过同步协议可以直接同步到端侧, 消息入库+更新UI即可。
而同步协议过载时(对应的场景是: 消息更新-端内漫游拉取历史), 用户在进入到会话中, 通过漫游拉取的形式时,由于多连续段并未清空, 因而导致以为消息均是有效的, 最终在将连续段合并起来时, m3的消息,依然是老的消息, 不是server的m3_v2的版本的消息。

同步过载时清空连续段的示意图

在这里插入图片描述

同上, 根据两个场景分析,

  1. 同步协议未过载时(对应的场景: 消息更新-同步协议不过载时),通过同步协议可以直接同步到端侧, 消息入库+更新UI即可。
  2. 同步协议过载时(对应的场景是: 消息更新-端内漫游拉取历史), 用户在进入到会话中, 通过漫游拉取的形式时,由于多连续段在发生过载时已经清空, 因而导致以为消息均是无效的, 因而历史消息均是通过漫游拉取下来的。所以消息翻到m3的page时,m3的消息是被server覆盖的, 因而展示的数据便是m3_v2。 保证了消息的准确性。
逻辑示意图

在这里插入图片描述

Case 用户新设备登录同步与拉取会话

同上, 不变

点击进入会话

同上, 不变

翻上一页

同上, 不变

实时推送

  1. 将消息撤回 以及 消息更新的操作统一认作是更新消息,并且仅是逻辑删除, 非物理删除。
  2. 对于收取到的实时推送消息, 需要区分是新增消息还是更新消息,对于更新消息的case下, 不需要处理连续段。

其他场景

  1. 暂短离线后再次在线与在线同步的逻辑一致, 不再赘述。
  2. 用户长期离线后再次在线, 如果采用不清空连续段的方式, 即在后方追加GAP的形式, 更新消息会存在问题, 因为没有办法感知到历史消息的变化。 因而采用单一连续段的形式是比较合适的。
  3. 用户在线收到消息: 同在线同步, 不再赘述。

结论

  1. 将消息撤回 以及 消息更新的操作统一认作是更新消息,并且仅是逻辑删除, 非物理删除。更新消息,如果端侧有此消息的缓存, 做更新, 没有缓存到, 不需要做更新。
  2. 更新消息, 采用出现同步GAP时, 采用清空连续段的方式
  3. 对于收取到的实时推送消息, 在会话没有过期时, 需要区分是新增消息还是更新消息,对于更新消息的case下, 检查本地是否存在已有的消息, 如果不存在, 忽略即可, 如果存在,更新消息, 不需要处理连续段。
  4. 其他结论: 同普通的消息通知的处理。

正常IM单个会话的可靠性展示(生产消息+消费消息)

案例: 唐僧要把通知消息变为公众号对话

西游记App的用户越来越多, 用户对于通知类的消息, 每次都需要点击到具体的消息,而为了促进用户的活跃以及问题能够及时反馈, 唐僧说, 这个通知消息里面,要支持用户跟我们互动: 如我们发起了一个活动, 直接推送一个文案到这个消息里面, 用户可以直接回复消息。 以及用户常见的疑问, 在我们这个里面,我们可以直接解决。悟空说, 这个活本来也是你干的, 现在需要继续想解决方案和实施方案。

思考

核心问题: 生产消息与消费消息两者并存, 如何解决连续性的问题。
上面提到的通知消息以及通知消息支持撤回或者更新的case,解决了生产消息连续段的标记。

而支持发送消息与前面的仅仅展示型的消息是不同的。 发送消息是生产消息,同步与拉取消息是消费消息。出现了生产, 那么端上的处理机制会产生比较大的变化。如:

  1. 发送消息时, 消息未发送成功, 如何跟已经发送成功的消息混排?
  2. 消息发送成功后, 连续段应该如何处理?
  3. 弱网情况下, 如果消息没有同步下来, 但是用户先去发送消息了,这时候连续段又应该如何处理?
  4. 弱网情况下, 用户先发送消息, 并且成功了, 稍后同步过载的事件通知到端上了, 此时的连续段有应该如何处理?
    此时我们会发现, 增加了发送消息后, 技术方案会变得复杂了许多。

技术方案

思路:

  1. 连续段的处理逻辑: 消息漫游触发变更连续段, server的同步事件触发变更连续段, 本地发送的消息, 不触发连续段的计算。
  2. 本地发送的消息虽然不参与连续段的计算, 但是却需要参与数据的展示, 否则, 会导致消息丢失。

根据这个思路, 那么弱网的两种case也是迎刃而解的。

  1. 弱网,消息同步失败,用户先发送消息,发送成功, 稍后,在网络恢复后, 同步消息会同步到端上,只不过此次弱网情况下, 对于用户而言, 有些消息看不到
  2. 弱网, 同步过载事件同步失败, 用户先发送消息, 发送成功, 稍后, 在网络恢复后, 同步过载的事件同步到端上。端上清空连续段, 再次进入到会话时,通过漫游更新的消息内容。

结论先行

  1. 连续段的处理逻辑: 消息漫游触发变更连续段, server的同步事件触发变更连续段, 本地发送的消息, 不触发连续段的计算。
  2. 本地发送的消息虽然不参与连续段的计算, 但是却需要参与数据的展示, 否则, 会导致消息丢失。
  3. 其他结论, 同支持撤回或者更新的通知消息。

具体case处理图示

由于过载不清空连续段存在消息不是最新的case, 因而以下我们只展示过载时清空连续段的方案。
在这里插入图片描述

结论

  1. 连续段的处理逻辑: 消息漫游触发变更连续段, server的同步事件触发变更连续段, 本地发送的消息, 不触发连续段的计算。
  2. 本地发送的消息虽然不参与连续段的计算, 但是却需要参与数据的展示, 否则, 会导致消息丢失。
  3. 其他结论, 同支持撤回或者更新的通知消息。

总结

上文通过三种场景,普通通知消息(不支持撤回/更新历史消息), 支持更新历史消息的通知消息,到最终的正常IM单个会话,通过三种场景, 最终得出客户端如何在推拉结合的模式下保证消息的可靠性展示的关键思路:

  1. 原则: server拉取的消息一定是连续的
  2. 原则: 端侧记录的消息的连续段有两个作用: 1. 记录消息的连续性, 即起始中间没有断层, 2. 消息连续, 同时意味着消息是最新的,消息不是过期的。
  3. 同步协议过载(SyncGapOverflow)时,通过清空会话消息连续段的机制,可以简单粗暴有效的处理同步过载,保证了端侧的连续段一定是连续,并且是最新的
  4. 同步协议过载(SyncGapOverflow)时, 也可以通过端侧不清空连续段的方式, (多个连续段, 中间有间隔)。 会话消息做展示时, 缓存+远端的方式, 保证消息的连续性。 但是这种方式对于历史的消息,可能会存在更新丢失的case, 即消息不是最新的, 因而不推荐使用。如果要使用, 需要配套其他的解决方案。 本文不做展开。
  5. 同步协议中, 需要区分会话消息是新增消息,还是更新消息。两者处理机制不同 新增消息除了入库, 还需要处理消息的连续段; 而更新消息,如果端侧有此消息的缓存, 消息更新,不处理连续段; 没有缓存此消息时, 不需要做消息的更新。
  6. 对于App内发送消息需要特殊处理 App内发送的消息, 仅仅做上屏, 不做连续段, 连续段的更新操作是同步协议下发的此条消息,才会做处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_283735.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】树与二叉树的基本概念及性质

目录 一、树的基本概念 1️⃣树的定义 2️⃣基本术语 3️⃣树的性质 二、二叉树的概念 1️⃣二叉树的定义 2️⃣特殊二叉树 3️⃣二叉树的性质 参考资料 一、树的基本概念 1️⃣树的定义 数据结构中的树是什么❓ 树是 个结点的有限集。有且仅有一个特定的称为根(上图A结点…

零基础教学必会篇(详解字符函数和字符串函数)(完结版)

各位csdn的友友们好,上次阿博给大家讲了一些简单的字符串函数的功能和模拟实现,今天就和阿博一起再上一个台阶继续拿捏它们😊😊😊 文章目录1.strstr的功能介绍2.strstr函数的模拟实现3.strtok的功能介绍4.strerror和pe…

零基础学习Java 06

目录 String String构造方法 字符串查找 字符串截取 字符串替换 字符串拆分 字符串修改 String String类在java.lang包下,所以使用的时候不需要导包。 String构造方法 字符串查找 char charAt(int index),输入位置index,找单个字符 …

MAE论文笔记+Pytroch实现

Masked Autoencoders Are Scalable Vision Learners, 2021 近期在梳理Transformer在CV领域的相关论文,落脚点在于如何去使用Pytroch实现如ViT和MAE等。通过阅读源码,发现不少论文的源码都直接调用timm来实现ViT。故在此需要简单介绍一下timm…

Linux 中的 /dev/random 和 /dev/urandom 是什么?

在Linux系统中,/dev/random和/dev/urandom是两个特殊的设备文件,用于生成随机数。在本文中,我们将深入探讨这两个设备文件的区别,以及它们在Linux系统中的作用。 /dev/random /dev/random是一个随机数生成器设备文件,…

windows10下编译zlib库

系列文章目录 文章目录系列文章目录前言一、问题原因二、准备具体操作编译zlib工程前言 我使用CMake编译zlib源码&#xff0c;出现警告&#xff1a;CMake Deprecation Warning at CMakeLists.txt:1 (cmake_minimum_required): Compatibility with CMake < 2.8.12 will be r…

五、基础初始化(init_sequence)

初始化序列数组 # < lib_arm\board.c > init_fnc_t *init_sequence[] { board_init, /* basic board dependent setup */ timer_init, /* initialize timer */ env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_…

VUE3 学习笔记(七)动态样式 class 实现

目录 一、绑定 HTML class 1. 绑定对象 2. 绑定数组 3. 在组件上使用 二、绑定内联样式 1. 绑定对象 2. 绑定数组 3. 自动前缀 4. 样式多值 数据绑定的一个常见需求场景是操纵元素的 CSS class 列表和内联样式。因为 class 和 style 都是 attribute&#xff0c;我们可…

一道小学题,解答了我与学霸的差距

目录一、背景二、题目三、过程1.形式转换2.个位数相加只能向前进一位嘛&#xff1f;进两位可以吗&#xff1f;进三位呢&#xff1f;3.十位数上要填写的内容&#xff0c;可以是0嘛&#xff1f;你想到了吗&#xff1f;4.如何下意识的去做结构化&#xff1f;四、总结五、升华一、背…

讲一下dns过程:给一个网址www.google.com,dns服务器如何逐级解析的?

DNS 中的域名都是用句点来分隔的&#xff0c;比如 www.server.com&#xff0c;这里的句点代表了不同层次之间的界限。在域名中&#xff0c;越靠右的位置表示其层级越高。域名最后还有一个点&#xff0c;比如 www.server.com.&#xff0c;这个最后的一个点代表根域名。 根DNS服…

UDP套接字

大家好,又见面了,&#x1f389;&#x1f389;&#x1f389;&#x1f338;&#x1f338;&#x1f338; 今天为大家带来UDP套接字的相关知识 文章目录认识socketUDP和TCP认识UDPAPI有关方法基于UDP实现回显服务器UDP的方法基于UDP实现回显程序认识socket UDP和TCP 认识UDPAPI有…

腾讯空降测试工程师,绩效次次拿S,真是砂纸擦屁股,给我露了一手啊

​上周我们公司的绩效面谈全部结束了&#xff0c;每年到这个时间点就是打绩效的时候了&#xff0c;对于职场打工人来说绩效绝对是最重要的事情之一&#xff0c;原因也很简单&#xff1a;奖金、晋升、涨薪都和它有关系。 比如下面这个美团员工在脉脉上的自曝就很凄凉&#xff1…

多种方法解决VS在创建多个源文件后运行时出现的重定义错误:main已经在1.obj中定义

名人说&#xff1a;博学之&#xff0c;审问之&#xff0c;慎思之&#xff0c;明辨之&#xff0c;笃行之。——《中庸》 创作者&#xff1a;Code_流苏(CSDN) 本篇文章收录于&#xff1a;各类问题记录专栏 记录一、原因经过二、解决方法1️⃣方法一 注释2️⃣方法二 生成排除3️⃣…

学习Python的一些知识点记录

一、对象比较 Python中有两种对象比较方式&#xff1a; 值比较。使用比较符号&#xff08;、>、<等&#xff09;标识符比较。使用 is、not 关键字。标识符就是对象在内存中的有效地址&#xff0c;使用 id() 函数可以得到对象的标识符。二、None 对象 这是一个特殊对象…

【Python】数学 - 用 Python 自动化求解函数 f(x) 的值

目录 1、缘起 2、求以下函数的值 3、代码清单 3.1、求解 f(0)、f(1)、 f(​编辑)、f(​编辑) 3.2、求解 g(0)、g(1)、g(​编辑)、g(​编辑) 3.3、求解 h(0)、h(1)、h(​编辑)、h(​编辑) 4、总结 1、缘起 Python 是一种强大的编程语言&#xff0c;它具有广泛的应用领域。…

四、第二阶段

全局数据 声明 # < lib_arm\board.c > DECLARE_GLOBAL_DATA_PTR; 定义 # < include\asm\global_data.h > typedef struct global_data { bd_t *bd; unsigned long flags; unsigned long baudrate; unsigned long have_console; /* serial_init() was calle…

使用adb 命令删除手机预装app

1. 手机开启开发者选项&#xff0c;允许usb调试&#xff1b; 2.pc 安装adb&#xff0c; 1&#xff09;Windows版本&#xff1a;https://dl.google.com/android/repository/platform-tools-latest-windows.zip 2&#xff09;按键windowsr打开运行&#xff0c;输入sysdm.cpl&a…

Go 语言安装部署,两分钟让你写`上Hello World`(包含 goland 开发工具)

Go 语言安装部署&#xff0c;两分钟让你写上Hello World&#xff08;包含 goland 开发工具&#xff09; 第一步下载 Go 安装包 官网 https://golang.google.cn/dl/ 根据自己使用电脑平台选择安装版本 第二步 安装 GO 打开安装包直接点击next下一步 勾选协议&#xff0c;继…

10 kafka生产者发送消息的原理

1.发送原理&#xff1a; 在消息发送的过程中&#xff0c;涉及到了两个线程——main 线程和 Sender 线程。在 main 线程 中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator&#xff0c; Sender 线程不断从 RecordAccumulator 中拉取消息发送到…

CTFHub | 00截断

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…