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

Redis--布隆过滤器

解决缓存穿透是构建高效缓存系统中的关键问题之一。缓存穿透指的是恶意或者非法请求经过缓存层直接访问数据库或者后端服务,导致系统资源浪费和性能下降的情况。为了有效应对缓存穿透问题,以下是几种常见的解决方法:

1. 布隆过滤器预检查

布隆过滤器是一种高效的数据结构,用于快速判断一个元素是否可能存在于集合中。在处理请求之前,可以使用布隆过滤器对请求的参数或者键进行预检查。如果请求被布隆过滤器判断为肯定不在缓存中,可以直接拒绝该请求,避免向数据库发起不必要的查询操作,从而减少了缓存穿透的风险。

2. 空对象缓存

当数据库或者后端服务查询结果为空时,不应该直接将空结果放入缓存,而应该设置一个较短的缓存过期时间,或者使用特定的标记来表示该键对应的数据不存在。这样可以避免频繁查询数据库,提高缓存的命中率,同时也降低了缓存穿透的可能性。

3. 缓存穿透保护机制

实现一个简单的锁定机制或者防护层,当缓存未命中时,只允许一个请求访问后端服务或数据库,其他请求在等待期间可以从缓存中获取结果,避免同时大量请求穿透缓存层,进一步降低了数据库或者后端服务的负载压力。

4. 使用互斥锁或分布式锁

在高并发环境中,多个请求同时更新缓存时,应使用互斥锁或分布式锁来保护缓存的数据一致性。这样可以确保只有一个请求可以更新缓存,避免了由于并发更新导致的数据不一致或者缓存雪崩的情况发生。

什么是布隆过滤器?

布隆过滤器是一种空间高效的概率型数据结构,用于快速检测一个元素是否属于一个集合中。它可能会返回“存在”(可能存在,有一定误判率),但绝不会返回“不存在”。

工作原理

布隆过滤器的核心组成包括:

  1. 位数组:初始化一个固定大小的位数组,通常初始化为0。
  2. 哈希函数:选择多个独立的哈希函数。这些函数将输入数据(如字符串或数字)映射到位数组的索引位置。
  3. 插入操作:要将元素添加到布隆过滤器中,对元素使用每个哈希函数进行哈希计算,并将位数组中对应位置的位设置为1。
  4. 成员检测:要检查元素是否在布隆过滤器中,对元素使用每个哈希函数进行哈希计算,并检查位数组中对应位置的位是否都为1。如果任何一位为0,则元素肯定不在集合中;如果所有位都为1,则元素可能在集合中。
为什么使用布隆过滤器?

布隆过滤器具有以下几个优点:

  • 空间效率:与存储实际数据相比,它所需的内存大大减少。
  • 快速成员查询:检查成员存在性的时间复杂度是常数时间O(k),其中k是哈希函数的数量。
  • 可扩展性:即使在处理大型数据集时,只要可以接受的误判率较低,它也能够有效运作。
适用场景

布隆过滤器在以下情况下特别适用:

  • 空间受限:需要高效存储大量数据。
  • 速度要求高:需要快速的成员查询,并能够容忍一定的误判率。
  • 预过滤:作为精确检查之前的快速预过滤器,能够提高性能。
实现一个简单的布隆过滤器

让我们通过一个简单的Java实现来说明:

