【IM】如何保证消息可用性(一)

目录

  • 1. 基本概念
    • 1.1 长连接 和 短连接
    • 1.2 PUSH模式和PULL模式
  • 2. 背景介绍
    • 2.1 理解端到端的思想
  • 3. 方案选型
    • 3.1 技术挑战
    • 3.2 技术目标

1. 基本概念

在讲解消息可用性之前,需要理解几个通信领域的基本概念。

1.1 长连接 和 短连接

  • 什么是长连接,短连接
    在HTTP/1.0中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。如果客户端浏览器访问的某个HTML或其他类型的 Web页中包含有其他的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话。

    但从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:

     Connection:keep-alive
    

    在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接要客户端和服务端都支持长连接。

    HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接


  • TCP的长连接和短连接

    • 对于TCP短连接,一般由客户端发起三次握手,经过一次读写操作后,由客户端发起四次挥手,断开连接。短连接的优点在于管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段

    • 对于TCP长连接,简单来说,client向server发起连接,server接受client连接,双方建立连接。Client与server完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。

      连接本身是一种资源,连接建立后,server需要保存相关的状态信息,如果客户端已经关闭,此时的状态信息就白白占用了server的资源,因此需要保活功能的存在: 保活功能主要为服务器应用提供,服务器应用希望知道客户主机是否崩溃,从而可以代表客户使用资源。如果客户已经消失,使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,则服务器将应远等待客户端的数据,保活功能就是试图在服务 器端检测到这种半开放的连接。
      如果一个给定的连接在两小时内没有任何的动作,则服务器就向客户发一个探测报文段,客户主机必须处于以下4个状态之一:正常运行,已经崩溃,客户主机崩溃并已经重新启动,客户机正常运行但是服务器不可达(弱网环境)

  • 长短连接的选择
    根据之前的介绍,我们已经能感受到长短连接的优缺点。长连接通常用于收发频繁的场景,尤其是点对点通信,比如IM,数据库;而短连接通常用于请求不频繁的情况,比如一般的WEB网站,对于网页资源的请求一般不会十分频繁。

  • 简单的TCP长连接服务器DEMO
    TCP的保活机制保证了传输层的连接可用性,但是如何保证应用层的连接,需要我们做跟多的工作,之后会单独讲解。

    package mainimport ("log""net""time"
    )func main() {// 创建 TCP 连接conn, err := net.Dial("tcp", "127.0.0.1:80")if err != nil {log.Fatal("Failed to connect:", err)}defer conn.Close()// 将连接转换为 TCPConn 类型tcpConn, ok := conn.(*net.TCPConn)if !ok {log.Fatal("Failed to convert to TCPConn")}// 设置 KeepAlive,启用 TCP 连接的 KeepAlive 功能if err := tcpConn.SetKeepAlive(true); err != nil {log.Fatal("Failed to set KeepAlive:", err)}// 设置 KeepAlive 周期,每隔一段时间发送一个 KeepAlive 包if err := tcpConn.SetKeepAlivePeriod(10 * time.Second); err != nil {log.Fatal("Failed to set KeepAlive period:", err)}// 在这里进行其他操作,保持 TCP 连接处于活跃状态
    }

1.2 PUSH模式和PULL模式

这个比较简单,可以理解为GIT里的push和pull.服务器主动向客户端发数据叫做push,客户端向客户端请求数据叫做pull

2. 背景介绍

在IM场景下,消息的可用性包含两个方面:可靠性和一致性,可以总结为:可达有序,不重不漏

  • 可靠性:消息一旦显示发送成功,则一定到达对端
  • 一致性:任何时刻消息保证由于发送端的发送顺序一致

2.1 理解端到端的思想

在设计IM系统的时候,最重要的思想是 端到端思维:

端到端原则是一种分布式系统中各个模块之间功能定位的设计原理,指的是从代价和性能的角度出发,在网络的最核心的部分应该只去做数据的传输而不能去做一些其他的应用,而数据是否正确传输则应该放到应用层去检查和判断,从而保证互联网核心的简单性,可维护性,可拓展性。

