去年双十一,我们电商系统遇到了一个棘手问题——订单号重复,凌晨流量高峰时,每秒上万笔订单涌入,原本好好的自增ID生成服务突然开始吐出重复的订单号,导致大量支付失败和售后纠纷,事后排查发现,单机版ID生成器在集群环境下根本扛不住高并发,多个实例同时分配ID导致冲突。
这次事故后,我们团队决定重构ID生成服务,经过多方对比,最终选择了基于Redis的分布式ID方案,它不仅解决了我们的燃眉之急,还带来了意想不到的性能提升,下面我就详细分享这个方案的实现细节。
传统数据库自增ID最大的问题就是扩展性差,当系统需要水平扩展时,单点故障和性能瓶颈就会暴露无遗,而Redis在这方面有几个天然优势:
最简单的实现就是利用Redis的INCR命令:
import redis r = redis.StrictRedis(host='localhost', port=6379, db=0) def generate_id(): return r.incr('global_order_id')
这个方案虽然简单,但有几个明显缺陷:
我们在生产环境使用的是改进后的分段批处理方案,核心思想是"预分配":
def get_id_batch(): # 获取当前批次最大值 current_max = r.get('id_max') if not current_max: # 初始化1000个ID空间 r.set('id_max', 1000) return (1, 1000) # 申请下一个批次 new_max = r.incrby('id_max', 1000) return (new_max - 999, new_max)
应用服务器每次获取一个ID区间(如1-1000),在内存中本地分配,这带来三个好处:
对于千万级并发的场景,我们进一步优化架构:
核心代码结构:
class DistributedIDGenerator: def __init__(self, node_id): self.node_id = node_id # 节点标识 self.current_batch = (0, 0) self.next_batch = (0, 0) self.lock = threading.Lock() def get_id(self): with self.lock: if self.__need_refill(): self.__async_refill() return self.__consume_id() def __need_refill(self): return self.current_batch[0] >= self.current_batch[1] * 0.8
在实际压测中,我们总结出几个关键优化点:
管道技术:批量获取ID区间时使用pipeline减少网络往返
pipe = r.pipeline() pipe.get('current_max') pipe.incrby('current_max', 1000) results = pipe.execute()
Lua脚本:将判断与递增操作原子化
local current = redis.call('GET', KEYS[1]) if not current then redis.call('SET', KEYS[1], ARGV[1]) return {0, ARGV[1]} end local new = redis.call('INCRBY', KEYS[1], ARGV[1]) return {new-ARGV[1]+1, new}
热点分离:不同业务使用不同key前缀,如"order_id"、"user_id"
在线上环境中,我们遇到过几个典型问题及解决方案:
时钟回拨问题:服务器时间同步导致时间戳倒退
解决方案:记录最后生成ID的时间戳,检测到回拨时短暂等待
批次浪费问题:服务重启时未使用的ID区间丢失
解决方案:将未使用区间写入Redis临时key,启动时恢复
长尾请求:网络波动导致个别请求超时
解决方案:设置分级超时,首次50ms,重试200ms
我们曾经对比过几种主流方案:
方案 | QPS上限 | 依赖性 | 是否有序 | 实现复杂度 |
---|---|---|---|---|
Redis方案 | 10万+ | 中 | 是 | 中 |
数据库自增 | 5千 | 高 | 是 | 低 |
UUID | 无限 | 无 | 否 | 低 |
雪花算法 | 1万/节点 | 无 | 是 | 高 |
最终选择Redis方案是因为它在有序性、性能和复杂度之间取得了最佳平衡,特别是在已有Redis集群的场景下,几乎不需要额外运维成本。
随着业务发展,我们的ID生成器还在持续进化:
这个方案上线后,经历了三次618和双十一大促的考验,始终保持零故障,最重要的是,它让我们明白了:好的技术方案不一定要多么高大上,适合业务场景的才是最好的。
本文由 旷寄松 于2025-08-02发表在【云服务器提供商】,文中图片由(旷寄松)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://vps.7tqx.com/wenda/510423.html
发表评论