chat聊天系统消息消费时遇到的问题及优化思路

news2024/9/24 15:23:34

前言

之前有段工作经历涉及到了chat相关,而消息的发送 -> 存储 -> 消费是由不同的团队负责的,因此消息如何再多个团队之间流通、以及通过什么介质传递都是需要考虑的问题。

之前我负责过一些消息消费的相关工作,消息发送团队将消息推送到kafka之后,由我们去订阅topic并消费对应的分区,拿到消息之后做对应的消息类型解析、消息发送双方可见性分析、接收方未读数、推送等业务处理。本文旨在记录之前工作中遇到的相关问题以及从consumer端如何优化处理。

在这里插入图片描述

可以看到,消息系统中引入了kafka,因此如果kafka出现问题,那整个系统都会出现问题。

顺序问题

1、为什么要保证消息的顺序

我们之所以能够回复对方发过来的消息的依据就是对方消息内容,因此对于chat系统来说,消息的顺序性是必须要求保证的硬核标准,如果消息乱序,那这个chat系统可以说是完全报废。因此对于chat系统来说必须要保证消息的顺序性

2、如何保证消息的顺序性

众所周知,kafka有topic的概念,每个topic可以拥有多个分区(partition),而每个分区的内部都是有序的
在这里插入图片描述

如此一来,如何保证消息的顺序性思路就比较清晰了,完全可以利用partition的特性去做处理,按照一定的规则将消息写到不同的partition中去,然后消费者消费partition中的消息。

思考这样一个问题:写到partition中的消息要按照什么规则去做呢?试想一下,我们要保证消息的顺序性,有序性是在同一会话的前提下,也就是说不同会话之前不需要保证消息的顺序性,因此我们可以把conversationId去做如取余或哈希操作,将同一个partition会话的消息全都放入一个partition中。
在这里插入图片描述

消息积压

上述一期方案上线后在项目初期运行一段时间基本没问题,但随着产品推广用户量激增,上述消费架构就出现了问题:消息接收方受消息不够实时,延迟比较高,这对用户来说十分不友好,本来10秒钟几句话的事,到现在可能延迟有1分钟,这谁能忍得了啊。

虽然可以通过水平扩展增加机器数量来缓解压力,但这不是最优的方案,而且最主要是费钱。

优化思路

1、消息体

思考下kafka消息发送到消息消费共经历了几次IO?

  • 从producer到broker经历一次网络IO
  • broker落盘经历一次磁盘IO
  • consumer从broker取数据时经历一次网络IO
  • broker从磁盘拿数据经历一次磁盘IO

一共经历四次IO,引用一张如图说明
在这里插入图片描述

因此这里有个优化思路就是减少消费者取数据时broker从磁盘取数据时经历的IO耗时,那该如何减少呢?

试想一下,假设消费者每次取500条数据,如果每条消息的消息体过大,那取500条数据经历IO耗时势必会增加,进而影响生产和消费速度。而且当消息体过大时,还有可能会导致磁盘空间不足的问题。

2、路由规则

排除消息体过大的原因之后,我们需要看下kafka是否存在lag,如果存在lag我们要从消费者端解决问题。

根据监控查看出现lag的具体的分区,如果是同一个topic的特定某几个分区出现lag,那就需要考虑下是不是路由规则不合理的问题。

一个例子就是对于点餐系统,如果路由规则是根据商家ID来做的,而某些商家订单量一直很大,恰巧这些商家的相关消息都路由到了同一个partition,就导致只有这个partition出现了lag,进而消息处理较慢。

针对这种路由不合理的问题,解决方案就是选择合理的路由规则或key,如上述点餐系统,可以考虑路由规则根据订单号来做,因为所有订单号都是基于同一套方案生成的,所以基本不会出现个别partition lag太高的情况。

而chat系统之前也说过路由规则是基于conversationId去做的,而conversationId也是基于相同的方案生成的,所以如果出现lag发生,那理论上会涉及到大多数partition都出现lag。

3、表过大

假设现在有1亿conversation存于一张表中,即使有索引,根据conversationId去查询对应会话信息的时候耗时也会很高,一条消息的消费原来可能只有500ms,但是现在可能需要5s甚至更久,因此,当数据量比较大时就要考虑分表了。