package com.cbv;import java.util.BitSet;
import java.util.Collection;
import java.util.List;public class BloomFilter {// 布隆过滤器的位数组private BitSet hashes;// 位数组的大小private int size;// 使用的哈希函数数量private int numHashes;// 构造函数,初始化布隆过滤器public BloomFilter(int size, int numHashes) {this.size = size;this.numHashes = numHashes;this.hashes = new BitSet(size); // 初始化位数组}// 计算哈希值的方法,基于输入字符串和哈希函数的编号iprivate int hash(String item, int i) {int hash1 = item.hashCode(); // 获取字符串的哈希码int hash2 = (hash1 >>> 16) ^ (hash1 << 1); // 生成第二个哈希值,通过右移和左移哈希码来生成return Math.abs((hash1 + i * hash2) % size); // 生成组合哈希值,并保证其在位数组的范围内}// 向布隆过滤器中添加一个元素public void add(String value) {for (int i = 0; i < numHashes; i++) {hashes.set(hash(value, i)); // 使用多个哈希函数设置位数组中的位}}// 检查布隆过滤器中是否可能包含某个元素public boolean contains(String value) {for (int i = 0; i < numHashes; i++) {if (!hashes.get(hash(value, i))) { // 如果有任意一个哈希值对应的位为0,则元素不在过滤器中return false;}}return true; // 所有哈希值对应的位都为1,则可能包含该元素}// 向布隆过滤器中批量添加多个元素public void addAll(Collection<String> values) {for (String value : values) {add(value); // 调用add方法逐个添加元素}}// 检查布隆过滤器中是否可能包含一组元素public boolean containsAll(Collection<String> values) {for (String value : values) {if (!contains(value)) { // 如果有任意一个元素不在过滤器中,则返回falsereturn false;}}return true; // 所有元素都可能在过滤器中,则返回true}// 测试布隆过滤器的主方法public static void main(String[] args) {int size = 1000; // 位数组大小int numHashes = 10; // 哈希函数数量BloomFilter bloomFilter = new BloomFilter(size, numHashes);List<String> dataList = List.of("item1", "item2", "item3"); // 初始化测试数据bloomFilter.addAll(dataList); // 向布隆过滤器中添加数据System.out.println("Contains item1: " + bloomFilter.contains("item1")); // 应该输出trueSystem.out.println("Contains item3: " + bloomFilter.contains("item3")); // 应该输出trueSystem.out.println("Contains item4: " + bloomFilter.contains("item4")); // 应该输出false}
}
结论

总而言之,布隆过滤器在处理大数据集和性能关键应用时,是程序员工具箱中的一把利器。尽管它会有误判率的问题,但其高效和速度使其在空间和时间有限的情况下,成为不可或缺的选择。理解它的优势和局限性,有助于在实际应用中充分发挥其作用。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Windows与Linux双机热备软件推荐
  • 设计模式使用场景实现示例及优缺点(行为型模式——命令模式)
  • Mac安装stable diffusion 工具
  • 封装网络请求 鸿蒙APP HarmonyOS ArkTS
  • 把关键字当作列名 不报错的方法 (数据库)
  • 大数据技术基础
  • Laravel表单验证的艺术:精细控制数据的入口
  • React遍历tree结构,获取所有的id,切换自动展开对应层级
  • Ajax从零到实战
  • Log4j的原理及应用详解(三)
  • 在GPU上运行PyTorch
  • MVC之 IHttpModule管道模型《二》
  • C++的关键字const
  • 飞睿智能UWB Tag蓝牙防丢器标签,宠物安全新升级,5cm精准定位测距不迷路
  • 杭州汽修元宇宙
  • conda常用的命令
  • Javascript 原型链
  • mysql_config not found
  • mysql常用命令汇总
  • OSS Web直传 (文件图片)
  • React+TypeScript入门
  • ubuntu 下nginx安装 并支持https协议
  • Vue小说阅读器(仿追书神器)
  • WebSocket使用
  • 仿天猫超市收藏抛物线动画工具库
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 简析gRPC client 连接管理
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 一起参Ember.js讨论、问答社区。
  • 在electron中实现跨域请求,无需更改服务器端设置
  • 终端用户监控:真实用户监控还是模拟监控?
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ​Python 3 新特性:类型注解
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • $forceUpdate()函数
  • (3)nginx 配置(nginx.conf)
  • (52)只出现一次的数字III
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (十六)Flask之蓝图
  • (四)鸿鹄云架构一服务注册中心
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (转)c++ std::pair 与 std::make
  • (转)Mysql的优化设置
  • *算法训练(leetcode)第四十天 | 647. 回文子串、516. 最长回文子序列
  • . NET自动找可写目录
  • .gitignore文件_Git:.gitignore
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .net dataexcel winform控件 更新 日志
  • .net MVC中使用angularJs刷新页面数据列表
  • .net SqlSugarHelper
  • .NET 表达式计算:Expression Evaluator
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .Net--CLS,CTS,CLI,BCL,FCL