简单的理解端到端思想,可以以数据传输的可靠性为例子,在网络中传输文件,传输错误可能发生在端到端路线的多个节点,也许我们可以通过在每一个交换节点上都加入数据校验,超时,重传的机制来保证数据正确,但是,实际上,可能错误可能发生在端系统的自身,比如磁盘存取错误,缓存不足。这样一来,即使中间节点提供了数据的可靠,端系统也没有任何工作量的减少,依然需要进行正确性的检测。 因此,在中间节点只需要提供其能完全实现的功能,即路由转发即可。

OSI七层模型也是端到端思想的产物,主机网络的每一层都是一个端系统,只对本层负责,保证本层数据可靠,不保证上层数据可靠。这样的设计使得每一层功能不重叠,结构清晰:

  • 数据链路层(第二层)和物理层(第一层): 这两层负责将数据转换为比特流并通过物理介质传输。在端到端原则下,这些层不应对数据进行处理,而应只负责将数据从一个点传输到另一个点。
  • 网络层(第三层): 数据在网络中进行路由和转发,以便从计算机 A 到计算机 B。在端到端原则下,网络层应该提供最佳的数据传输路径,但不对数据进行修改或过滤
  • 传输层(第四层): 数据被传输到传输层,以便在计算机 A 和 B 之间进行可靠的数据传输。在端到端原则下,传输层负责数据的分段、重传和错误检测,以保证数据的完整性和可靠性

由此我们可以总结:底层可靠性仅能保证底层可靠,不对上层负责。传输层已经帮我们做到了数据的完整和可靠,但是并不能说它能保证应用层的可靠了


那么TCP到底做到了哪一步,我们又需要做哪些工作呢?
在这里插入图片描述
现在假设一个场景(应用层不做可用性处理):clientA发送msg1和msg2到server,两个消息通过一个长连接到达了服务端,此时可能会出现下面这些情况:

  1. msg1和msg2到达应用层,分别由一个线程去处理,msg2先落表成功,发送给clientB,造成数据乱序。
  2. msg1在server落盘失败,msg2成功,先发送给了clientB,造成数据丢失,乱序。
  3. 消息在由接入层到达业务层的时候,server进程崩溃,但是此时clientA认为已经送达,服务端业务无法感知,消息丢失。

因此对于IM这种三方通信来说,TCP/UDP的保证是远远不足够。

消息的端到端可用性 = 上行消息可用 + 服务端业务可用 + 下行消息可用

3. 方案选型

如何设计一个保证消息端到端可用性的协议是我们的本文的最重要任务。

3.1 技术挑战

  1. 三方通信,难以保证网络上的消息必达
  2. 没有全局时钟,那一确定唯一顺序,因果顺序
    • 时钟零点漂移问题:时钟零点漂移通常指的是在计算机系统中时钟的偏移或漂移,这可能会导致时钟与实际时间之间存在误差。这种情况可能由多种因素引起,包括硬件时钟的不准确性、操作系统的时钟管理、系统负载等。
      可行的解决方式有:
      • 使用网络时间协议(NTP): NTP 是一种用于同步计算机时钟的协议,可以从互联网上的时间服务器获取准确的时间信息,并调整本地时钟以匹配其时间。在大多数操作系统中,可以配置系统以自动与 NTP 服务器同步时间。
      • 定期同步时间: 即使已启用自动同步时间功能,也建议定期手动同步一次时间,以确保时钟的准确性
      • 减少系统负载: 高负载的系统可能会影响时钟同步的准确性。尽量减少系统的负载,特别是在进行时钟同步时
  3. 消息顺序性在多客户端,多服务端,多线程/协程下那一保持

3.2 技术目标