这里提供一种分表思路,基于conversatioId%100去做,或者是对1000取余。

4、数据库主从延迟

如果在生产环境数据库采用主从架构,主节点负责写,从节点负责读,在从broker拿到消息并完成解析拿到conversationId,这时候去会话团队拿数据,发现数据返回空,对应我们这边后续消费逻辑直接报错而返回,而会话团队根据conversationId去查是有这个会话的,这种情况第一次遇到时就显得很诡异。

后来进过分析发现,我们这边调接口时走的是会话团队数据库的从库,而主从同步还没将最新数据写到从库中。

发现问题后有两个解决方案:

  • 直接读master节点,这种方案不太可取,这样slave节点只作为备份?而且master节点压力会变大,甚至垮掉,也就失去了主从架构原有的作用。
  • 加入重试机制,读取到conversation为空时,将此消息加入到重试表,在做后续处理。
5、并发消费

上述消费架构是一个分区有一个消费者,既然一个消费者消费速度太慢,那何不增加消费者的数量呢?因此优化思路就有了:
在这里插入图片描述

可以把每个partition中的消息按照conversationId%5然后放入到channel中,然后每个channel在配备一个goroutine去消费,这样既能保证同一会话消息的顺序性,又能提升消费速度尽量避免lag。

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

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

相关文章

【Linux】简介磁盘|inode|动静态库

目录一.简介磁盘1.磁盘的物理结构:2.磁盘存储方式:3.磁盘的逻辑抽象:二.inode&&文件系统1.inode文件属性(inode)内容(data block)为什么删除一个文件相比于写一个文件要快得多&#xff…

若依配置教程(二)集成积木报表JimuReport

积木报表配置官网 在搭建好若依环境成功运行以后,我们先在这个系统中加一个小功能:JimuReport积木报表,以下步骤,我们按照官网教程,详细配置一下: 1.在ruoyi-admin文件夹下的pom.xml加入jar包依赖&#x…

MLP多层感知机理解

目录 .1简介 .2例子 2.1模型 2.2 实例 2.2.1 问题描述 2.2.2 数学过程 .3 代码 3.1 问题描述 3.2 代码 references: .1简介 多层感知机是全连接的 可以把低维的向量映射到高维度 MLP整个模型就是这样子的,上面说的这个三层的MLP用公式总结起来…

C 语言零基础入门教程(二十)

