ABP VNext + Redis Bloom Filter:大规模缓存穿透防护与请求去重 🚀


📚 目录

  • ABP VNext + Redis Bloom Filter:大规模缓存穿透防护与请求去重 🚀
    • TL;DR ✨
    • 1. 引言 🎉
    • 2. 环境与依赖 🛠️
    • 3. Bloom Filter 原理简述 🎓
    • 4. ABP 中的配置化注入 🔧
      • 4.1 配置类
      • 4.2 Module 注册
    • 5. 请求去重 Behavior 🔐
      • 5.1 Key 生成:SHA-256 哈希
      • 5.2 自定义异常
      • 5.3 Behavior 实现
    • 6. 缓存穿透防护策略 🔍
    • 7. Prometheus 全链路监控 📈
      • 7.1 中间件配置
      • 7.2 自定义指标
    • 8. 从启动到拦截 🚀


TL;DR ✨

  • 在 ABP VNext 应用层,通过 BloomFilter.Redis.NetCore + StackExchange.Redis 实现高性能、可配置的请求去重与缓存穿透防护 (NuGet)
  • 支持 IOptionsMonitor<BloomSettings> 动态调整预估容量、误判率与 Filter Key
  • 使用 SHA-256 生成紧凑稳定的请求 Key 并结合 ContainsAsync + AddAsync 避免并发竞态
  • 自定义 DuplicateRequestException 映射 HTTP 409,嵌入日志(ILogger)与 Prometheus 指标,全链路可观测 (NuGet)

1. 引言 🎉

在高并发场景下,比如秒杀、验证码、消息幂等等业务,常会遇到:

  • 缓存穿透:恶意或无效 Key 直击数据库,拖垮后端 😱
  • 请求去重:同一业务上下文多次触发同一逻辑,浪费计算与 I/O 🔄

如何在 ABP VNext (.NET 7/8) 中:

  1. 请求去重:管道最前端拦截重复请求
  2. 缓存穿透防护:访问 DB/缓存前快速判断 Key 是否“可能存在”

并在生产级角度引入:

  • 配置化 (IOptionsMonitor<BloomSettings>)
  • SHA-256 Key 生成
  • ContainsAsync + AddAsync 竞态处理
  • Prometheus 全链路监控
ContainsAsync false
ContainsAsync true
客户端发起请求
BloomFilterBehavior
AddAsync + 下游执行
抛出 DuplicateRequestException
调用下游 Handler
返回 HTTP 409

2. 环境与依赖 🛠️

dotnet add package StackExchange.Redis
dotnet add package BloomFilter.Redis.NetCore --version 2.5.2
dotnet add package prometheus-net.AspNetCore
  • BloomFilter.Redis.NetCore:Redis 后端 Bloom Filter 实现 (NuGet)
  • prometheus-net.AspNetCore:ASP.NET Core 集成的 Prometheus 指标服务 (NuGet)

appsettings.json 示例:

{"Redis": {"Configuration": "127.0.0.1:6379"},"BloomSettings": {"FilterKey": "bf:requests","ExpectedItems": 1000000,"FalsePositiveRate": 0.001}
}

3. Bloom Filter 原理简述 🎓

false
true
请求 Key
ContainsAsync?
AddAsync + 放行
抛出 409 异常
  • 结构:大小为 m 的位数组 + k 哈希函数

  • 误判率

    • k = ln2·(m/n)
    • 误判 ≈ (1–e–k·n/m)k
  • 对比 LRU

    • LRU:存全量 Key,无误判
    • Bloom:低内存、高速,允许小概率误判

4. ABP 中的配置化注入 🔧

4.1 配置类

public class BloomSettings
{public string FilterKey { get; set; }public long ExpectedItems { get; set; }public double FalsePositiveRate { get; set; }
}

4.2 Module 注册

public override void ConfigureServices(ServiceConfigurationContext context)
{var config = context.Services.GetConfiguration();// 绑定配置Configure<BloomSettings>(config.GetSection("BloomSettings"));// 注入 Redis 连接context.Services.AddSingleton<IConnectionMultiplexer>(sp =>ConnectionMultiplexer.Connect(config["Redis:Configuration"]));// 注入 BloomFilter(FilterRedisBuilder.Build 来自 BloomFilter.Redis.NetCore)context.Services.AddSingleton<IBloomFilter>(sp =>{var settings = sp.GetRequiredService<IOptionsMonitor<BloomSettings>>().CurrentValue;return FilterRedisBuilder.Build(config["Redis:Configuration"],   // Redis 连接字符串settings.FilterKey,              // Bloom Filter Key & 名称(int)settings.ExpectedItems,     // 预估容量settings.FalsePositiveRate       // 误判率);});// 注册 Pipeline Behaviorcontext.Services.AddTransient(typeof(IPipelineBehavior<,>),typeof(BloomFilterBehavior<,>));
}