对消息可用性的进一步细化:

  1. 消息及时:实时接收,发送 (响应时间<=200ms,高峰期 <=1s)
  2. 消息可达:超时重试,ACK确认
  3. 消息幂等(每条消息只处理一次):分配seqId,服务端存储seqId
  4. 消息有序:seqId可比较,接收端可以按照发送端的顺序进行消息排序 (一个会话内保证消息有序即可)

在下一篇文章中,我们将探讨更加具体的实现方案。

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

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

相关文章

MQ面试题之Kafka

前言 前文介绍了消息队列相关知识&#xff0c;并未针对某个具体的产品&#xff0c;所以略显抽象。本人毕业到现在使用的都是公司内部产品&#xff0c;对于通用产品无实际经验&#xff0c;但是各种消息中间件大差不差&#xff0c;故而本次选择一个相对较熟悉的Kafka进行详细介绍…

YoloV8改进策略:BackBone改进|DCNv4最新实践|高效涨点|多种改进教程|完整论文翻译

摘要 涨点效果:在我自己的数据集上,mAP50 由0.986涨到了0.993,mAP50-95由0.737涨到0.77,涨点明显! DCNv4是可变形卷积的第四版,速度和v3相比有了大幅度的提升,但是环境搭建有一定的难度,对新手不太友好。如果在使用过程遇到编译的问题,请严格按照我写的环境配置。 …

RBD —— Fracture SOP

目录 Assemble —— 清理破碎操作并生成碎片 Boolean Fracture —— 使用切割面破碎输入的几何体 Convex Decomposition —— 将输入几何体分解为凸线段 Glue Cluster —— 构建cluster值想glue约束添加强度 RBD Material Fracture —— 基于材质类型预破碎 Concrete Gl…

C++ 之LeetCode刷题记录(二十)

&#x1f604;&#x1f60a;&#x1f606;&#x1f603;&#x1f604;&#x1f60a;&#x1f606;&#x1f603; 开始cpp刷题之旅。 依旧是追求耗时0s的一天。 110. 平衡二叉树 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二…

RK3588平台开发系列讲解(视频篇)RKMedia框架

