golang如何实现消息防重复发送_golang消息防重复发送实现教程
Kafka幂等生产者是最省心的防重方案需开启idempotence并满足单生产者单分区条件语义去重则需应用层指纹Redis原子校验。用 Kafka 幂等生产者是最省心的防重发送方案Kafka 0.11.0 原生支持幂等性只要开启配置就能从协议层杜绝「同一条消息重复入队」。它不依赖业务逻辑、不增加中间件、也不需要你手写去重逻辑——前提是你的场景满足「单生产者实例 单分区语义」。config.Producer.Idempotent true 必须设为 true这是开关同时 config.Producer.Retry.Max 要 ≥ 1幂等依赖重试机制不能手动指定 Partition 后再启用幂等——否则会 panicKafka 要求幂等生产者必须由 broker 自动分配分区否则无法保证 PID SeqNum 的连续性每条消息的 Key 不影响幂等性但会影响分区路由如果你靠 Key 做语义分组比如 user_id那幂等只在该分区维度生效跨分区不保序也不防重注意 client ID同一 client.id 下重启的生产者能延续 PID不同 client ID 视为全新生产者历史 SeqNum 不继承自己生成唯一消息指纹 Redis 校验适合自定义去重逻辑当你要防的是「语义重复」而非「字节重复」时比如两条内容完全一样的订单创建请求就得在应用层做指纹提取缓存校验。这时候 Kafka 幂等没用——它只认 byte-level 相同不理解 JSON 字段含义。指纹建议拼接method topic userID orderID body_hash[:12]别用纯时间戳或 time.Now().UnixNano()容器里纳秒级极易碰撞Redis 写入必须用原子命令SET key processing EX 300 NX返回 OK 才继续发消息返回 (nil) 就直接跳过避免多协程并发写入同一条过期时间要大于消息端到端最大耗时含网络延迟、broker 处理、消费者拉取建议设为 5–10 分钟太短会导致“刚发完还没消费key 就过期了”下次重试仍被放行不要把整个 body 存 Redis只存指纹和状态结果数据另存如用 idempotent:result:{fingerprint}避免大 value 拖慢 SETsync.Map 在单机轻量场景下可替代 Redis但得自己管过期如果你是单实例部署、QPS 不高sync.Map 是零依赖、低延迟的选择。但它不提供 TTL所有清理逻辑都得你补全。键名格式推荐fmt.Sprintf(%s:%s:%s, topic, userID, hex.EncodeToString(hash[:8]))避免不同 topic 冲突值类型别用 bool改用结构体type idempotentItem struct { done bool; result []byte; ts time.Time }方便后续判断是否超时必须启动 goroutine 定期扫描time.AfterFunc(10*time.Second, cleanupExpired) 或用 time.Ticker否则内存只增不减写入前先 Load命中且 done true 就直接返回缓存结果未命中则 LoadOrStore 占位执行完再 Store 更新状态数据库唯一索引是最后一道不可绕过的防线无论 Kafka 幂等、Redis 校验还是 sync.Map都可能因网络中断、服务崩溃、配置错误而失效。真正能 100% 拦住重复数据的只有数据库的唯一约束。 Cleanup.pictures 智能移除图片中的物体、文本、污迹、人物或任何不想要的东西