FilterRedisBuilder.Build 方法在 vla/BloomFilter.NetCore 库中提供,可配置容量、误判率并返回 IBloomFilter 实例 (GitHub)。


5. 请求去重 Behavior 🔐

5.1 Key 生成:SHA-256 哈希

public static class BloomKeyGenerator
{public static string Generate(object request){var raw = $"{request.GetType().Name}:{JsonSerializer.Serialize(request, new JsonSerializerOptions {IgnoreNullValues = true})}";using var sha = SHA256.Create();var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(raw));return Convert.ToHexString(hash); // .NET 5+ API}
}

🔍 提示:极端高吞吐场景可选用 xxHash 等非加密哈希,进一步降 CPU 开销 (GitHub)。

5.2 自定义异常

public class DuplicateRequestException : BusinessException
{public DuplicateRequestException(): base("DUPLICATE_REQUEST", "请求已被拦截(重复请求)") { }
}

全局异常处理中映射为 HTTP 409 Conflict。

5.3 Behavior 实现

public class BloomFilterBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>where TRequest : IRequest<TResponse>
{private readonly IBloomFilter _bloom;private readonly ILogger _logger;private static readonly Counter ContainsCount = Metrics.CreateCounter("bloom_contains_total", "BloomFilter ContainsAsync 调用总数");private static readonly Counter AddCount = Metrics.CreateCounter("bloom_add_total",      "BloomFilter AddAsync 调用总数");private static readonly Counter DuplicateCount = Metrics.CreateCounter("bloom_duplicate_total","重复请求拦截总数");public BloomFilterBehavior(IBloomFilter bloomFilter,ILogger<BloomFilterBehavior<TRequest, TResponse>> logger){_bloom = bloomFilter;_logger = logger;}public async Task<TResponse> Handle(TRequest request,RequestHandlerDelegate<TResponse> next,CancellationToken cancellationToken){var key = BloomKeyGenerator.Generate(request);ContainsCount.Inc();if (await _bloom.ContainsAsync(key)){DuplicateCount.Inc();_logger.LogWarning("重复请求拦截: {Key}", key);throw new DuplicateRequestException();}AddCount.Inc();await _bloom.AddAsync(key);return await next();}
}

如所用库的 AddAsync 返回布尔值,可用返回值判断“新加”/“已存在”,进一步简化逻辑。


6. 缓存穿透防护策略 🔍

public async Task<ProductDto> GetAsync(Guid productId)
{var key = productId.ToString();// 1. Bloom 预判断if (!await _bloom.ContainsAsync(key)){// 未命中,尝试真实查询并预热var entity = await _repository.GetAsync(productId);if (entity != null){await _bloom.AddAsync(key);}return entity; // null 或真实结果}// 2. 可能存在,直接查询缓存/DBreturn await _repository.GetAsync(productId);
}
false
entity ≠ null
entity = null
true
GetAsync(Product)
ContainsAsync?
Db.GetAsync
AddAsync
返回 null
Cache/DB 查询

✔️ 优化:此策略无需离线“预热”,首访合法请求正常命中并写入 Bloom。


7. Prometheus 全链路监控 📈

7.1 中间件配置

var builder = WebApplication.CreateBuilder(args);// 注册 Prometheus 指标服务 & HTTP 埋点
builder.Services.AddMetricServer();
builder.Services.AddHttpMetrics();var app = builder.Build();
app.UseHttpMetrics();   // 自动统计 HTTP 请求
app.UseMetricServer();  // 暴露 /metrics
app.MapControllers();
app.Run();

Prometheus 客户端包:prometheus-net.AspNetCore (NuGet)。

7.2 自定义指标

  • bloom_contains_total
  • bloom_add_total
  • bloom_duplicate_total
  • false_positive_total(业务层捕获误判并上报)

8. 从启动到拦截 🚀