文章目录 一、 RKMedia框架介绍二、 RKMedia框架API三、 视频处理流程四、venc 测试案例沉淀、分享、成长,让自己和他人都能有所收获!😄 📢RKMedia是RK提供的一种多媒体处理方案,可实现音视频捕获、音视频输出、音视频编解码等功能。 一、 RKMedia框架介绍 功能: VI(输…

【牛客刷题】笔试选择题整理(day1-day2)

每天都在进步呀 文章目录 1. 小数求模运算2. 进程的分区&#xff0c;这里说的不是JVM的分区。进程中&#xff0c;方法存放在方法区。3. 访问权限控制4. 继承与多态5. 与equals()6. 类加载顺序7. super()与this()7.1 super7.1.1 super调用父类构造方法7.1.2 super调用父类属性和…

私人漫画图书馆:分类管理,一目了然 | 开源日报 No.157

tachiyomiorg/tachiyomi Stars: 26.9k License: Apache-2.0 tachiyomi 是一个免费开源的安卓漫画阅读器。 该项目的主要功能、关键特性、核心优势包括&#xff1a; 从多种来源在线阅读本地阅读已下载内容可配置的阅读器&#xff0c;具有多个查看器、翻页方向和其他设置支持追…

什么叫高斯分布?

高斯分布&#xff0c;也称为正态分布&#xff0c;是统计学中最常见的概率分布之一。它具有钟形曲线的形态&#xff0c;对称分布在均值周围&#xff0c;且由均值和标准差两个参数完全描述。 高斯分布的概率密度函数&#xff08;Probability Density Function, PDF&#xff09;可…

[设计模式Java实现附plantuml源码~创建型] 复杂对象的组装与创建——建造者模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

DevOps系列文章之 GitLabCI汇总

GitlabCI环境搭建 前提 先安装 docker Docker容器化安装 docker pull gitlab/gitlab-ee:12.4.0-ee.0 创建挂载目录 mkdir -p /srv/gitlab mkdir -p /srv/gitlab/config # 映射到 Glitlab 容器中的配置目录 mkdir -p /srv/gitlab/logs # 映射到 Glitlab 容器中的日志目录 m…

mac裁剪图片

今天第一次用mac裁剪图片&#xff0c;记录一下过程&#xff0c;差点我还以为我要下载photoshop了&#xff0c; 首先准备好图片 裁剪的目的是把图片的标题给去掉&#xff0c;但是不能降低分辨率&#xff0c;否则直接截图就可以了 解决办法 打开原始图片(不要使用预览&#xf…

Python环境下基于机器学习的NASA涡轮风扇发动机剩余使用寿命RUL预测

本例所用的数据集为C-MAPSS数据集&#xff0c;C-MAPSS数据集是美国NASA发布的涡轮风扇发动机数据集&#xff0c;其中包含不同工作条件和故障模式下涡轮风扇发动机多源性能的退化数据&#xff0c;共有 4 个子数据集&#xff0c;每个子集又可分为训练集、 测试集和RUL标签。其中&…

【开源】基于JAVA语言的二手车交易系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手车档案管理模块2.3 车辆预约管理模块2.4 车辆预定管理模块2.5 车辆留言板管理模块2.6 车辆资讯管理模块 三、系统设计3.1 E-R图设计3.2 可行性分析3.2.1 技术可行性分析3.2.2 操作可行性3.2.3 经济…

Java入门——数据类型、自动类型转换、强制类型转换

目录 数据类型 基本数据类型 自动类型转换 表达式的自动类型转换 强制类型转换 计算机中表示数据的最小单元 计算机中表示数据的最小单元&#xff1a;一个字节&#xff08;byte&#xff0c;简称B&#xff0c;是使用8个二进制位组成的&#xff09;字节中的每个二进制位就称…

Python进阶第一篇(Python的面向对象)

文章目录 一、初识对象1.案例代码2.读出结果 二、类的成员方法三、类和对象四、构造方法六、其他内置方法1.魔术方法案例代码2.读出结果 七、封装1.封装案例代码2.读出结果 八、继承1.复写与调用2.类型注解 九、多态 在这个探索和学习的旅程中&#xff0c;我们将深入理解一些编…

基于DataKit迁移MySQL到openGauss

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

网络防御保护——防火墙子接口配置

一.实验拓扑图 二.实验要求 1.生产区在工作时间内可以访问服务区&#xff0c;仅可以访问http服务器。 2.办公区全天可以访问服务区&#xff0c;其中&#xff0c;10.0.2.20可以访问FTP服务器和HTTP服务器&#xff0c;10.0.2.10仅可以ping通10.0.3.10。 3.办公区在访问服务区时采…

【软件测试】学习笔记-Nginx 在系统架构中的作用

本篇文章你探讨 Nginx 在应用架构中的作用&#xff0c;并从性能测试角度看如何利用 Nginx 数据统计用户访问量。 Nginx 重要的两个概念 代理 首先要来解释一下什么是代理&#xff0c;正向代理和反向代理是什么意思&#xff1f;各自作用是什么&#xff1f;不少同学经常听到这…

C语言——操作符详解2

目录 0.过渡0.1 不创建临时变量&#xff0c;交换两数0.2 求整数转成二进制后1的总数 1.单目表达式2. 逗号表达式3. 下标访问[ ]、函数调用( )3.1 下标访问[ ]3.2 函数调用( ) 4. 结构体成员访问操作符4.1 结构体4.1.1 结构体的申明4.1.2 结构体变量的定义和初始化 4.2 结构体成…

【Web】小白也能做的RWCTF体验赛baby题部分wp

遇到不会的题&#xff0c;怎么办&#xff01;有的师傅告诉你完了&#xff0c;废了&#xff0c;寄了&#xff01;只有Z3告诉你&#xff0c;稳辣&#xff01;稳辣&#xff01;都稳辣&#xff01; 这种CVE复现的题型&#xff0c;不可能要求选手从0到1进行0day挖掘&#xff0c;其实…