《后端程序猿 · 基于 Lettuce 实现缓存容错策略》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 近期刚转战 CSDN,会严格把控文章质量,绝不滥竽充数,如需交流,欢迎留言评论。👍

文章目录

    • 写在前面的话
    • 背景说明
    • 方案介绍
    • 具体实现
    • 总结陈词

写在前面的话

笔者所在公司由于存在大量业务场景,是借助Redis缓存实现的,因此缓存的健康状态对框架整体的影响较大。
针对这一问题,在框架封装过程中,采用了基于 Lettuce 事件总线实现的缓存容错策略和环境监测。
本篇博文鉴于此方案,展开描述,让我们絮絮道来。


背景说明

在高并发场景中,通常会引入Reids缓存机制,以此减轻数据库的查询压力,增加系统吞吐量。
例如,以Spring开发框架为例,开发者通常会选择采用@Cacheable等注解方式,便捷实现缓存的快速利用。
在传统的开发模式下,当Redis缓存宕机的时候,该注解所标注的方法会直接抛出异常,对功能调用方不太友好,并且针对缓存环境恢复的情况下,没有自动切换缓存策略的机制。开发人员往往要对单独接口进行缓存降级策略的编写,往往容易出现疏漏。开发者即使采用其他缓存客户端代码的使用方式,都不可避免的需要面对这个问题。
同时,由于Redis集群部署成本较高,部分企业并不会采用集群模式,往往不能保障Redis的高可用。
综上所述,Redis在宕机情况下的容错应对机制,是框架设计人员必须要考虑的。

【@Cacheable 技术简介】
@Cacheable 是 Spring 自带的注解,便捷操作缓存的。对于使用 @Cacheable 标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。

【关于缓存容错策略增强】
传统使用Cacheable注解Redis方法时,如果Redis服务器挂了,就直接抛出异常了,
java.net.ConnectException: Connection refused: connect
新框架对Spring的@Cacheable功能进行了增强,支持毫秒级故障自动降级与自动恢复已支持组件。


方案介绍

本方案通过自定义拓展 SpringRedisCacheManager 缓存处理器,设置不同环境的缓存处理策略,并且基于 LettuceEventBus 机制实现缓存环境监测和策略切换,以此增强单机模式下的 Redis容错性。通过这种方式,解决了传统缓存运用的弊端,开发人员可以正常使用@Cacheable,当缓存宕机的话,可以根据项目级配置,指定想要的缓存策略,比如按包装异常抛出策略、或执行原逻辑策略等。当缓存恢复的时候,会自动恢复切换到正常的缓存策略,不影响用户操作,切换不需要人工干预。当然,这一过程,对业务开发人员也是不需要特别关注的,开发人员只需要正常使用缓存场景,不需要为单独接口考虑缓存降级策略。同时,本方案支持采用延迟任务模式,不断确保缓存健康状态下缓存处理器的正确性,并做出相应响应。


具体实现

本方案自定义拓展缓存处理器,基于 Lettuce 的 EventBus 机制实现缓存环境监测和缓存策略切换。完成了对缓存宕机情况下,可以定制缓存容错策略。同时可以根据缓存环境的健康,自动切换缓存策略,增强了系统的稳定性,减少了人工运维成本。
本方案的缓存服务端不局限于Redis,缓存操作方式也不局限于Spring的@Cacheable方式,为方便理解,下文暂以这两种模式声明。
Step1、自定义缓存管理器,继承Spring自带的CacheManager,在其构造函数中,设置失败时的缓存处理器,成功时缓存处理器,当前激活缓存处理器等属性,并重写获取缓存的相关方法,同时新增同步缓存处理器的切换方法;
Step2、定义失败时缓存处理器,读取服务的项目级策略配置,示例代码如下,根据指定的缓存策略枚举,激活对应的缓存容错策略;

xxxx:cache:# degrade=自动降级# 当Redis服务出现故障时,不再查询Redis缓存,直接执行原有的方法逻辑# fail_fast=快速失败# 当Redis服务出现故障时,调用被标记了@Cacheable的方法将直接抛出 cache-fail-strategy: degrade  

