反垃圾邮件系统技术选型:5000万级数据高效存储查询及TTL支持需求
针对你这个反垃圾邮件系统的场景,结合5000万条记录的存储、实时读写更新、TTL过期和特定维度的聚合查询需求,我给你几个兼顾时间与空间效率的方案建议,你可以根据自身的并发量、技术栈偏好来选择:
方案一:Redis Cluster(高并发实时读写首选)
这个方案主打极致的读写性能,完美适配反垃圾邮件场景下的高频实时更新需求。
- 数据模型设计:把复合维度(
project_id,domain_id,user_id,type,subtype)和epoch_day组合成紧凑的Redis Key,比如用格式:as:{p}:{d}:{u}:{t}:{st}:{ed}(as是anti_spam的缩写,缩短Key长度节省内存),Value直接存储count的整数值。如果想进一步优化Key数量,也可以把同一天的同维度数据放到Hash结构里:Key为as:{p}:{d}:{u}:{t}:{st},Hash的Field是epoch_day,Value是count。 - 读写更新操作:用Redis的原子命令
INCRBY(或者Hash结构的HINCRBY)直接完成"查询当前值+更新计数"的操作,全程原子性,不用担心并发冲突,而且命令执行速度极快,单节点就能支撑每秒几十万次操作。 - TTL实现:每条记录设置TTL为7天多1小时(比如
86400*7 + 3600秒),确保最近7天的数据都能被查询到,过期后Redis会自动删除,无需额外维护。如果用Hash结构,就给整个Hash Key设置TTL即可。 - 查询实现:
- 最近1天:直接查询当天对应的Key(或Hash Field)的值即可;
- 最近7天:如果是单个Key模式,需要用Key前缀匹配(比如
as:{p}:{d}:{u}:{t}:{st}:*)遍历最近7天的Key,然后用Lua脚本在服务器端求和(减少网络传输开销);如果是Hash模式,直接用HVALS获取所有Field的值,再求和即可。
- 优缺点:优点是读写性能拉满,部署简单,TTL原生支持;缺点是聚合查询需要额外处理,数据存在内存中,单集群的存储容量受限于内存,成本相对较高。
方案二:TiDB(分布式关系型,兼顾OLTP与OLAP)
如果你需要标准SQL支持、复杂查询能力,同时要应对超大规模数据的水平扩展,TiDB是非常合适的选择。
- 数据模型设计:创建专门的表,把
project_id,domain_id,user_id,type,subtype,epoch_day设为联合主键,count设为INT类型。表结构示例:CREATE TABLE anti_spam_records ( project_id INT NOT NULL, domain_id INT NOT NULL, user_id VARCHAR(64) NOT NULL, type INT NOT NULL, subtype INT NOT NULL, epoch_day DATE NOT NULL, count INT DEFAULT 0, PRIMARY KEY (project_id, domain_id, user_id, type, subtype, epoch_day) ); - 读写更新操作:用
INSERT ... ON DUPLICATE KEY UPDATE语法实现原子性的插入或更新,既能获取当前记录的count,又能完成增量更新:
执行后可以直接查询更新后的count值。INSERT INTO anti_spam_records (project_id, domain_id, user_id, type, subtype, epoch_day, count) VALUES (?, ?, ?, ?, ?, ?, 1) ON DUPLICATE KEY UPDATE count = count + 1; - TTL实现:TiDB原生支持TTL,给表添加TTL字段并配置规则即可,数据会自动过期删除:
ALTER TABLE anti_spam_records ADD COLUMN ttl TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + INTERVAL 7 DAY; ALTER TABLE anti_spam_records TTL ttl; - 查询实现:直接用SQL的聚合函数完成,因为有联合主键索引,查询速度非常快:
- 最近1天:
SELECT SUM(count) FROM anti_spam_records WHERE project_id=? AND domain_id=? AND user_id=? AND type=? AND subtype=? AND epoch_day >= CURRENT_DATE - INTERVAL 1 DAY; - 最近7天:把上面的
1 DAY改成7 DAY即可。
- 最近1天:
- 优缺点:优点是支持标准SQL,聚合查询简单,分布式存储可水平扩展,兼顾OLTP和OLAP场景;缺点是读写性能略低于Redis,部署维护复杂度比Redis高。
方案三:ClickHouse(大数据量聚合查询首选)
如果你的场景中聚合查询的需求远高于实时更新需求,或者数据量会持续增长到数亿甚至数十亿条,ClickHouse的高压缩比和极速聚合能力会非常适合。
- 数据模型设计:使用
AggregatingMergeTree引擎,把project_id,domain_id,user_id,type,subtype,epoch_day设为排序键,count字段用聚合函数类型:CREATE TABLE anti_spam_records ( project_id INT, domain_id INT, user_id VARCHAR(64), type INT, subtype INT, epoch_day DATE, count AggregateFunction(sum, UInt32) ) ENGINE = AggregatingMergeTree() ORDER BY (project_id, domain_id, user_id, type, subtype, epoch_day) TTL epoch_day + INTERVAL 7 DAY; - 读写更新操作:通过插入增量记录来实现更新,每次插入
count=1的记录,ClickHouse会在后台自动聚合:
如果需要实时获取聚合值,可以用INSERT INTO anti_spam_records (project_id, domain_id, user_id, type, subtype, epoch_day, count) VALUES (?, ?, ?, ?, ?, ?, sumState(1));sumMerge(count)查询。 - TTL实现:创建表时直接配置
TTL规则,数据会在7天后自动删除,无需额外操作。 - 查询实现:聚合查询速度极快,适合大数据量场景:
SELECT sumMerge(count) FROM anti_spam_records WHERE project_id=? AND domain_id=? AND user_id=? AND type=? AND subtype=? AND epoch_day >= CURRENT_DATE - INTERVAL 7 DAY; - 优缺点:优点是存储压缩比极高(通常能达到10:1以上),聚合查询速度秒杀传统数据库;缺点是实时更新能力较弱(后台异步聚合),不适合高并发的实时更新场景,更适合批量处理或准实时分析。
方案选型建议
- 如果你的系统是高并发实时场景(比如每秒数十万次更新),优先选Redis Cluster;
- 如果需要标准SQL支持、复杂查询,同时数据量会持续增长,选TiDB;
- 如果聚合查询需求占主导,数据量超大,选ClickHouse。
内容的提问来源于stack exchange,提问作者Yash Tandon
相关产品推荐
相关产品推荐