docker run -d --name redis -p 6379:6379 redis:7
dotnet run --project YourAbpApp
ClientAPIRedisDB第 1 次 请求ContainsAsync(key)falseAddAsync(key)OKGetAsync(key)返回数据200 OK第 2 次 请求ContainsAsync(key)true409 ConflictClientAPIRedisDB

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

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

相关文章

构建工具和脚手架:从源码到dist

构建工具和脚手架&#xff1a;从源码到dist**1. 为什么需要工程转换&#xff1f;****2. 构建工具的核心职责**为什么要求转换**1&#xff09;明确三种关键问题****&#xff08;2&#xff09;Webpack 的打包机制****3. 开发服务器&#xff08;Webpack Dev Server&#xff09;***…

数字化生产管理系统设计

下面提供一个基于Python的数字化管理系统框架&#xff0c;使用现代技术栈实现。这个系统将包含设备监控、故障管理、装配配套表生成、生产计划管理等功能。系统架构数字化生产管理系统 ├── 设备监控模块 ├── 故障管理模块 ├── 产品装配管理模块 ├── 生产计划管理模…

【vue】创建响应式数据ref和reactive的区别

目录 1、所谓响应式数据 2、ref创建基本类型响应式数据 3、reactive创建对象类型响应式数据 4、ref定义对象类型响应式数据 5、总结&#xff1a;ref和reactive对比 6、补充&#xff1a;toRefs与toRef 1、所谓响应式数据 所谓响应式数据就是&#xff0c;在vue页面中&#…

YOLO12 改进、魔改|直方图 Transformerm模块HTB ,通过动态范围特征分组、针对性注意力与多尺度融合,提高对遮挡以及多尺度目标的关注能力

在恶劣天气&#xff08;如雨、雪、雾&#xff09;下的图像恢复任务中&#xff0c;传统 Transformer 模型为降低计算量&#xff0c;常将自注意力限制在固定空间范围或仅在通道维度操作&#xff0c;导致难以捕捉长距离空间特征&#xff0c;尤其无法有效处理天气退化像素&#xff…

涉水救援机器人cad【12张】三维图+设计书明说

涉水救援机器人设计 摘 要 随着城市化进度的加快&#xff0c;各种水上游乐设备的增多&#xff0c;水上灾害和溺水事件频繁发生&#xff0c;水上救援任务困难重重&#xff0c;特别是在一些水流湍急的环境下进行救援。传统的水上救援工作比较缓慢&#xff0c;大多数是通过投射救…

电子病历:现代HIS系统不可或缺的核心组成部分

一、电子病历在 HIS 系统中扮演了一个什么角色?电子病历在医院信息系统&#xff08;HIS&#xff09;中扮演着核心、基础且不可替代的角色&#xff0c;可以说是整个HIS系统的临床信息中枢和业务驱动引擎。它的重要性体现在以下几个方面&#xff1a;1、临床诊疗活动的核心载体&a…

【深度学习】通俗易懂的基础知识:指数加权平均

一、什么是指数加权平均&#xff1f; 指数在数学中表示一个数的幂次运算&#xff08;如aⁿ中的n&#xff09;&#xff0c;而在统计学中特指随时间变化的几何衰减系数&#xff0c;加权指对不同数据赋予不同权重&#xff0c;使重要数据对结果产生更大影响。指数加权平均指是一种时…

c++-list

C-list std::list是C标准模板库(STL)提供的双向链表容器&#xff0c;它提供了高效的插入和删除操作&#xff0c;特别适合频繁修改的序列。定义在 <list> 头文件中&#xff0c;属于 std 命名空间。该类的接口与常规容器接口基本一致。 模板原型&#xff1a; template <…

【笔试真题】2024秋招京东后端开发岗位-第一批笔试

31.牛牛与切割机 有一个序列 a1,a2,...,ana_1,a_2,...,a_na1​,a2​,...,an​ &#xff0c; 牛牛将对这个序列切割一刀&#xff08;划分分成两个不相交的非空序列&#xff0c;一个序列为 a1,...,apa_1,...,a_pa1​,...,ap​&#xff0c;另一个序列为 ap1,...,ana_{p1},...,a_na…

【整数转罗马数字】

思路计算数字的位数&#xff1a; 通过 while(x) 循环计算输入数字 num 的位数 n。提取各位数字&#xff1a; 将数字 num 的每一位分解并存储到 nums 数组中&#xff0c;顺序为从高位到低位。罗马数字映射&#xff1a; 使用固定数组 Roman 存储罗马数字符号&#xff1a;Roman {…

spring Scheduled注解详解

spirng Scheduled注解详解 用于标记需要安排执行的方法的注解。必须指定 cron、fixedDelay 或 fixedRate 中的恰好一个属性。 被标注的方法必须不接受任何参数。它通常会具有 void 类型的返回值&#xff1b;如果不是这样&#xff0c;那么在通过调度器调用该方法时&#xff0c;返…

新升级超值型系列32位单片机MM32G0005

灵动微推出的新型MM32G0005系列基于ArmCortex - M0内核&#xff0c;具备高可靠性、低功耗、高性价比等特性。Flash升级至64KB&#xff0c;SRAM为4KB&#xff0c;还有1KB Data Flash。Flash全温擦写次数超过10万次。采用24Pin封装&#xff0c;最多有22个IO。QFN20和TSSOP20封装与…

Spark SQL 的详细介绍

Spark SQL 是 Apache Spark 生态系统中用于处理结构化数据的模块&#xff0c;它将 SQL 查询与 Spark 的分布式计算能力相结合&#xff0c;提供了一种高效、灵活的方式来处理结构化和半结构化数据。以下是对 Spark SQL 的详细介绍&#xff1a;1. 核心定位与优势结构化数据处理&a…

【FreeRTOS】空闲任务与钩子函数原理、实现与功能详解

一、FreeRTOS空闲任务概述FreeRTOS中的空闲任务(Idle Task)是系统自动创建的一个特殊任务&#xff0c;具有最低优先级(优先级0)。当没有其他更高优先级的任务运行时&#xff0c;调度器就会运行空闲任务。空闲任务的主要功能系统资源回收&#xff1a;自动清理被删除任务的内存和…

imx6ull-驱动开发篇6——Linux 设备树语法

目录 前言 设备树 设备树概念 DTS、 DTB 和 DTC DTS 语法 .dtsi 头文件 设备节点 /根节点​​ 节点命名与标签 节点层次结构​ 属性数据类型​ 标准属性 compatible 属性 model 属性 status 属性 #address-cells 和#size-cells 属性 reg 属性 ranges 属性 n…

ansible简单playbook剧本例子2

1. 准备主机组[rootansible-master ansible_quickstart]# vim inventory/hosts[web:vars] ansible_port22 ansible_passwordAdmin123456[web] 192.168.100.1822.准备剧本 vim hello.yml--- - hosts: webremote_user: roottasks:- name: Ping the target hostsping:- name: 获取…

EmpService 和 EmpMapper接口的作用

在这个项目中&#xff0c;EmpService 和 EmpMapper 都定义接口&#xff0c;是基于面向接口编程&#xff08;Interface Oriented Programming&#xff0c;IOP&#xff09;的设计思想&#xff0c;这两种接口在项目中承担着不同的职责&#xff0c;具体说明如下&#xff1a; EmpSer…

【语音技术】什么是动态实体

目录 动态实体的定义和维度 1.1 动态实体的资源 1.2 生效维度 1.2.1 应用级 1.2.2 用户级 1.2.3 自定义级 2. 动态实体的上传及使用 2.1 WebAPI 2.1.1 授权认证 2.1.2 上传资源接口 2.1.2.1 参数说明 2.1.2.2 返回说明 2.1.3 查询打包状态 2.1.3.1 参数说明 2.1.…

STM32学习记录--Day3

今天了解了下I2C&#xff1a;1.I2C电路结构I2C通信示意图&#xff1a;数据传输阶段​​​​主→从模式​​&#xff08;写操作&#xff09;&#xff1a;主机控制SCL时钟&#xff08;把SCL拉低&#xff09;主机向SDA线发送数据&#xff08;每次8位1位ACK&#xff09;​​主←从模…

裂变数据看板:5个核心指标决定活动生死​

数据是裂变活动的“指南针”。本文详解曝光量、转化率、裂变系数等5大核心指标&#xff0c;结合工具与案例&#xff0c;教你用数据驱动活动优化&#xff0c;避免“自嗨式裂变”。​为什么数据是裂变的“生死线”&#xff1f;&#xff08;认知重构&#xff09; 很多企业裂变活动…