20240711每日消息队列-------------MQ消息的积压的折磨

news2024/9/22 23:26:20

目标

解决MQ消息的积压

背景

菜馆系统-----------
系统读取消息,处理业务逻辑,持久化订单和菜品数据,然后将其显示在菜品管理客户端上。
在这里插入图片描述
最初我们的用户基数很小,上线后的一段时间内,MQ消息通信还算顺利。
随着用户规模的扩大,每个商家每天都会产生大量的订单数据,每个订单都包含多个菜品。这导致我们的菜肴管理系统的数据量显着增加。
某一天,商家投诉,称用户下单后平板上的菜品列表出现延迟。
几分钟后厨房才看到菜品。

这能行?

很明显出现这样的菜品展示延迟肯定和Kafka有关,所以我们先从排查Kafka开始。
正如预期的那样,有一个 message backlog 。
通常,消息积压的原因有:

  • MQ 使用者已关闭。
  • MQ 生产者生成消息的速率超过 MQ 消费者消费消息的速率。

我们检查了监控系统,发现我们的MQ消费服务运行正常,没有任何异常。
剩下的原因可能是MQ消费者的消息处理速度变慢了。
接下来我查看了菜品管理表,只有几十万条记录。

首先定位处理MQ日志比较慢的地方:
在代码中添加了一些日志来打印出MQ消费者中各个关键点所花费的时间。
确实有两个地方延迟有点高:
1、有一段代码在for循环中,一条一条的查询数据库。
2、有一段代码执行多条件数据查询。

解决循环查询

对于在for循环中一一查询数据库的代码,我使用参数集合将其更改为 batch query 。
原代码如下:

public List<User> queryUser(List<User> searchList) {
    if (CollectionUtils.isEmpty(searchList)) {
        return Collections.emptyList();
    }List<User> result = Lists.newArrayList();
    searchList.forEach(user -> result.add(userMapper.getUserById(user.getId())));
    return result;
}

改进一下:

public List<User> queryUser(List<User> searchList) {
    if (CollectionUtils.isEmpty(searchList)) {
        return Collections.emptyList();
    }
    List<Long> ids = searchList.stream().map(User::getId).collect(Collectors.toList());
    return userMapper.getUserByIds(ids);
}

很简单的调整,搞一个ids集合,轻松解决挤压问题。

第二次遇到消息积压

这一次,它是零星的,只是偶尔发生,而不是大多数时候发生。
查了一下菜品管理表,现在已经有几百万条记录了
通过监控和DBA每天的慢查询邮件,我注意到了一些异常情况。

我发现有些SQL语句的WHERE条件完全相同,只是参数值不同,导致使用的索引不同。
例如, order_id=123 使用索引 a,而 order_id=124 使用索引 b。
该表查询场景众多,为了满足不同的业务需求,增加了多个复合索引。

MySQL 根据几个因素选择索引:
1、通过数据采样估计要扫描的行数。更多行可能会导致更高的 I/O 操作和更高的 CPU 使用率。
2、是否使用临时表,也会影响查询速度。
3、是否需要排序,因为它会影响查询速度。

考虑到这些因素和其他因素,MySQL 优化器会选择它认为最合适的索引。

MySQL优化器通过采样来估计要扫描的行数,这涉及到选择一些数据页进行统计估计,从而引入一些误差。

由于MVCC设计,存在多个版本的数据页。例如,删除的数据可能在其他事务中仍然可见,因此索引并未真正删除。这可能会导致统计数据不准确并影响优化器的决策。
这些因素都会导致MySQL在执行SQL语句时出现 错误索引
为了解决MySQL选择错误索引的问题,我们使用 FORCE INDEX 关键字强制SQL查询使用索引a。

FORCE INDEX

force index() 方法强制使用这个索引

第三次遇到消息积压

半年后的某一天,检查监控系统,发现Kafka消息再次积压。
检查了MySQL索引,发现使用了正确的索引,但数据查询仍然很慢。
检查菜品管理表,短短六个月内就增长到了 3000 万条记录。

通常,当单个表包含太多数据时,查询和写入性能都会下降。
这次查询缓慢的原因是数据量太大。

大数据表,解决这个问题,我们需要:
1、实施数据库和表分区
2、备份历史数据

但是我们的体量和预算不支持分库分表

因此,我们决定备份历史数据。
经过与产品经理和DBA讨论,我们决定菜品管理表只保留最近30天的数据,而早于该时间的数据将移至 historical table 。
经过这样的优化,菜品管理表在30天内只积累了几百万条记录,对性能的影响很小。

第四次遇到消息积压

又又又,没错,来了
年后的一个下午,当我查看公司邮件时,发现大量关于Kafka消息积压的监控警报邮件。
下午,这个时间点很奇怪。。。