Step3、同理,类似步骤2,定义成功时的缓存处理器;
Step4、在程序初始化的时候,利用Lettuce的客户端API,检查缓存当前健康状态,选择对应的缓存处理器为当前激活的缓存处理器;
Step5、在程序初始化的时候,利用Lettuce的EventBus事件总线监听机制,包含但不限于监听ConnectionActivatedEvent和ConnectionDeactivatedEvent等事件,并做出相应处理;
Step6、当监听到ConnectionDeactivatedEvent事件时,代表当前缓存状态异常,此时将触发步骤1的自定义缓存管理器的up方法,将失败时缓存处理器设定为当前激活状态,此时若逻辑执行到@Cacheable等注解方式标注的方法,将根据缓存容错策略,例如进行异常报错或直接执行原方法等;
Step7、当监听到ConnectionActivatedEvent事件时,代表当前缓存状态健康,此时将触发步骤1的自定义缓存管理器的down方法,将失败时缓存处理器设定为当前激活状态,此时若逻辑执行到@Cacheable等注解方式标注的方法,将继续正常优先从缓存加载数据;
Step8、同时,在事件监听逻辑中,利用ScheduledThreadPoolExecutor线程池的scheduleAtFixedRate方法,开启间隔延迟任务,不断检查缓存状态,确保上述缓存切换的准确性,并将结果输出日志;

缓存容错


总结陈词

上文介绍了博主所在公司采用的缓存容错策略方案,仅供参考。
从内容上看,主要是方案介绍(PS:因为是技术交底书口吻编写),有需要源代码的欢迎留言交流。
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

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

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

相关文章

机器学习辅助的乙醇浓度检测

目录 1.为什么要机器学习 2. 神经网络一般组成 3.BP神经网络工作过程 4.评价指标 5.实操代码 1.为什么要用机器学习 人工分析大量的谐振模式,建立各种WGM的响应与未知目标之间的关系,是一个很大的挑战。机器学习(ML)能够自行识别全谱的全部特征。作为…

如何在Lazada平台快速出单?测评助力商家突破销量瓶颈

Lazada在短短的几年里已经发展成了东南亚地区最大的在线购物网站之一 ,很多商家也想要在这样一个大的跨境平台上发展。那么,对于希望在Lazada平台上大展拳脚的商家而言,出单是否容易呢? ​一、Lazada出单容易吗? Lazada出单的难易程度并非…

漫步5G-A City,一份独属于上海的浪漫

作家亨利詹姆斯曾写道,“城市漫步,让我接触到了这个世界上最好的东西”。 用漫无目的地行走,来体验和观察一座城市,上海凭借丰富多元的文化特质,成为citywalk这种浪漫生活方式的流行地。 无论你是漫步在美术馆、画廊林…

数据抓取技术在视频内容监控与快速读取中的应用

引言 在数字化时代,视频内容的快速读取和监控对于内容提供商来说至关重要。思通数科的OPEN-SPIDER抓取技术为这一需求提供了高效的解决方案。 OPEN-SPIDER技术概述 OPEN-SPIDER是思通数科开发的一种先进的数据抓取技术,它能够: - 高效地从各…

Stable Diffusion【基础篇】:降噪强度(denoising strength)

