
1.问题背景
在我们的生产追溯系统中,一个棘手的问题困扰了我们很长时间:如何高效地对大量SN(序列号)进行查重?我们的TDengine数据库中存储了超过1000万条SN记录,且每天还在持续增长。直接查询TDengine的性能很差,因为你不确定时间范围,所以全库扫描最差情况下一次查询需要8秒左右,特别是在30台机器并发查询的情况下,系统几乎无法正常工作。
随着业务规模扩大,预计很快数据量会增长到1亿条,使用传统数据库索引方式已经难以满足高并发、低延迟的需求。我们需要一个更高效的解决方案。
2. 解决方案探索
2.1 传统方案的局限性
最初我们考虑了几种常见的解决方案:
- 数据库索引优化:虽然索引可以提升查询速度,但在上亿数据量级下效果有限
- 分库分表:实现复杂,且仍然无法从根本上解决高并发查询问题
- 内存缓存:全量缓存10-100M的SN数据需要大量内存,成本过高
2.2 布隆过滤器
2.2.1 概率数据结构的引入
在深入研究后,我们发现概率数据结构可能是解决这个问题的关键。这类数据结构使用极少的内存就能处理大规模数据集,代价是引入可控的误判率。
我们主要考察了两种方案:
- Bloom过滤器:空间效率高,但不支持删除操作
- 布谷鸟过滤器(Cuckoo Filter):支持删除操作,且误判率和空间效率可控
因为存在 SN 撤销的情况,所以最终我们选择了布谷鸟过滤器作为核心技术方案。
2.2.2 布谷鸟过滤器
布谷鸟过滤器是一种基于哈希表的概率数据结构,它支持插入、删除和查询操作。
3. 布谷鸟过滤器原理
3.1 基本原理
布谷鸟过滤器是一种概率数据结构,它通过哈希函数将元素映射到固定大小的表中,具有以下特点:
- 空间效率:存储1000万个元素只需约15MB内存
- 查询性能:查询时间复杂度O(1),实际性能<1μs
- 支持删除:与Bloom过滤器不同,可以删除已添加的元素
- 可控误判:可以通过调整参数控制误判率
3.2 误判处理
布谷鸟过滤器最关键的一点是它可能出现”假阳性”(误报),即报告存在实际上不存在的元素。对此,我们设计了二次确认机制:
- 首先在布谷鸟过滤器中快速查询
- 当过滤器报告元素存在时,再去TDengine中进行确认
- 如发现是误判,自动修正过滤器
这种策略充分发挥了布谷鸟过滤器的速度优势,同时保证了结果的准确性。
4. 实现架构
4.1 技术栈选择
- Redis + RedisBloom模块:提供布谷鸟过滤器的实现
- Laravel框架:构建Web管理界面和API服务
- TDengine:作为数据源和二次确认的数据库
4.2 系统架构
我们的SN查重服务由以下几部分组成:
- 数据层:TDengine存储原始SN数据
- 缓存层:Redis存储布谷鸟过滤器
- 服务层:Laravel API提供查重和管理功能
- 管理层:Dcat Admin实现可视化管理
- 客户端:设备端通过API进行SN查询
5 核心功能实现和踩坑
5.1 使用RedisBloom模块
RedisBloom模块是Redis的扩展模块,提供了布谷鸟过滤器的实现。但是我们生产环境都是 docker 部署,所以我们找了一个综合的镜像,包含了 RedisBloom 模块。就是 redis-stack-server 镜像 https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/docker/。
注意:redis-stack-server 镜像中低于 7.0 的版本是不支持布谷鸟过滤器的。
5.2 在 laravel 中使用布谷鸟过滤器
因内Laravel 的原生 redis 扩展不支持布谷鸟过滤器,所以要使用 rawCommand 来使用布谷鸟过滤器。
1 | Redis::connection()->client()->rawCommand( |
这是布谷鸟过滤器的初始化命令,$capacity 是过滤器的容量,$expansion 是扩展因子,$max_iterations 是最大迭代次数。
然后在初始化中,加载历史 SN到 Redis 中,
1 | $result = taosHttpClient($sql); |
这只是 demo,实际场景是要分批加载的,否则单次加载太多,内存会直接爆掉。
注意:CF.ADDNX 是布谷鸟过滤器的添加命令,如果元素已经存在,则不添加。而 CF.ADD 是布隆过滤器的添加命令,如果元素已经存在,依然会添加。 见: https://redis.io/docs/latest/commands/cf.add/
5.3 核心判重代码
1 | public function checkSN(Request $request) |
6. 性能对比
6.1 查询性能 (当前 1000w 数据量下)
方案 | 单次查询时间 | 内存占用 | 支持删除 | 额外条件 |
---|---|---|---|---|
直接查询TDengine | ~8秒 | 低 | 是 | TDEngine 服务器会产生大量 CPU 和内存占用 |
MySQL索引 | ~500ms | 中 | 是 | 需要大量索引和分表,同时占用大量硬盘 |
Redis集合 | ~1ms | 高(~500MB) | 是 | 无法满足日后数据量增长 |
布谷鸟过滤器 | <1μs | 低(~15MB) | 是 | 完美 |
7. 总结
布谷鸟过滤器在当前 1000w 数据量下,查询性能和内存占用都非常优秀,支持删除操作,且误判率和空间效率可控。
布谷鸟过滤器为我们的SN查重服务带来了质的飞跃,将http查询时间降至秒级,同时大幅降低了资源消耗。这种技术方案特别适合大规模数据的快速查重场景。