经过上面的排查都没问题。
我询问订单团队当天下午是否发布了新版本或执行了任何特定功能。因为我们的菜品管理系统是他们的下游系统,跟他们的运营有直接关系。有同事提到,半个小时前,他们做了一个作业,批量更新了几万个订单的状态。更改订单状态会自动发送 MQ 消息。
这导致他们的程序在很短的时间内生成了大量的MQ消息。
我们的 MQ 使用者无法足够快地处理这些消息,导致消息积压。
我们检查了Kafka消息积压情况,发现有几十万条消息在排队。

查看Kafka消息积压情况

https://www.cnblogs.com/lanbojini/p/17314699.html

快速提高MQ消费者的处理速度

我们考虑了两种解决方案:
1、增加分区数量。
2、使用线程池来处理消息。

然而,由于消息已经积压在现有分区中,因此添加新分区并没有多大帮助。
因此,我们决定重构代码以使用 thread pool 来处理消息。
为了开始消耗积压的消息,我们将线程池的核心线程数和最大线程数增加到 50。
此次调整后,积压的数十万条消息在20分钟左右就得到了处理。
解决这个问题后,我们保留了消息消费的线程池逻辑,将核心线程数设置为 8 ,最大线程数设置为 10 。
这使我们能够临时调整线程计数,以快速解决未来的任何消息积压问题,而不会显着影响用户。

注意:使用线程池消费MQ消息并不是通用的解决方案。它有一些缺点,例如潜在的消息排序问题以及导致服务器 CPU 使用率飙升的风险。另外,如果在多线程环境下调用第三方接口,可能会导致第三方服务过载而崩溃。

结语

MQ积压,没有完美的解决方案,只有最适合当前业务场景的解决方案。fuck everythimg

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

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

相关文章

在Mac上一键安装Mysql(解决所有安装问题)

重点强调安装mysql成功的关键在于安装的版本不能是最新&#xff01;&#xff01; 目录 一&#xff1a;下载mysql数据库安装部分到此结束 二&#xff1a;配置mysql数据库三&#xff1a;启动mysql数据库四&#xff1a;各类奇葩问题总结 一&#xff1a;下载mysql数据库 1.进入MyS…

触摸屏虚拟键盘组件 jQuery Virtual Keyboard使用 自定义键盘

如何在触摸设备上为输入域添加虚拟键盘&#xff1f; 一个插件可以解决这个问题&#xff0c;关键还支持高度自定义&#xff08;git地址&#xff09;&#xff1a; GitHub - Mottie/Keyboard: Virtual Keyboard using jQuery ~ 官网地址&#xff1a;Virtual Keyboard 使用步骤&…

百日筑基第十八天-一头扎进消息队列1

百日筑基第十八天-一头扎进消息队列1 先对业界消息队列有个宏观的认识 消息队列的现状 当前开源社区用的较多的消息队列主要有 RabbitMQ、RocketMQ、Kafka 和Pulsar 四款。 国内大厂也一直在自研消息队列&#xff0c;比如阿里的 RocketMQ、腾讯的 CMQ 和 TubeMQ、京东的 JM…

无头双向非循环链表实现

无头双向非循环链表实现 Ilist.java接口&#xff1a;MyLinkedList.java&#xff1a; 无头双向非循环链表大致与无头单向非循环差不多&#xff0c;只不过每个节点多了个prev引用&#xff0c;可以从后一个节点找到前一个节点。并且除了头节点head&#xff0c;双链表还多了个尾节点…

自定义多选组件

一.业务场景 选择用印公司时&#xff0c;需要选择多个公司&#xff0c;一个公司对应一个实际使用人 点击用印单位&#xff0c;弹出选择公司窗口&#xff0c;选择使用人&#xff0c;同时带上公司ID,点击确定按钮&#xff0c;将公司和使用人回显在用印单位上 二.上代码 wxml代码…

快递查询|阿里云实现调用API接口

整体请求流程 介绍&#xff1a; 本次解析通过阿里云云市场的云服务来实现程序中对快递包裹实时监控&#xff0c;首先需要准备选择一家可以提供快递查询的商品。 https://market.aliyun.com/apimarket/detail/cmapi00065859#skuyuncode5985900001 步骤1: 选择商品 如图点击…

复杂表单一键填充,让信息输入更轻松

随着网络购物成为日常生活的一部分&#xff0c;用户在多个购物应用中重复输入地址信息带来的效率问题日益凸显。同样&#xff0c;在为家人预订车票或机票时&#xff0c;添加新的购票人信息也因难以记忆家人详细信息而变得繁琐。 为了解决这些用户痛点&#xff0c;HarmonyOS SD…

企业响应式网站建站模版源码系统 海量模版随心选择 带完整的安装代码包以及搭建部署教程

系统概述 企业响应式网站建站模版源码系统”是一套完整、高效的网站建设解决方案。它旨在为企业提供一站式的网站建设服务&#xff0c;无需专业的编程知识&#xff0c;即可通过简单的操作&#xff0c;快速搭建出美观、专业的企业网站。该系统不仅包含了丰富的网站模版&#xf…

