即时通讯系列-N-客户端如何在推拉结合的模式下保证消息的可靠性展示

news2024/11/27 15:36:11

结论先行

  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.coloradmin.cn/o/402603.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java学习-MySQL-创建数据库表

Java学习-MySQL-创建数据库表 SHOW DATABASESUSE school CREATE TABLE IF NOT EXISTS student( id INT(10) NOT NULL AUTO_INCREMENT COMMENT 学号, name VARCHAR(30) NOT NULL DEFAULT 匿名 COMMENT 姓名, pws VARCHAR(20) NOT NULL DEFAULT 123456 COMMENT 密码, sex VARCHA…

算法题--二叉树(判断是不是平衡二叉树、二叉树的中序遍历、二叉树最大深度、对称二叉树、合并二叉树)

目录 二叉树 题目 判断是不是平衡二叉树 题链接 解析 核心思想 答案 二叉树的中序遍历 原题链接 解析 核心思想 答案 二叉树最大深度、对称二叉树、合并二叉树 二叉树 该类题目的解决一般是通过节点的遍历去实现,一般是分两种。 一是递归(…

【记录】日常|shandianchengzi的三周年创作纪念日

机缘 接触 CSDN 之前,我已经倒腾过 hexo 搭建 github 博客、本地博客、图床;   接触 CSDN 之后,我还倒腾过纸质笔记、gitee 博客、博客园、知乎、b站、Notion、腾讯文档、有道云笔记、XMind、飞书文档、简书等一系列创作平台,但…

SAPUI5开发01_01-Installing Eclipse

1.0 简要要求概述: 本节您将安装SAPUI 5,以及如何在Eclipse Juno中集成SAPUI 5工具。 1.1 安装JDK JDK 是一种用于构建在 Java 平台上发布的应用程序、Applet 和组件的开发环境,即编写 Java 程序必须使用 JDK,它提供了编译和运行 Java 程序的环境。 在安装 JDK 之前,首…

1635_fileno的简单使用

全部学习汇总: GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 在看MIT的OS课程的时候发现自己动不动就因为只是的缺少而卡住,而这个学习占据了我工作之余很多的时间。现在都有一点觉得通关不了的感觉了,…

1. Qt Designer Studio界面介绍

1. 说明: Qt当中的Qt Quick框架使用QML语言来快速搭建优美的界面,但是对于单纯做界面的设计人员并不是很友好,还要让界面设计人员去消耗时间成本学习QML语法。Qt Designer Studio软件就是为了解决这个问题而设计的,工作人员不需要…

【Blender】Stability AI插件 - AI生成图像和动画

Stability AI 的官方插件允许 Blender 艺术家使用现有的项目和文本描述来创建新的图像、纹理和动画。 推荐:用 NSDT场景设计器 快速搭建3D场景。 1、安装Stability for Blender插件 首先,从这里下载最新版本的 Blender,然后转到 Addon Relea…

论文阅读笔记|大规模多标签文本分类

多标签文本分类(Extreme Multi Label Classification, MLTC)是自然语言处理领域中一个十分重要的任务,其旨在从一个给定的标签集合中选取出与文本相关的若干个标签。MLTC可以广泛应用于网页标注,话题识别和情感分析等场景。大规模…

1636_isatty函数的功能

全部学习汇总: GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 前面刚刚看完了一个函数和三个文件指针,一行代码懂了半行。但是继续分析我之前看到的代码还是遇到了困难,因为之前自己对于UNIX的一些基础知…

网络协议(十四):WebSocket、WebService、RESTful、IPv6、网络爬虫、HTTP缓存

网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类、ISP、上网方式、公网私网、NAT 网络…

Kubernetes(K8s)接入Prometheus示例、查看指标

Prometheus安装关联服务见:https://blog.csdn.net/lsc_2019/article/details/129445580?spm1001.2014.3001.5502 在Kubernetes中创建一个Deployment和一个Service apiVersion: apps/v1 kind: Deployment metadata:name: myapp spec:replicas: 3selector:matchLabe…

Jackson 返回前端的 Response结果字段大小问题

目录 1、问题产生的背景 2、出现的现象 3、解决方案 4、成果展现 5、总结 6、参考文章 1、问题产生的背景 因为本人最近工作相关的对接外部项目,在我们国内有很多程序员都是使用汉语拼音或者部分字母加上英文复合体定义返回实体VO,这样为了能够符合…

数据表(三) - 多语言的实现

前文介绍了关于数据表的几种形式,以及如何让数据表运用更加简单高效,这篇我们来讲讲多语言在数据表中的实现方式。游戏项目中文字显示本身就是件比较头疼的事,再加上多语言,更多的问题将待需解决。很多时候项目起初,文…

Golang-GMP模型

写在前面 Go 为了自身 goroutine 执行和调度的效率,自身在 runtime 中实现了一套 goroutine 的调度器,下面通过一段简单的代码展示一下 Go 应用程序在运行时的 goroutine,方便大家更好的理解。 The Go scheduler is part of the Go runtime,…

华为机试题:HJ92 在字符串中找出连续最长的数字串(python)

文章目录(1)题目描述(2)Python3实现(3)知识点详解1、input():获取控制台(任意形式)的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方…

C++语法规则2(C++面向对象)

继承 面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。 当创建一个类时,您不需要重新编写新的数据成员和成…

SpringBoot修改启动图标(详细步骤)

目录 一、介绍 二、操作步骤 三、介绍Java学习(题外话) 四、关于基础知识 一、介绍 修改图标就是在资源加载目录(resources)下放一个banner.txt文件。这样运行加载的时候就会扫描到这个文件,然后启动的时候就会显…

vue -- 自定义指令钩子函数补充 自定义过滤器filter参数

自定义指令补充 自定义指令通过钩子函数的形式来实现自定义的功能 这里是几个常用的钩子函数以及它的方法: bind:只调用一次,指令第一次绑定到元素时调用,在这里可以进行一次性的初始化设置。 inserted:被绑定元素插…

Docker Nginx 反向代理

最近在系统性梳理网关的知识,其中网关的的功能有一个是代理,正好咱们常用的Nginx也具备次功能,今天正好使用Nginx实现一下反向代理,与后面网关的代理做一个对比,因为我使用的docker安装的Nginx,与直接部署N…

web worker的基本使用案例

文件目录如下 代码按照顺序分别如下 webworker.html <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewpo…