Redis如何实现高性能的布隆过滤器_利用Lua脚本原子化更新

梦强吖_5041

梦强吖_5041

2026-05-12

927人浏览

原创

必须用lua脚本封装布隆过滤器操作,因为其原子性可确保k个哈希位的setbit/getbit不可分割;且所有哈希计算须在lua内完成,避免客户端哈希不一致导致映射错乱。

redis如何实现高性能的布隆过滤器_利用lua脚本原子化更新

为什么不能直接用 SETBIT + GETBIT 手动实现布隆过滤器

Redis 原生不提供布隆过滤器命令,有人会尝试用 SETBIT 和 GETBIT 模拟位数组,再自己算哈希、设位——这在单线程下看似可行,但一到并发就出问题:多个客户端同时对同一个 key 执行多次 SETBIT,无法保证所有哈希位原子性地“全写入或全不写”。漏掉任意一位,后续 GETBIT 判断就可能误判为“不存在”,破坏布隆过滤器的“不漏判”特性。

更麻烦的是,手动实现还要自己管理容量扩容、哈希函数数量、误判率控制,实际落地时极易因位图越界(ERR bit offset is not an integer or out of range)或哈希冲突堆积导致误判率远超预期。

所以,绕过 Lua 直接用客户端拼逻辑,不是“能不能做”,而是“做了也难稳”。

为什么必须用 Lua 脚本封装布隆过滤器操作

Lua 脚本在 Redis 中以原子方式执行,整个脚本期间不会有其他命令插入。这对布隆过滤器最关键:添加元素需计算 k 个哈希值、对 k 个位执行 SETBIT;查询需对 k 个位执行 GETBIT 并 AND 判断——这两组操作都必须不可分割。

常见错误是把哈希计算放在客户端,只让 Lua 做位操作。这不行:不同客户端用不同语言/版本算哈希,结果不一致(比如 Python 的 hash() 在进程重启后变,Java 的 String.hashCode() 虽稳定但和 Redis Lua 的 redis.sha1hex() 不兼容),会导致同一元素在不同客户端被映射到不同位,彻底失效。

正确做法是:所有哈希计算、位索引推导、位操作,全部在 Lua 脚本内完成。示例如下(简化版 ADD):

local key = KEYS[1]
local element = ARGV[1]
local m = tonumber(ARGV[2]) -- 位图总长度
local k = tonumber(ARGV[3]) -- 哈希函数个数
<p>for i = 1, k do
local h = redis.sha1hex(element .. i) -- 拼 salt 防止哈希退化
local idx = tonumber(string.sub(h, 1, 12), 16) % m
redis.call('SETBIT', key, idx, 1)
end
return 1</p>

注意:string.sub(h, 1, 12) 取前 12 位十六进制字符(≈48bit),转十进制后对 m 取模,避免大数溢出;i 作为 salt 确保 k 个哈希相互独立。

redis-tools
redis-tools

按类别查找Redis命令、检测服务器连接、监控键数量和内存占用,支持离线速查表。

下载

如何避免 Lua 脚本触发 Redis 的 OOM 或慢日志

布隆过滤器的位图如果过大(比如 m > 100M bits ≈ 12MB),每次 SETBIT 都可能触发 Redis 内存重分配,而 Lua 脚本执行期间会阻塞主线程——一个大 key 的 ADD 就能让整个实例卡住几百毫秒。

实操建议:

  • 预估容量:用公式 m = -n * ln(p) / (ln(2)^2) 计算位图大小,其中 n 是预期元素数,p 是目标误判率(如 0.01);别盲目设 1GB 位图
  • 拆分粒度:对超大规模场景,按时间窗口或业务维度分 key(如 bloom:order:202405),而非单 key 扛全量
  • 禁用 EVALSHA:Lua 脚本尽量用 EVAL 直传(避免 EVALSHA 命中失败后 fallback 的额外 round-trip),但要控制脚本长度(lua-time-limit 默认 5s,超时会中断并返回错误 BUSY Redis is busy running a script)
  • 监控 latency latest 和 slowlog get,重点看 eval 类型慢命令

为什么推荐用 RedisBloom 模块而不是手写 Lua

手写 Lua 能跑通,但生产环境要面对的问题远不止原子性:自动扩容(当元素数超限时动态扩展位图)、内存优化(roaring bitmap 压缩)、多精度支持(支持 COUNTING 布隆)、与 Redis Cluster 兼容性……这些全靠 Lua 很难稳健实现。

RedisBloom 模块(官方维护)已解决这些问题:BF.ADD / BF.EXISTS 原子、BF.RESERVE 支持指定 ERROR 和 SIZE、集群模式下 key hash tag 自动路由。它底层仍是 C 实现的位操作,性能比 Lua 高一个数量级。

如果你的 Redis 版本 ≥ 6.0 且能装模块,别犹豫——redis-cli --loadmodule ./redisbloom.so 启动后,直接用 BF.ADD myfilter "user:123"。手写 Lua 的唯一合理场景,是嵌入已有无法升级/加模块的旧系统,且数据规模可控(日增

真正容易被忽略的点是:布隆过滤器的“删除”能力。标准布隆不支持删除,RedisBloom 的 CF.ADD(Cuckoo Filter)可删但有踢出风险;而手写 Lua 若强行加 DELETE 逻辑,极易因并发导致状态不一致——这时候,与其硬刚,不如换思路:用带 TTL 的普通 key 做轻量缓存兜底。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

相关标签:

redis

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

4569

19

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.14

4135

11

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.02

7712

6

redis怎么做缓存服务器
redis怎么做缓存服务器

redis 作为缓存服务器的答案:redis 是一款开源、高性能、分布式的键值存储,可作为缓存服务器使用。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

643

6

redis怎么解决数据一致性
redis怎么解决数据一致性

redis 提供了两种一致性模型,以维护副本数据一致性:强一致性 (sync) 确保写操作仅在复制到所有从节点后才完成;最终一致性 (async) 则在主节点上写操作后认为已完成,牺牲一致性换取性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

756

6

mysql和redis怎么保证双写一致性
mysql和redis怎么保证双写一致性

确保 mysql 和 redis 双写一致性的技术包括:1、事务性更新:同时更新 mysql 和 redis,保证一致性;2、主从复制:mysql 主服务器更改同步到 redis 从服务器;3、基于事件的更新:mysql 记录更改并发送到 redis等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

7682

6

redis缓存一般存些什么数据
redis缓存一般存些什么数据

redis缓存中存储的数据类型包括:字符串、哈希、列表、集合、有序集合、位图、地理空间数据和hyperloglog。这些数据类型适用于存储各种数据,从简单信息到复杂对象和地理位置。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

1160

6

redis的8种数据类型有哪些
redis的8种数据类型有哪些

redis 提供 8 种数据类型:字符串(文本、数字、二进制)、哈希(键值对)、列表(有序集合)、集合(无序唯一元素)、有序集合(按分数排序)、地理空间(地理位置)、hyperloglog(估计大数据基数)和位图(位序列存储)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

1156

6

redis主要作用有哪些
redis主要作用有哪些

redis 的主要作用包括:1. 缓存数据,提高访问速度;2. 充当消息队列,实现消息传递;3. 存储各种数据类型,如字符串、散列和集合;4. 管理会话信息,确保可靠性和可用性;5. 限制请求速率,防止服务器超载等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

6698

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习