当前位置: 首页 > news >正文

Spring Boot关闭时,如何确保内存里面的mq消息被消费完?

1.背景

之前写一篇文章Spring Boot集成disruptor快速入门demo,有网友留言如下图:

1730887217742

针对网友的留言,那么我们如何解决这个问题呢

  • Spring-Boot应用停机时,如何保证其内存消息都处理完成?

2.解决方法

方法其实挺简单的,disruptor有优雅停机方法,不用我们自己去实现逻辑,只需要调用 disruptor.shutdown() ;就可以实现优雅关闭。

1.禁用kill -9

使用kill -9命令强制终止进程在某些情况下可能会导致数据丢失或资源未正确释放。以下是一些原因和替代方案,帮助你安全地停止应用程序:

为什么避免使用kill -9
  1. 数据丢失kill -9会立即终止进程,不会给应用程序任何机会去保存数据或完成正在进行的操作。

  2. 资源泄漏:进程被强制终止后,可能无法正确释放内存、文件句柄或网络连接等资源。

  3. 不执行清理逻辑:应用程序通常在关闭时执行一些清理逻辑(如关闭数据库连接、写入日志等),kill -9会跳过这些步骤。

2.优雅停机方案

Spring Boot可以引入这个包

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

放开shutdown接口

management:endpoints:web:exposure:include: "*"endpoint:shutdown:enabled: true
server:port: 8088

然后post http://127.0.0.1:8088/actuator/shutdown 实现优雅停机,但是spring boot 2.3以下,停止后不能停止api继续对外。我们可以使用过滤器来禁止api对外提供服务,手动设置HttpServletResponse.SC_SERVICE_UNAVAILABLE

package com.et.disruptor.config;import org.springframework.stereotype.Component;import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;@Component
public class GracefulShutdownFilter implements Filter {private final AtomicBoolean shuttingDown = new AtomicBoolean(false);@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {if (shuttingDown.get()) {((HttpServletResponse) response).setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);return;}chain.doFilter(request, response);}public void startShutdown() {shuttingDown.set(true);}
}

DisposableBean是Spring框架中的一个接口,用于在Spring容器销毁Bean时执行一些自定义的清理逻辑。实现这个接口的Bean会在容器关闭时自动调用其destroy()方法。这对于需要在应用程序关闭时释放资源或执行其他清理操作的Bean非常有用。