提到降噪强度(denoising strength),大家一定不会陌生,这个参数是图生图中最关键的参数之一。今天在Stable Diffusion Art网站看到一篇介绍降噪强度(denoising strength)的文章(地址:…

从hugging face 下模型

支持国内下载hugging face 的东西 下模型权重 model_id 是红色圈复制的 代码 记得设置下载的存储位置 import os from pathlib import Path from huggingface_hub import hf_hub_download from huggingface_hub import snapshot_downloadmodel_id"llava-hf/llava-v1…

【Python机器学习】模型评估与改进——二分类指标

目录 1、错误类型 2、不平衡数据集 3、混淆矩阵 与精度的关系。 准确率、召回率与f-分数 分类报告 4、考虑不确定性 5、准确率-召回率曲线 6、受试者工作特征(ROC)与AUC 二分类可能是实践中最常见的机器学习应用,也是概念最简单的应…

云原生之容器编排实践-OpenEuler23.09在线安装Kubernetes与KubeSphere

背景 前几篇文章中介绍了如何将 ruoyi-cloud 项目部署到 Kubernetes 集群中,包括网关服务、认证服务和系统服务并且对全部服务采用 YAML 文件的方式来进行部署,这虽然有助于理解 K8S 组织管理资源的风格与底层机制,但是对于团队中不太熟悉命…

代码随想录算法训练营第21天|LeetCode 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

1.LeetCode 669. 修剪二叉搜索树 题目链接:https://leetcode.cn/problems/trim-a-binary-search-tree/description/ 文章链接:https://programmercarl.com/0669.修剪二叉搜索树.html 视频链接:https://www.bilibili.com/video/BV17P41177ud?…

【网络】网络基础(一)

网络基础(一) 文章目录 一、计算机网络背景1.1网络发展1.2认识“协议” 二、网络协议初识2.1OSI七层模型2.2OSI五层模型 三、网络传输基本流程3.1局域网通信3.2网络传输流程不跨子网的网络传输跨子网的网络传输 3.3网络中的地址管理IP地址MAC地址 一、计…

Kotlin中的数据类型

人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 目录 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌…

冒泡排序写法

正宗的冒泡排序写法&#xff1a; public class BubbleSort {public static void main(String[] args) {int[] a {4,6,5,24,3,7,1};//初始化一个最大角标变量int n a.length-1;//循环轮次for (int i0;i<n;i){//从后向前开始&#xff0c;相邻元素比较大小&#xff0c;小的元…

Batch Size 不同对evaluation performance的影响

目录 问题描述如果是bugbatch size的设置问题尝试使用GroupNorm解决batchsize不同带来的问题归一化的分类 参考文章 问题描述 深度学习网络训练时&#xff0c;使用较小的batch size训练网络后&#xff0c;如果换用较大的batch size进行evaluation&#xff0c;网络的预测能力会…

Python基础001

Python输出语句 print输出字符串 print("中国四大名著&#xff1a;","西游记|","三国演义|","红楼梦|","水浒传") print(6) print(1 1)Python输入语句 input函数 input() input("我的名字是&#xff1a;") p…

RK3568驱动指南|第十五篇 I2C-第182章 使用Linux中默认的模拟I2C驱动程序

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

线性代数笔记

行列式 求高阶行列式 可以划上三角 上三角 余子式 范德蒙行列式 拉普拉斯公式 行列式行列对换值不变 矩阵 矩阵的运算 同型矩阵加减 对应位置相加减 矩阵的乘法 左边第 i 行 一次 相乘求和 右边 第 j 列 eg 中间相等 两边规模 矩阵的幂运算 解题思路 找规律 数学归纳…

CVE-2024-6387 分析

文章目录 1. 漏洞成因2. 漏洞利用前置知识2.1 相关 SSH 协议报文格式2.2 Glibc 内存分配相关规则 3. POC3.1 堆内存布局3.2 服务端解析数据时间测量3.3 条件竞争3.4 FSOP 4. 相关挑战 原文链接&#xff1a;个人博客 近几天&#xff0c;OpenSSH爆出了一个非常严重的安全漏洞&am…

重生奇迹mu精灵之心怎么搭配

玩家可以通过召唤来召唤多种精灵之心&#xff0c;每种精灵之心增加的属性也不同。精灵之心的作用是为了提升各种各样的属性。我们可以通过召唤获得精灵之心&#xff0c;前面的解锁费用较低&#xff0c;而后面的解锁需要大量的金币来解锁。 召唤精灵之心后&#xff0c;我们可以…

数据结构(JAVA)—代码题

01-数据结构—判断题 02-数据结构—选择题 03 数据结构—多选填空程序填空 ​ 01-顺序表的建立及遍历 import java.util.Iterator; import java.util.LinkedList; import java.util.ListIterator; import java.util.Scanner;public class Main {public static void main(St…