抽丝剥茧,Redis使用事件总线EventBus或AOP优化健康检测
目录
前言
Lettuce
什么是事件总线EventBus?
Connected
Connection activated
Disconnected
Connection deactivated
Reconnect failed
使用
一种另类方法—AOP
具体实现
前言
在上一篇深入浅出,SpringBoot整合Quartz实现定时任务与Redis健康检测(二)_往事如烟隔多年的博客-CSDN博客
文章中,通过在SpringBoot中使用Quartz实现了Redis健康状态的检测,虽然一定程度上解决了Redis的连接问题,但仍存在一些问题,比如当Redis在定时检测的间隔时间内断开连接时,此时有用户请求进入时仍然会出现服务不可用的状态,那么有办法能够在Redis断开时通知到SpringBoot程序,进而实现Redis到MySQL的切换呢?本文将在之前的基础上使用Redis的事件总线机制来解决该问题。
Lettuce
在SpringBoot 2.x版本中默认使用的Redis客户端为Lettuce,与早期的Jedis不同,Lettuce底层由Netty构建,异步IO驱动提升效率,支持高并发,且线程安全。由下图可以看出项目中引入了Redis依赖后使用的客户端为Lettuce。
什么是事件总线EventBus?
虽然引入了Lettuce,但是面临的问题应该如何作以解决呢?这里就得讲一下Redis的EventBus了,可以通过Lettuce官方文档了解相关信息,
Connection Events · lettuce-io/lettuce-core Wiki · GitHub
由于客户端使用了lettuce6.1.10,因此我们关注内容如下Connection Events · lettuce-io/lettuce-core Wiki · GitHub
不难看出自lettuce提供了一个用于使用连接事件的实例代码,通过订阅事件总线可以监听到当前Redis的连接事件状态,连接事件状态分为如下五种:
Connected
传输协议连接建立,即TCP三次握手完成,Socket通信建立,事件类型ConnectedEvent。
Connection activated
逻辑连接建立,当前处于活动状态并且可以开始分发Redis命令,此时ping命令已经发送并收到回应,可以正常使用Redis命令。事件类型ConnectionActivatedEvent。
Disconnected
连接关闭,传输协议关闭或重置。该事件发生在定期关闭和连接中断时,事件类型Disconnected。
Connection deactivated
连接停用,逻辑连接停用,内部的处理状态被重置,并且isOpen()标志被设置为false,该事件发生在定期关闭和连接中断时,事件类型Connection deactivated。
Reconnect failed
重连失败(自5.3版起),尝试重连失败。包含重连失败和重连计数器。事件类型RecconectFailedEvent。
如上五种类型中需要重点关注的是Connection activated,当该连接事件发生时,将Redis连接标识置为true即可。
使用
根据前文提到的官方文档给出的代码,使用后会发现并未监听到Redis的连接状态。
RedisClient client = RedisClient.create()
EventBus eventBus = client.getresources().eventBus();eventBus.get().subscribe(e -> System.out.println(event));...
client.shutdown();
此时进入create()方法内部查看情况,可以看到默认无参的构造函数创建了一个RedisClient对象,其中第一个参数为clientResources对象,第二个参数为一个字符串,即空的URI,想必在这里已经猜到为什么无法监听连接了。
由于并没有传入对应的Redis资源或URI路径,导致无法进行正常的事件监听。
在源码中不难发现有其它同名含参的构造方法, 此处使用第三个含有ClientResource对象的方法,因为可以通过Spring注入该对象,从而省去手工构造的繁琐步骤。
具体代码如下
通过创建事件总线对象,进而订阅Redis的连接事件,当Reids处于非连接状态时会实时修改RedisCheckConfig的连接状态标识。即使在Redis定时检测任务的间隔中也能保证服务的正常运行。
@Component
@Slf4j
public class RedisStatusListener {@Autowiredprivate ClientResources clientResources;public RedisClient redisClient() {RedisClient client = RedisClient.create(clientResources);EventBus eventBus = client.getResources().eventBus();eventBus.get().subscribe(e -> {RedisCheckConfig.redisConnected = e instanceof ConnectionActivatedEvent ? true : false;log.info("EventBus获取Redis是否连接 "+RedisCheckConfig.redisConnected);});return client;}
}
一种另类方法——AOP
如果并不想使用事件总线的方式来解决,这里再提供一种其它的思路。可以通过AOP的方式来完成判断。
通过对Redis操作类中的所有操作指令进行检测,即当Redis操作命令执行超过1s(可调节)时则认为此时Redis出现了连接异常。
这里由于需要统计执行时间需要用到线程池,通过AOP的环绕通知来实现业务逻辑拦截,即当Redis命令操作超过指定时间则返回数据为其对应存储数据的默认类型。
具体实现
@Component
@Aspect
@Slf4j
public class RedisOperationAspect {@Around("execution(* com.o2o.shop.util.RedisOperator.*(..))")public Object monitorRedisCommandExecution(ProceedingJoinPoint joinPoint) throws Throwable {// 获取方法信息MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();Method method = methodSignature.getMethod();String methodName = method.getName();// 执行超时时间,单位mslong timeout = 1000;ExecutorService executor = new ThreadPoolExecutor(1, 1,1000, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(1));// 创建Future对象Future<Object> future = executor.submit(() -> {try {return joinPoint.proceed();} catch (Throwable throwable) {log.error("Redis AOP 执行 "+joinPoint+"异常");throw new RuntimeException(throwable);}});// 执行方法并等待结果,设置超时时间try {return future.get(timeout, TimeUnit.MILLISECONDS);} catch (TimeoutException e) {// 超时处理log.warn("Redis command execution timed out");// 中断方法执行future.cancel(true);// 返回特定结果Class<?> returnType = method.getReturnType();if (returnType.isPrimitive()) {if (returnType == boolean.class) {return false;} else if (returnType == char.class) {return '\0';} else if (returnType == byte.class || returnType == short.class ||returnType == int.class || returnType == long.class) {return 0;} else if (returnType == float.class || returnType == double.class) {return 0.0f;}}return null;} finally {// 关闭线程池executor.shutdown();}}}
相关文章:

抽丝剥茧,Redis使用事件总线EventBus或AOP优化健康检测
目录 前言 Lettuce 什么是事件总线EventBus? Connected Connection activated Disconnected Connection deactivated Reconnect failed 使用 一种另类方法—AOP 具体实现 前言 在上一篇深入浅出,SpringBoot整合Quartz实现定时任务与Redis健康…...

【Tailwind CSS】当页面内容过少,怎样让footer保持在屏幕底部?
footer通常写版权信息等,显示在页面底部。如果页面内容过少,则footer会出现在屏幕中间位置,很尴尬。在 Tailwind 中,你可以使用flex来实现footer保持在屏幕或页面底部。 代码: <div class"flex flex-col min…...

Docker基础管理
这里写目录标题 Docker基础管理一.Docker 概述1.Docker介绍2.Docker与虚拟机的区别3.容器在内核中支持2种重要技术4.Docker核心概念 二.安装Docker1.安装依赖包2.配置文件及相关 三.Docker操作1.镜像操作2.容器操作 Docker基础管理 一.Docker 概述 1.Docker介绍 Docker是一个…...

基于YOLOv8模型的烟雾目标检测系统(PyTorch+Pyside6+YOLOv8模型)
摘要:基于YOLOv8模型的烟雾目标检测系统可用于日常生活中检测与定位烟雾目标,利用深度学习算法可实现图片、视频、摄像头等方式的目标检测,另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算法训练数据集…...

【代码随想录01】数组总结
抄去吧,保存去吧!...

(SpringBoot)第二章:Spring创建和使用
文章目录 一:Sring创建(1)创建一个Maven项目(2)添加Spring框架支持(3)添加启动类二:存储Bean(1)创建Bean(2)将Bean注册到Spring中三:获取并使用Bean(1)创建Spring上下文(2)获取指定Bean(3)使用Bean注意:在Java中对象也叫做Bean,所以后续文章中用Bean代替对…...

力扣刷题 day56:10-26
1.解码异或后的数组 未知 整数数组 arr 由 n 个非负整数组成。 经编码后变为长度为 n - 1 的另一个整数数组 encoded ,其中 encoded[i] arr[i] XOR arr[i 1] 。例如,arr [1,0,2,1] 经编码后得到 encoded [1,2,3] 。 给你编码后的数组 encoded 和原…...

『第四章』一见倾心:初识小雨燕(上)
在本篇博文中,您将学到如下内容: 1. 基本数据类型2. 基本操作符3. 枚举和结构4. 类和 Actor5. 属性、方法与访问控制6. 聚集总结夜月一帘幽梦,春风十里柔情。 无声交谈情意深,一见心曲绕梁成。 1. 基本数据类型 无论是 macOS 还是 iOS 上的开发,Swift 基础类型和功能都内置于…...

elasticsearch-7.9.3 单节点启动配置
一、elasticsearch-7.9.3 单节点启动配置 node.name: node-1 network.host: 192.168.227.128 http.port: 9200 discovery.seed_hosts: ["192.168.227.128"] node.max_local_storage_nodes: 1 discovery.type: single-node二、kibana-7.9.3-linux-x86_64 单节点启动配…...

【2024秋招】2023-10-9 同花顺后端笔试题
1 Hashmap mp new hashmap(50)的大小扩充了几次 初时应该就给了这么多空间,在不考虑添加元素,所以扩容为0次 2 算数表达式的中缀为ab*c-d/e,后缀为abc*de/-,前缀是? 3 50M电信带宽ÿ…...

完美的错误处理:Go 语言最佳实践分享
Go 语言是一门非常流行的编程语言,由于其高效的并发编程和出色的网络编程能力,越来越受到广大开发者的青睐。在任何编程语言中,错误处理都是非常重要的一环,它关系到程序的健壮性和可靠性。Go 语言作为一门现代化的编程语言&#…...

vue首页多模块布局(标题布局)
<template><div class"box"><div class"content"><div class"box1" style"background-color: rgb(245,23,156)">第一个</div><div class"box2" style"background-color: rgb(12,233,…...

嵌入式系统>嵌入式硬件知识
AI芯片的特点包括 :新型计算范式AI芯片的关键特征: 1、新型的计算范式 AI 计算既不脱离传统计算,也具有新的计算特质,如处理的内容往往是非结构化数据(视频、图片等)。处理的过程通常需要很大的计算量&am…...

LeetCode 1402. 做菜顺序【排序,动态规划;贪心,前缀和,递推】1679
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...

【多线程】探索Java中的多线程编程
标题:探索Java中的多线程编程 摘要: Java是一种广泛使用的编程语言,具有强大的多线程编程能力。本文将深入探讨Java中的多线程编程,包括线程的创建、同步与互斥、线程池的使用以及常见的多线程编程模式。通过示例代码和详细解释&…...

【算法题】翻转对
题目: 给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。 你需要返回给定数组中的重要翻转对的数量。 示例 1: 输入: [1,3,2,3,1] 输出: 2 示例 2: 输入: [2,4,3,5,1] 输出: 3 注意: 给定数组的长…...

适用于 Mac 或 Windows 的 4 种最佳 JPEG/PNG图片 恢复软件
您的计算机或外部存储驱动器上很可能有大量 JPEG /PNG图片照片,但不知何故,您意识到一些重要的 JPEG /PNG图片文件丢失或被删除,它们对您来说意义重大,您想要找回它们. 4 种最佳 JPEG/PNG图片 恢复软件 要成功执行 JPEG /PNG图片…...

位置信息API
位置信息API 一、获取当前位置:wx.getLocation(object)二、选择位置:wx.chooseLocation(object)三、打开位置:wx.openLocation(object)四、监听位置事件五、地图组件控制API六、收货地址API:wx.chooseAddress(object) 一、获取当前…...

MySQL——九、SQL编程
MySQL 一、触发器1、触发器简介2、创建触发器3、一些常见示例 二、存储过程1、什么是存储过程或者函数2、优点3、存储过程创建与调用 三、存储函数1、存储函数创建和调用2、修改存储函数3、删除存储函数 四、游标1、声明游标2、打开游标3、使用游标4、关闭游标游标案例 一、触发…...

threejs(4)-纹理材质高级操作
一、纹理重复_缩放_旋转_位移操作 // 导入threejs import * as THREE from "three"; // 导入轨道控制器 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; // 导入lil.gui import { GUI } from "three/examples/jsm/l…...

Redis | 数据结构(01)
这里写自定义目录标题 Redis 速度快的原因除了它是内存数据库,使得所有的操作都在内存上进行之外,还有一个重要因素,它实现的数据结构,使得我们对数据进行增删查改操作时,Redis 能高效的处理。 因此,这次我…...

一文详解多模态大模型发展及高频因子计算加速GPU算力 | 英伟达显卡被限,华为如何力挽狂澜?
★深度学习、机器学习、多模态大模型、深度神经网络、高频因子计算、GPT-4、预训练语言模型、Transformer、ChatGPT、GenAI、L40S、A100、H100、A800、H800、华为、GPU、CPU、英伟达、NVIDIA、卷积神经网络、Stable Diffusion、Midjourney、Faster R-CNN、CNN 随着人工智能技术…...

debian 10 安装apache2 zabbix
nginx 可以略过,改为apache2 apt updateapt-get install nginx -ynginx -v nginx version: nginx/1.14.2mysql 安装参考linux debian10 安装mysql5.7_debian apt install mysql5.7-CSDN博客 Install and configure Zabbix for your platform a. Install Zabbix re…...

Qt之菜单栏、工具栏、状态栏介绍及工具栏QAction的动态增删显示实现方式
目的 端应用程序或者编辑器基本都支持工具栏快捷功能的动态增删,即通过在菜单栏上打钩就可以在工具栏上看到相应功能的快捷按钮,取消打钩则在工具栏上就移除了该功能的快捷按钮。那么Qt如何实现这个功能,本篇目的就是记录实现此功能的方法及思…...

十四天学会C++之第八天:文件操作
1. 文件的打开和关闭 文件操作的基本概念。打开文件:使用fstream库打开文件以供读写。关闭文件:确保文件在使用完毕后正确关闭。 文件的打开和关闭:C 文件操作入门 在C编程中,文件操作是一项重要的任务,可以读取和写…...

基于(N-1)×(N-1)棋盘的解的情况推出N×N棋盘的解的情况的N皇后问题
N皇后问题是一个比较经典的问题,其主要目标是在NN的棋盘上,放置N个皇后,要求所有皇后之间不能互相攻击,即任意两个皇后不能处在同一行、同一列或同一对角线上。解决该问题可以采用递归的方式,基于(N-1)棋盘的解的情况推…...

Vue mixin混入
可以把多个组件中共有的配置提取出来构成一个混入。 一、配置混入 (一) 创建mixin.js 这里的名字可以自定义,但是为了方便识别,多数场景下都写mixin。 mixin.js 要创建在src目录下,与main.js平级: &…...

基于 FFmpeg 的跨平台视频播放器简明教程(十):在 Android 运行 FFmpeg
系列文章目录 基于 FFmpeg 的跨平台视频播放器简明教程(一):FFMPEG Conan 环境集成基于 FFmpeg 的跨平台视频播放器简明教程(二):基础知识和解封装(demux)基于 FFmpeg 的跨平台视频…...

正点原子嵌入式linux驱动开发——Linux LCD驱动
LCD是很常用的一个外设,通过LCD可以显示绚丽的图片、界面等,提交人机交互的效率。STM32MP1提供了一个LTDC接口用于连接RGB接口的液晶屏。本章就来学校一下如何在Linux下驱动LCD屏。 LCD和LTDC简介 LCD简介 这里在当时学习stm32裸机开发的时候就学过了…...

2-Java进阶知识总结-6-多线程
文章目录 多线程--基本概念并发和并行进程和线程多线程 多线程--实现方式一,继承Thread类方法介绍实现步骤注意事项 方式二,实现Runnable接口Thread构造方法实现步骤 方式三,实现Callable接口方法介绍实现步骤 三种多线程实现方法对比 多线程…...