背景:在分布式系统中,对于订单ID如何保证全局唯一地高效的生成,并对性能影响不大的情况下,利于建立索引和业务使用?
方案一:使用数据库主键ID
优势:实现简单;
弊端:使用数据库增加写库的压力,生成订单的上限受限于数据库的写性能上限;扩展性差;
方案二:单点批量生成订单号的服务;
优势:批量降低了数据库的读写压力
弊端:服务单点风险;
方案三:使用UUID
优势:本地生成ID,不进行远程调用,延迟低;
弊端:无法保证趋势增长;uuid过长且建立索引效率低下;64位太长;
方案四:使用毫秒数
优势:本地生成ID,不进行远程调用,延迟低;ID为整数利于建立索引;
弊端:并发超过1000,可能会重复;
优化方案:使用LRU Cache存储最近生成的100Key,去除后先判断是否重复;进一步降低重复的可能性;但是无法根本上解决高并发下的重复;
方案五:订单号分段表示具体含义
方案描述:使用39bit表示毫秒数、4bit表示业务线、7bit表示机器等
优势:实现简单,且重复可能性很低;
弊端:订单长度过长,不利于业务使用;
方案六:使用Redis服务+毫秒数双重方案
优势:使用redis的自增序列特性,每次获取一定数量的数据(1000个),降低了每次调用Redis的开销;当Redis挂了,使用基于毫秒数的本地生成ID优化方案;
弊端:redis挂了后,订单号的重复性不可避免;
总结:
我们在设计分布式全局唯一单号的时候,不仅需要考虑生成单号的是否重复性,还要考虑生成时的性能开销、是否有容灾方案、是否便于建立索引、是否利于业务使用等。基于这些点的考虑,我们采用了方案六作为线上的唯一生成方案,并把此方案作为一个业务隔离的二方库,可以提供给不同业务方式用;