上一篇
想象一下这个场景:你正在运营一个电商促销系统,"双11"零点刚过,海量订单像潮水般涌来,突然发现,有些顾客的订单竟然重复提交了3-5次!💸 不是因为他们太热情,而是网络抖动导致客户端多次重试,更糟的是,你的优惠券系统给同一个用户发了5张满1000减500的券...财务同事已经在提刀赶来的路上了!😱
这就是典型的消息重复问题——在分布式系统中,网络波动、服务重试、消息队列重投等都会导致重复消息,今天我们就用Redis这个"瑞士军刀"来解决这个棘手问题!
Redis作为内存数据库,有三大绝杀技特别适合消息去重:
def is_duplicate(message_id): key = f"msg:{message_id}" # 如果设置成功返回True,表示首次出现 return not redis.setnx(key, 1) # 设置24小时过期 redis.expire(key, 24*3600)
👍 优点:实现简单,占用空间小
👎 缺点:海量数据时内存消耗大
def check_duplicate(message_id): return redis.sismember("message_set", message_id) def add_message(message_id): redis.sadd("message_set", message_id)
💡 小技巧:配合SCARD
命令还能统计唯一消息量
// 假设message_id是数字 public boolean isDuplicate(long messageId) { return redis.getbit("message_bits", messageId); } public void markAsProcessed(long messageId) { redis.setbit("message_bits", messageId, true); }
📊 内存对比:1亿条消息只需约12MB!但要求ID是数字
// 添加消息 redis.pfadd("message_hll", messageId); // 检查是否可能重复(有约0.8%误差) const isLikelyDuplicate = redis.pfcount("message_hll") === previousCount;
🌐 适用场景:UV统计等允许少量误差的场景
// 使用RedisBloom模块 _, err = client.Do("BF.ADD", "message_bf", messageID) if err != nil { log.Fatal(err) } exists, err := redis.Int(client.Do("BF.EXISTS", "message_bf", messageID))
✅ 特点:空间效率极高,但有假阳性可能(误判为存在)
假设我们有个订单系统,需要防止重复处理订单,采用方案2+方案5的组合拳:
def process_order(order_id): # 第一层:BloomFilter快速过滤 if redis.execute_command("BF.EXISTS", "orders_bf", order_id): # 第二层:Set精确判断 if redis.sismember("orders_set", order_id): print(f"订单{order_id}已处理过,直接跳过") return False # 处理订单逻辑... print(f"处理订单{order_id}") # 更新去重库 redis.execute_command("BF.ADD", "orders_bf", order_id) redis.sadd("orders_set", order_id) redis.expire("orders_set", 7*24*3600) # 保留7天 return True
方案 | 精确度 | 空间占用 | 适用场景 |
---|---|---|---|
String | 100% | 高 | 低频、少量消息 |
Set | 100% | 中 | 需要精确统计的场景 |
Bitmap | 100% | 极低 | ID为连续数字 |
HLL | ~99% | 最低 | 允许误差的统计场景 |
BloomFilter | ~99% | 很低 | 海量数据初步过滤 |
-- 用Lua脚本保证原子操作 local key = KEYS[1] local value = ARGV[1] local ttl = ARGV[2] if redis.call("SETNX", key, value) == 1 then redis.call("EXPIRE", key, ttl) return 0 -- 表示首次出现 else return 1 -- 表示重复 end
对于超大规模系统(日消息量>1亿),可以考虑:
Redis就像消息去重界的"多功能料理机"🍳,不同数据结构对应不同"刀头",选择合适方案,你的系统就能:
下次遇到重复消息,别再手动写数据库查重啦!快掏出Redis这把瑞士军刀🔪,让你的系统轻盈又高效!
本文技术方案基于Redis 7.x版本验证,数据参考自2025年8月Redis官方基准测试报告
本文由 乌孙鑫鹏 于2025-08-01发表在【云服务器提供商】,文中图片由(乌孙鑫鹏)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://vps.7tqx.com/wenda/508285.html
发表评论