订单编号生成规则
订单号生成是系统设计中常见的问题,特别是在分布式系统中,生成唯一性、高效性的订单号是非常重要的。
(1)自增数字序列
使用数据库的自增主键、redis的INCR 命令生成序列化。
(2)时间戳+随机数
将年月日时分秒和一定范围内的随机数组合起来。有重复的风险。
(3)订单类型+日期+序号
将订单类型(例如"01"表示普通订单,"02"表示VIP订单等)、日期和序号组合起来。加上订单类型的好处是方便客户服务,根据订单号就可以知道订单的类型。
(4)分布式唯一ID生成器
使用分布式唯一ID生成器(例如Snowflake算法)生成全局唯一的ID作为订单号。Snowflake 算法根据机器ID、时间戳、序号等因素生成,保证全局唯一性,它的优势在于生成的 ID 具有趋势递增、唯一性、高效性等特点.
1. 为什么需要订单编号
订单表已经有一个唯一的订单id了,为什么还需要一个唯一的订单编号呢?订单id已经可以唯一标识一个订单。
在订单表中,订单ID 和 订单编号 都可以唯一标识一个订单,但它们存在的意义和用途有所不同,因此在实际开发中通常会同时存在这两个字段。以下是常见的原因:
1.1 技术层面 vs 业务层面
- 订单ID:通常是数据库的主键,用于技术层面上的唯一标识,常常是自增的整数类型或者使用如 Snowflake 算法生成的唯一ID。它是系统内部用于快速查询和关联数据的标识符,不对用户显示,也不用于业务流程。
- 订单编号:则是面向业务的唯一标识,用于在外部系统、用户、客服人员之间传递和沟通。它通常遵循一定的业务逻辑,如包含时间戳、业务类型、随机数等信息。
1.2 可读性
- 订单ID 一般是技术生成的长整型数字或类似的随机字符串,缺乏人类可读性,不适合客户或运营人员使用。
- 订单编号 则可以根据业务需求进行定制,如时间戳、订单类型等信息,使其更具可读性。
1.3 防止泄漏系统内部逻辑
- 订单ID 有时是数据库自增主键,暴露给用户或外部系统可能导致系统的设计逻辑泄漏,甚至可能引发安全问题(如通过观察ID的自增模式进行攻击)。
- 订单编号 可以通过自定义的生成规则,使外部无法猜测出系统内部的逻辑和订单的具体数量,增加系统安全性。
1.4 不同系统间的关联
在一个复杂的业务系统中,订单号可能需要与其他子系统(例如物流、支付、CRM系统)进行对接。为了更好地在不同系统之间传递和识别订单,通常会设计一个业务层面的订单编号,这样能够确保订单在跨系统操作时的唯一性和一致性。
1.5 排错与客服支持
在进行客服支持时,使用自增的 订单ID 进行沟通不太直观,而订单编号可以包含更多业务信息(如日期、订单类型等),更有助于客服人员快速定位订单,且便于客户理解和记忆。
2. 订单编号生成规则
2.1 自增数字序列
2.1.1 实现方式
- 通过数据库的自增主键来生成订单号。
- 使用 Redis 的
INCR
命令来生成唯一的自增序列。
2.1.2 优点
- 简单易用:实现逻辑简单,依赖于数据库或 Redis 的自增特性。
- 订单号有序:生成的订单号按顺序递增,易于排序和管理。
2.1.3 缺点
- 单点瓶颈:如果依赖数据库的自增主键,数据库成为单点瓶颈,可能无法应对高并发场景。
- 不适用于分布式:在分布式系统中,由于多台服务器并发处理,依赖单个数据库或 Redis 节点来生成自增序列可能导致性能瓶颈或冲突。
2.1.4 使用场景
- 适用于小型项目或单一服务系统,订单量不大且没有分布式需求的场景。
2.2 时间戳 + 随机数
2.2.1 实现方式
- 将当前时间戳(如年月日时分秒)与一定范围内的随机数组合,生成订单号。
2.2.2 优点
- 实现简单:生成逻辑易于实现,不需要依赖外部系统。
- 包含时间信息:通过时间戳可以轻松获取订单的生成时间。
2.2.3 缺点
- 重复风险:由于随机数范围有限,存在生成重复订单号的风险,特别是在高并发场景下。
- 订单号较长:为了降低重复风险,随机数位数可能需要较多,导致订单号长度较长。
2.2.4 使用场景
- 适用于订单量相对较小的场景,或者系统没有严格的分布式需求时可以使用。
2.3 订单类型 + 日期 + 序号
2.3.1 实现方式
- 将订单的类型、日期(通常是年月日)、序号等元素组合生成订单号。
- 订单类型:如"01"表示普通订单,"02"表示VIP订单等。
- 序号:可以是每日从1开始自增的序号,也可以是数据库或 Redis 自增的序列。
2.3.2 优点
- 可读性好:通过订单号可以直接识别订单类型和生成日期,方便系统管理和客户服务。
- 灵活性高:序号部分可以根据不同的订单类型或日期进行自增,不同类型的订单可以独立生成序列。
2.3.3 缺点
- 重复风险:如果序号设计不合理,可能在并发场景下出现重复订单号的风险(例如相同订单类型和日期)。
- 依赖外部存储:序号部分通常依赖于数据库或 Redis 来保证唯一性,存在性能瓶颈。
2.3.4 使用场景
- 适用于订单量较大、订单类型较多的场景,方便通过订单号直接获取订单的基本信息。
2.4 分布式唯一ID生成器(如 Snowflake 算法)
2.4.1 实现方式
- 使用分布式唯一ID生成算法(如 Snowflake 算法)生成全局唯一的订单号。Snowflake 是 Twitter 开发的一种算法,它基于时间戳、机器ID、序列号来生成唯一ID。
2.4.2 优点
- 全局唯一:生成的订单号保证在分布式系统中的唯一性,无需依赖数据库或其他外部存储。
- 高效性:算法可以在短时间内生成大量的唯一ID,性能高效。
- 趋势递增:生成的ID具有时间上的趋势递增性,易于排序。
2.4.3 缺点
- 实现复杂:需要部署和维护分布式ID生成服务,或者集成第三方工具,增加了系统的复杂性。
- 不可读性:生成的ID通常是较长的数字,无法通过订单号直接获取有用的订单信息。
2.4.4 使用场景
- 适用于高并发、大规模分布式系统,需要保证订单号全局唯一性且性能要求较高的场景。
3. 总结
- 小型系统、单点系统:使用自增序列(数据库或 Redis
INCR
)即可,简单易实现,但需要注意系统扩展性和性能瓶颈。 - 需要包含时间信息的订单号:可以使用时间戳 + 随机数,通过随机数降低重复风险,适合小型系统。
- 订单类型明确的系统:可以使用订单类型 + 日期 + 序号,不仅保证唯一性,还能通过订单号获取有用信息,适合有不同订单类型的系统。
- 高并发分布式系统:推荐使用分布式唯一ID生成器(如 Snowflake 算法),高效、唯一、支持分布式,是大型系统和高并发系统的首选。