【qt】客户端连接到服务器

获取到IP地址和端口号. 通过connectToHost() 来进行连接. 对于客户端来讲,只需要socket即可. 客户端连接服务端只需要使用套接字(Socket)来进行通信。客户端通过创建一个套接字来连接服务端&#xff0c;然后可以通过套接字发送和接收数据。套接字提供了一种简单而灵活的方式来…

勘测院如何实现可控便捷的图纸安全外发?

勘测院&#xff0c;也称为勘测设计研究院或勘测设计院&#xff0c;是进行与地质、地形和地貌有关的勘察测量的单位&#xff0c;为各类工程项目提供准确的地质数据和设计依据。 勘测院会产生各类包括图纸在内的文件&#xff0c;如&#xff1a; 1、项目相关文件&#xff1a;项目…

不同的企业如何量身制定数据治理体系

在当今数据驱动的商业环境中&#xff0c;数据治理已成为企业不可或缺的一部分。然而&#xff0c;由于行业、规模、业务模式的差异&#xff0c;不同企业在制定数据治理体系时面临着各自独特的挑战和机遇。本文将探讨不同企业如何根据自身特点量身制定数据治理体系。 明确企业数据…

基于Rspack实现大仓应用构建提效实践|得物技术

一、实践背景 随着项目的逐步迭代&#xff0c;代码量和依赖的逐渐增长&#xff0c;应用的构建速度逐步进入缓慢期。以目前所在团队的业务应用来看&#xff08;使用webpack构建&#xff09;&#xff0c;应用整体构建耗时已经普遍偏高&#xff0c;影响日常开发测试的使用效率&am…

浅谈后置处理器之JSON提取器

浅谈后置处理器之JSON提取器 JMeter 的 JSON 提取器&#xff08;JSON Extractor&#xff09;是一个强大的后置处理器&#xff0c;它允许用户从HTTP响应、数据库查询或其他类型的响应中提取JSON数据&#xff0c;并将这些数据存储为变量&#xff0c;以便在后续的请求中重用。这对…

人工智能行业应用-垃圾识别一

垃圾识别应用主要体现在AI图像垃圾识别技术上&#xff0c;这是一种基于人工智能和计算机视觉技术的图像处理技术&#xff0c;广泛应用于各个领域以提高垃圾处理的效率和准确性。 1、垃圾识别效果图 2 垃圾识别任务分析 综合利用Python语言、Qt开发模块&#xff0c;OpenCV开发模…

python使用tkinter加载rtsp视频流

简介 最近有个需求&#xff0c;需要开发个桌面应用工具&#xff0c;可是实时显示rstp视频&#xff0c;于是想到了用python自带的tkinter 来开发&#xff0c;最后打包成exe应用。 import cv2 import random import threading from tkinter import * from PIL import Image, Ima…

group 与查询字段

需求 每周周一&#xff0c;统计菜单在过去一周&#xff0c;点击次数&#xff0c;和点击人数&#xff08;同一个人访问多次按一次计算&#xff09; 表及数据 日志表 CREATE TABLE t_data_log ( id varchar(50) NOT NULL COMMENT 主键id, operation_object varchar(500) DE…

麦克风领夹式的哪个牌子最好,一文告诉你无线领夹麦克风哪款好

​在选择无线麦克风时&#xff0c;多样化的市场需求和不断进步的技术&#xff0c;使得从专业级到入门级的各类产品应运而生&#xff0c;满足不同场景和预算的需求。为了让消费者在众多选择中找到适合自己的无线麦克风&#xff0c;我们基于市场销量和用户口碑&#xff0c;整理出…

Java中的Set系列集合超详解

Set List是有序集合的根接口&#xff0c;Set是无序集合的根接口&#xff0c;无序也就意味着元素不重复。更严格地说&#xff0c;Set集合不包含一对元素e1和e2 &#xff0c;使得e1.equals(e2) &#xff0c;并且最多一个空元素。   使用Set存储的特点与List相反&#xff1a;元素…

界面组件Kendo UI for React 2024 Q2亮点 - 生成式AI集成、设计系统增强

随着最新的2024年第二季度发布&#xff0c;Kendo UI for React为应用程序开发设定了标准&#xff0c;包括生成式AI集成、增强的设计系统功能和可访问的数据可视化。新的2024年第二季度版本为应用程序界面提供了人工智能(AI)提示&#xff0c;从设计到代码的生产力增强、可访问性…

219.贪心算法:柠檬水找零(力扣)

代码解决 class Solution { public:bool lemonadeChange(vector<int>& bills) {int num50, num100; // 初始化5美元和10美元的计数器for(int i0; i < bills.size(); i) // 遍历所有账单{if(bills[i]5) // 如果账单是5美元{num5; // 增加5美元的计数continue; // …