package com.et.disruptor.config;import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class GracefulShutdownManager implements DisposableBean {@Autowiredprivate GracefulShutdownFilter shutdownFilter;@AutowiredMqManager mqManager;@Overridepublic void destroy() throws Exception {// reject  new  requestsshutdownFilter.startShutdown();//graceful shutdown DisruptormqManager.shutdownDisruptor(); // wait all events to complete// wait all  your self-definite task finishwaitForTasksToComplete();}private void waitForTasksToComplete() throws InterruptedException {System.out.println("Waiting for tasks to complete...");// use CountDownLatch or other//mock task processThread.sleep(100000);}
}

3.disruptor优雅关闭

如果不想显示的调用shutdown 也可以用注解@PreDestroy

package com.et.disruptor.config;import com.et.disruptor.event.HelloEventFactory;
import com.et.disruptor.event.HelloEventHandler;
import com.et.disruptor.model.MessageModel;
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;@Configuration
public class MqManager {private static Disruptor<MessageModel> disruptor;@Bean("ringBuffer")public RingBuffer<MessageModel> messageModelRingBuffer() {//define the thread pool for consumer message hander, Disruptor touch the consumer event to process by java.util.concurrent.ExecutorSerivceExecutorService executor = Executors.newFixedThreadPool(2);//define Event FactoryHelloEventFactory factory = new HelloEventFactory();//ringbuffer byte sizeint bufferSize = 1024 * 256;disruptor = new Disruptor<>(factory, bufferSize, executor, ProducerType.SINGLE, new BlockingWaitStrategy());//set consumer eventdisruptor.handleEventsWith(new HelloEventHandler());//start disruptor threaddisruptor.start();//gain ringbuffer ring,to product eventRingBuffer<MessageModel> ringBuffer = disruptor.getRingBuffer();return ringBuffer;}//@PreDestroypublic void shutdownDisruptor() {if (disruptor != null) {System.out.println("close Disruptor...");disruptor.shutdown(); //cl0se Disruptor}}
}

shudown方法源码

public void shutdown(long timeout, TimeUnit timeUnit) throws TimeoutException {long timeOutAt = System.currentTimeMillis() + timeUnit.toMillis(timeout);do {if (!this.hasBacklog()) {this.halt();return;}} while(timeout < 0L || System.currentTimeMillis() <= timeOutAt);throw TimeoutException.INSTANCE;
}

这里会等到所有内存消息全部处理完

private boolean hasBacklog() {long cursor = this.ringBuffer.getCursor();Sequence[] var3 = this.consumerRepository.getLastSequenceInChain(false);int var4 = var3.length;for(int var5 = 0; var5 < var4; ++var5) {Sequence consumer = var3[var5];if (cursor > consumer.get()) {return true;}}return false;
}

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

  • GitHub - Harries/springboot-demo: a simple springboot demo with some components for example: redis,solr,rockmq and so on.(Disruptor)

3.测试

  • 启动Spring Boot应用
  • post 请求http://127.0.0.1:8088/actuator/shutdown实现优雅停止
  • 访问http://127.0.0.1:8088/hello,会报503错误
  • 后台会等待Disruptor处理内存消息
  • 后台等待处理其他的异步任务
  • 最后关闭Spring Boot应用

4.引用

  • https://medium.com/@contact.technovisionconsulting/how-to-achieve-a-graceful-shutdown-in-spring-boot-ec93d55916ed
  • Spring Boot关闭时,如何确保内存里面的mq消息被消费完? | Harries Blog™

相关文章:

Spring Boot关闭时,如何确保内存里面的mq消息被消费完?

1.背景 之前写一篇文章Spring Boot集成disruptor快速入门demo&#xff0c;有网友留言如下图&#xff1a; 针对网友的留言&#xff0c;那么我们如何解决这个问题呢 Spring-Boot应用停机时&#xff0c;如何保证其内存消息都处理完成&#xff1f; 2.解决方法 方法其实挺简单的&…...

HTML 基础标签——文本内容标签 <ul>、<ol>、<blockquote> 、<code> 等标签的用法详解

文章目录 1. 标题标签2. 段落标签3. 文本格式化标签4. 列表标签4.1 无序列表 `<ul>`4.2 有序列表 `<ol>`5. 引用标签5.1 块引用 `<blockquote>`5.2 行内引用 `<q>`5.3 作品引用 `<cite>`6. 代码和预格式文本标签6.1 代码标签 `<code>`6.2 …...

高效管理社团:Spring Boot在校园社团信息管理中的应用

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理校园社团信息管理系统的相关信息成为必然。…...

mysql约束和高级sql

约束 MySQL中的约束用于定义表中数据的规则&#xff0c;以确保数据的准确性和可靠性。以下是MySQL中常用的一些约束类型及其概述&#xff1a; PRIMARY KEY&#xff08;主键&#xff09;&#xff1a;唯一标识表中每条记录的字段或字段组合&#xff0c; 一个表中只能有一个主键…...

蓝桥杯真题——三角回文数(C语言)

问题描述 对于正整数 n, 如果存在正整数 k 使得 n123⋯kk(k1)2n123⋯kk(k1)/2​, 则 n 称为三角数。例如, 66066 是一个三角数, 因为 66066123⋯36366066123⋯363 。 如果一个整数从左到右读出所有数位上的数字, 与从右到左读出所有数位 上的数字是一样的, 则称这个数为回文数…...

uni-app 封装图表功能

文章目录 需求分析1. 秋云 uchars2. Echarts 需求 在 uni-app 中使用图表功能&#xff0c;两种推荐的图表工具 分析 在 Dcloud市场 搜索Echarts关键词&#xff0c;会出现几款图表工具&#xff0c;通过大家的下载量&#xff0c;可以看到秋云这个库是比较受欢迎的&#xff0c;其…...

Kubernetes的基本构建块和最小可调度单元pod-0

文章目录 一&#xff0c;什么是pod1.1pod在k8s中使用方法&#xff08;1&#xff09;使用方法一&#xff08;2&#xff09;使用方法二 1.2pod中容器的进程1.3pod的网络隔离管理&#xff08;1&#xff09;pause容器的作用 1.4 Pod分类&#xff1a;&#xff08;1&#xff09;自主式…...

QT创建按钮篇

QT创建按钮篇 1.概述 这篇文章从创建一个按钮对QT开发流程熟悉。 2.代码 #include "mywidget.h" #include <QPushButton>myWidget::myWidget(QWidget *parent): QWidget(parent) { // 第一种创建按钮方式 // QPushButton *btn new QPushButton(); /…...

初级软件测试工程师就别出口喊15K了,连自动化测试都不会,还不如应届生

一. 为什么学软件测试 零基础转行&#xff0c;为什么首选软件测试&#xff1f; 软件测试是软件开发的重要过程之一&#xff0c;是软件质量的保证。国外信息技术领域软件开发人员与测试人员的比例是1:1&#xff0c;而国内目前专业软件测试人员很少&#xff0c;属于紧缺型人才&a…...

Mybatis查询数据库,返回List集合,集合元素也是List。

#有时间需求会要求&#xff1a;查询全校的学生数据&#xff0c;且学生数据按班级划分。那么就需要List<List<user>>类型的数据。 SQL语句 SELECT JSON_ARRAYAGG(JSON_OBJECT(name , name ,BJMC, BJMC ,BJBH,BJBH)) as dev_user FROM dev_user WHERE project_id …...

SQL 视图:概念、应用与最佳实践

SQL 视图&#xff1a;概念、应用与最佳实践 SQL&#xff08;Structured Query Language&#xff09;视图是数据库管理中的一个重要概念&#xff0c;它允许用户以虚拟表的形式查看数据。视图在数据库中并不实际存储数据&#xff0c;而是提供了一个查询结果的快照&#xff0c;这…...

ubuntu交叉编译expat库给arm平台使用

1.下载expat库源码: https://github.com/libexpat/libexpat/release?page=2 wget https://github.com/libexpat/libexpat/release/download/R_2_3_0/expat-2.3.0.tar.bz2 下载成功: 2.解压expat库,并进入解压后的目录: tar xjf expat-2.3.0.tar.bz2 cd expat-2.3.0 <…...

成都郝蓉宜恺文化传媒有限公司以诚信经营赢得客户长期信赖

成都郝蓉宜恺文化传媒有限公司秉承深厚的企业文化和价值观&#xff0c;其中“以诚信经营为本”是其核心理念之一。以下是对该公司如何以诚信经营为基础&#xff0c;赢得客户长期信赖的几点客观分析&#xff1a; 1.建立信任基石&#xff1a;在商业领域&#xff0c;信任是客户与企…...

LabVIEW for Linux 介绍

LabVIEW for Linux 介绍 1. 兼容性 LabVIEW for Linux 设计用于多种 Linux 发行版&#xff0c;包括 CentOS、Ubuntu 等。在安装之前&#xff0c;务必检查与您特定发行版版本的兼容性。 2. 程序移植 可移植性&#xff1a;在许多情况下&#xff0c;LabVIEW 程序&#xff08;VI…...

一次32bit有符号数据类型转换为64bit无符号数据类型引发的溢出错误

现象&#xff1a; 在调试一款sensor&#xff0c;通过10帧->8帧->6帧,这样不断的降低帧率调试低照度下的图像效果。ISP配置文件上设置的最大曝光曝光参数为&#xff1a; EXP&#xff1a;15266 Again:15494 Dgain:714 ISPDGain:1360。 当达到最低帧率最低亮度时&#x…...

aosp安卓15新特性dump的wms窗口层级树优化的更加美观

背景&#xff1a; 近来在体验调试aosp15时候&#xff0c;使用了dumpsys activity containers时候&#xff0c;发现wms层级结构树有一个巨大的变化。 很多学员朋友对这个优化改进都给出巨大的点赞&#xff0c;有的学员朋友还想老版本自己实现一下这种树绘制&#xff1a; 对比…...

git的使用、router和route的区别以及v-show和v-if的差别

这里写目录标题 多人协作使用git的步骤&#xff08;使用gitub&#xff09;建立自己的空仓库连接远程仓库使伙伴可以使用仓库将代码拉入空仓库进行git指令的学习 router和route的区别router定义&#xff1a;用途&#xff1a; route定义&#xff1a;用途&#xff1a; v-show和v-i…...

Win系统通过命令行查看笔记本电池损耗/寿命/健康

在 Windows 10/11 系统中&#xff0c;可以通过指令查看笔记本电池的寿命情况&#xff0c;方法如下&#xff1a; 0&#xff0c;打开cmd/终端 键盘快捷键&#xff1a;Win R&#xff0c;然后输入cmd&#xff0c;点击【确定】 1&#xff0c;执行命令 在命令行中输入下面指令并按…...

【安当产品应用案例100集】029-使用安全芯片保护设备核心业务逻辑

我国工业企业普遍缺乏数据安全意识&#xff0c;对数据安全保护缺乏基本认识。这导致企业在数据安全方面的投入不足&#xff0c;保护能力基本不具备&#xff0c;难以有效应对数据安全风险。不过随着安全事件越来越多&#xff0c;很多工业企业的安全意识也越来越高&#xff0c;在…...

Redis高级篇之缓存一致性详细教程

文章目录 0 前言1.缓存双写一致性的理解1.1 缓存按照操作来分 2. 数据库和缓存一致性的几种更新策略2.1 可以停机的情况2.2 我们讨论4种更新策略2.3 解决方案 总结 0 前言 缓存一致性问题在工作中绝对没办法回避的问题&#xff0c;比如&#xff1a;在实际开发过程中&#xff0c…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent

安全大模型训练计划&#xff1a;基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标&#xff1a;为安全大模型创建高质量、去偏、符合伦理的训练数据集&#xff0c;涵盖安全相关任务&#xff08;如有害内容检测、隐私保护、道德推理等&#xff09;。 1.1 数据收集 描…...

恶补电源:1.电桥

一、元器件的选择 搜索并选择电桥&#xff0c;再multisim中选择FWB&#xff0c;就有各种型号的电桥: 电桥是用来干嘛的呢&#xff1f; 它是一个由四个二极管搭成的“桥梁”形状的电路&#xff0c;用来把交流电&#xff08;AC&#xff09;变成直流电&#xff08;DC&#xff09;。…...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践

前言&#xff1a;本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中&#xff0c;跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南&#xff0c;你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案&#xff0c;并结合内网…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例

目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码&#xff1a;冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...

在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7

在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤&#xff1a; 第一步&#xff1a; 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为&#xff1a; // 改为 v…...