redis实现布隆过滤器
文档
官方文档
下载地址
说明
- 版本选择:
redis-7.0.0.tar.gz - 下载地址:[https://download.redis.io/releases/redis-7.0.0.tar.gz\](
redis实现布隆过滤器
安装单机版redis
- 安装单机版redis参考文档:redis单机安装
springboot整合redisson单机模式
- springboot整合redisson单机模式参考文档:springboot整合redisson单机模式
方式一:Redisson RBloomFilter
-
Redisson 提供了 R BloomFilter,底层用 Bitmap 实现。
-
使用示例
-
创建
IpBlacklistService.java,校验IP黑名单java@Service public class IpBlacklistService { private static final String BLOOM_KEY = "bloom:ip:blacklist"; private static final long EXPECTED_INSERTIONS = 100_0000L; private static final double FALSE_PROBABILITY = 0.01; private final RedissonClient redissonClient; public IpBlacklistService(RedissonClient redissonClient) { this.redissonClient = redissonClient; } private RBloomFilter<String> getBloomFilter() { RBloomFilter<String> filter = redissonClient.getBloomFilter(BLOOM_KEY); if (!filter.isExists()) { filter.tryInit(EXPECTED_INSERTIONS, FALSE_PROBABILITY); } return filter; } public void addToBlacklist(String ip) { getBloomFilter().add(ip); } public boolean isBlacklisted(String ip) { return getBloomFilter().contains(ip); } } -
创建
IpBlacklistController.java, 提供IP黑名单管理接口,依托Redis布隆过滤器实现黑名单的加入和查询java@RestController @RequestMapping("/blacklist") public class IpBlacklistController { private final IpBlacklistService ipBlacklistService; public IpBlacklistController(IpBlacklistService ipBlacklistService) { this.ipBlacklistService = ipBlacklistService; } /** * 将 IP 加入黑名单 * * @param ip 待加入黑名单的 IP 地址 * @return "ok" 表示添加成功 */ @PostMapping("/ip") public String addIp(@RequestParam("ip") String ip) { ipBlacklistService.addToBlacklist(ip); return "ok"; } /** * 判断 IP 是否在黑名单中 * * @param ip 待校验的 IP 地址 * @return true 可能 blacklisted(存在误判),false 一定不在黑名单 */ @GetMapping("/ip/check") public boolean checkIp(@RequestParam("ip") String ip) { return ipBlacklistService.isBlacklisted(ip); } } -
调用接口
curl命令(windows)shellcurl.exe -X POST "http://localhost:8080/redis01/blacklist/ip?ip=192.168.1.100" curl.exe "http://localhost:8080/redis01/blacklist/ip/check?ip=192.168.1.100"
-
方式二:手动用redis实现布隆过滤器
-
基本思路
- 维护一个长度为 m 的 bit 数组(全 0)
- 准备 k 个 彼此独立的 hash 函数,每个把元素映射到 [0, m-1] 的一个下标。
- 添加:把元素用 k 个 hash 得到 k 个下标,把这 k 个 bit 都置为 1。
- 查询:用同样的 k 个 hash 得到 k 个下标,若全是 1 就说"可能在",有任一是 0 就说"一定不在"。
-
n、p、m、k的含义
- n:要存多少条数据
- p:能接受多高的误判率
- m:一共用多少 bit 存
- k:每个元素用几个 hash(写/查几个 bit)
-
参考文档:布隆过滤器 -Bloom Filter,了解n、p、m、k之间的关系
-
使用示例
-
创建
RedisBloomFilter.java,手动实现布隆过滤器逻辑javapublic class RedisBloomFilter { private final StringRedisTemplate redisTemplate; private final String key; private final int bitSize; private final int hashCount; public RedisBloomFilter(StringRedisTemplate redisTemplate, String key, long expectedInsertions, double fpp) { this.redisTemplate = redisTemplate; this.key = key; this.bitSize = optimalNumOfBits(expectedInsertions, fpp); this.hashCount = optimalNumOfHashFunctions(expectedInsertions, bitSize); } public void add(String value) { for (int i = 0; i < hashCount; i++) { long hash = hash(value, i); long index = (hash & 0x7FFFFFFFFFFFFFFFL) % bitSize; redisTemplate.opsForValue().setBit(key, index, true); } } public boolean contains(String value) { for (int i = 0; i < hashCount; i++) { long hash = hash(value, i); long index = (hash & 0x7FFFFFFFFFFFFFFFL) % bitSize; if (Boolean.FALSE.equals(redisTemplate.opsForValue().getBit(key, index))) { return false; } } return true; } private long hash(String value, int seed) { long result = 0; for (int i = 0; i < value.length(); i++) { result = result * 31 + value.charAt(i) + seed; } return result; } static int optimalNumOfBits(long n, double p) { return (int) (-n * Math.log(p) / (Math.log(2) * Math.log(2))); } static int optimalNumOfHashFunctions(long n, long m) { return Math.max(1, (int) Math.round((double) m / n * Math.log(2))); } }optimalNumOfBits(long n, double p)的作用:在给定预期元素个数 n 和目标误判率 p 时,算出布隆过滤器最少需要多少个 bit(m),使理论误判率不超过 poptimalNumOfHashFunctions(long n, long m)的作用:在已经定好 bit 数 m 和预期元素个数 n 的前提下,算出使误判率尽量低的 hash 函数个数 k
-
创建
ManualIpBlacklistService.java,校验IP黑名单java@Service public class ManualIpBlacklistService { private static final String BLOOM_KEY = "bloom:ip:blacklist"; private static final long EXPECTED_INSERTIONS = 1_000_000L; private static final double FALSE_PROBABILITY = 0.01; private final StringRedisTemplate redisTemplate; private volatile RedisBloomFilter bloomFilter; public ManualIpBlacklistService(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } private RedisBloomFilter getBloomFilter() { if (bloomFilter == null) { synchronized (this) { if (bloomFilter == null) { bloomFilter = new RedisBloomFilter(redisTemplate, BLOOM_KEY, EXPECTED_INSERTIONS, FALSE_PROBABILITY); } } } return bloomFilter; } public void addToBlacklist(String ip) { getBloomFilter().add(ip); } public boolean isBlacklisted(String ip) { return getBloomFilter().contains(ip); } } -
创建
ManualIpBlacklistController.java, 提供IP黑名单管理接口,依托Redis布隆过滤器实现黑名单的加入和查询java@RestController @RequestMapping("/blacklist/manual") public class ManualIpBlacklistController { private final ManualIpBlacklistService manualIpBlacklistService; public ManualIpBlacklistController(ManualIpBlacklistService manualIpBlacklistService) { this.manualIpBlacklistService = manualIpBlacklistService; } /** * 将 IP 加入黑名单(手写布隆过滤器) * * @param ip 待加入黑名单的 IP 地址 * @return "ok" 表示添加成功 */ @PostMapping("/ip") public String addIp(@RequestParam("ip") String ip) { manualIpBlacklistService.addToBlacklist(ip); return "ok"; } /** * 判断 IP 是否在黑名单中(手写布隆过滤器) * * @param ip 待校验的 IP 地址 * @return true 表示可能 blacklisted(存在误判),false 表示一定不在黑名单 */ @GetMapping("/ip/check") public boolean checkIp(@RequestParam("ip") String ip) { return manualIpBlacklistService.isBlacklisted(ip); } } -
调用接口
curl命令(windows)shellcurl.exe -X POST "http://localhost:8080/redis01/blacklist/manual/ip?ip=192.168.1.100" curl.exe "http://localhost:8080/redis01/blacklist/manual/ip/check?ip=192.168.1.100"
-
参考资料
注意事项
- 部分内容由AI生成
- 如有不对,欢迎指正!!!