C 预处理器 C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器(C Preprocessor&#x…

练手好福利!20个Python实战项目含源代码【2023最新】

高效学习源代码的步骤:1.运行程序,观察表现2.运行源码,断点调试,从头跟一边源码的执行流程,注意函数堆栈3.画类图、流程图,先把遇到的重要类记录下来,表明各个类的关系4.记录问题,把…

Unity XR

一、几个Unity XR Interaction Toolkit学习地址 1.B站视频 https://www.bilibili.com/video/BV11q4y1b74z/?spm_id_from333.999.0.0&vd_source8125d294022d2e63a58dfd228a7fcf63 https://www.bilibili.com/video/BV13b4y177J4/?spm_id_from333.999.0.0&vd_source8…

【对象的比较】java代码实现,详解对象的比较,Comparable接口和Comparator比较器

前言: 大家好,我是良辰丫,💞💞💞今天的我们要学习的知识点是java对象的比较,不是大家现实生活中对象的比较,是java中new一个对象的那个对象,对象的比较到底是什么意思呢&…

24.网络编程(二)

目录 三.TCP通信 3.1 TCP协议特点 3.2 TCP协议通信场景 3.3 TCP通信模型演示 3.4 Socket 3.5 ServerSocket 3.6 注意事项 3.7 案例 3.7.1 TCP通信—单发单收 3.7.2 TCP通信—多发多收 3.7.3 TCP通信—同时接收多个客户端的消息。 3.7.4 TCP通信—使用线程池优化&am…

工业相机和镜头

工业相机和镜头镜头型号数据电源接口定焦镜头的调焦景深景深大小光圈相机、镜头选取参考镜头型号、数据电源接口、定焦镜头的调焦、景深、景深大小、光圈、相机、镜头选取 镜头型号 C,CS系列:相机镜头的C、CS接口非常相似,它们的接口直径、螺…

检索业务:基本数据渲染和排错

采用标签显示商品的数据 <div class"rig_tab"><div th:each"product:${result.getProducts()}"><div class"ico"><i class"iconfont icon-weiguanzhu"></i><a href"/static/search/#">…

5、数据的重构

目录 一、为什么进行数据重构 二、如何进行数据重构 一、为什么进行数据重构 进行数据分析时&#xff0c;有可能会发现数据的结构并不适合直接进行数据分析操作&#xff0c;如下面数据&#xff0c;但通过复制-粘贴-转置等方法操作又太繁琐&#xff0c;数据量小还行&#xff…

C++ 图进阶系列之 kruskal 和 Prim 算法_图向最小生成树的华丽转身

1. 前言 树和图形状相似&#xff0c;也有差异性。树中添加一条或多条边&#xff0c;可成图。图中减小一条或多条边&#xff0c;可成树。形态的变化由数据之间的逻辑关系决定。 图用来描述数据之间多对多关系。树用来描述数据之间一对多关系。 思考如下问题&#xff1f; 如果…

esp32 烧录协议

esp32的rom固化了出场固件。进入烧录模式后&#xff0c;esp32串口输出&#xff1a;给esp32烧录固件的时候&#xff0c;需要和rom的bootloder进行通讯。通讯时&#xff0c;使用 SLIP 数据包帧进行双向数据传输。每个 SLIP 数据包都以 0xC0 开始和结束。 在数据包中&#xff0c;所…

9、Servlet——Request对象

目录 一、get请求和post请求的区别 二、Request对象的应用 1、request主要方法 2、request获取数据 3、设置请求的编码格式 三、解决get请求收参乱码问题 四、解决post请求中文乱码问题 一、get请求和post请求的区别 在Servlet中用来处理客户端请求需要用doGet()方法或…

openGauss数据库源码解析系列文章——备份恢复机制:openGauss全量备份技术

目录 10.1 openGauss全量备份技术 10.1.1 gs_basebackup备份工具 10.1.2 gs_basebackup备份交互流程 本文主要介绍openGauss的备份恢复原理和技术。备份恢复是数据库日常维护的一个例行活动&#xff0c;通过把数据库数据备份到另外一个地方&#xff0c;可以抵御介质类的损…

数据结构与算法-稀疏数组

Java高级系列文章前言 本文章涉及到数据结构与算法的知识&#xff0c;该知识属于Java高级阶段&#xff0c;通常为学习的二阶段&#xff0c;本系列文章涉及到的内容如下&#xff08;橙色框选内容&#xff09;&#xff1a; 本文章核心是教学视频&#xff0c;所以属于个人笔记&a…

深度卷积对抗神经网络 基础 第六部分 缺点和偏见 GANs Disadvantages and Bias

深度卷积对抗神经网络 基础 第六部分 缺点和偏见 GANs Disadvantages and Bias GANs 综合评估 生成对抗网络&#xff08;英语&#xff1a;Generative Adversarial Network&#xff0c;简称GAN&#xff09;是非监督式学习的一种方法&#xff0c;透过两个神经网络相互博弈的方式…

实体对齐(三):RNM

一.摘要 实体对齐旨在将来自不同知识图&#xff08;KG&#xff09;的具有相同含义的实体联系起来&#xff0c;这是知识融合的重要步骤。 现有研究侧重于通过利用知识图谱的结构信息学习实体嵌入来进行实体对齐。这些方法可以聚合来自相邻节点的信息&#xff0c;但也可能带来来…

从软件开发角度看待PCI和PCIe

从软件开发角度看待PCI和PCIe 文章目录从软件开发角度看待PCI和PCIe参考资料&#xff1a;一、 最容易访问的设备是什么二、 地址空间的概念三、 理解PCI和PCIE的关键3.1 地址空间转换3.2 PCI接口速览3.3 PCIe接口速览四、 访问PCI/PCIe设备的流程4.1 PCI/PCIe设备的配置信息4.2…

特斯拉2022全年财报摘要

重点一览一、盈利方面 2022全年营业利润率为16.8%&#xff0c;其中第四季度为16.0% 2022全年GAAP营业利润为137亿美元&#xff0c;其中第四季度为39亿美元 2022全年GAAP净利润为126亿美元&#xff0c;其中第四季度为37亿美元 2022全年非GAAP净利润为141亿美元&#xff0c;其中…