伙伴云客服论坛»论坛 S区 S客户管理 查看内容

0 评论

0 收藏

分享

订单系统设计

我们每天都在使用下单。但是订单是如何生成的呢,又是如何推送到下游的各个系统的?

订单系统设计-1.jpg


最重要的保证:

订单系统的低延迟,高可用的,不丢单问题。
万级和千万级架构是不一样的。
思路:
首先,设计一个简单的订单系统。
分析哪几个环节会丢单。
日万级如何优化。
日千万如何晋级改造。
简单系统:

订单系统设计-2.jpg

只要前台和后台,前台结算页提供用户去结算。当后台收到前台用户点击去结算的操作时,就会处置下单效劳。
起初,订单会被处置到后台的数据库中,然后异构数据到缓存中。以此提供用户在我的订单中停止订单查询。
当用户支付完成后,收银台发送消息给下单的效劳,停止数据库和缓存中的订单状态的修改。这样一个简单的订单系统就完成了。
真实的订单系统会有更多的业务,使得系统更加复杂。前面只是一个示例。
接下来,我们再看看这个系统中,哪些环节可能会呈现丢单的问题。其实如今后台系统研发架构已经很成熟了。但是假设系统挂了,就是挂了。
所以关键点应该聚焦在写数据库,和接收和发送订单消息的环节上。
总结为3步:

1.

关键逻辑不要使用读写分别的查询方式,防止从库同步延迟形成订单查询异常。
比如

订单系统设计-3.jpg


创建订单后,要创建支付单,但是在反查订单的时候由于主从延迟,没查到订单信息,这就可能会形成创建支付单的失败。
2

关键逻辑也不要使用缓存来停止订单的查询

订单系统设计-4.jpg

这样做,同时是为了防止因为缓存延迟形成订单反查失败。


订单补偿不要粗暴的使用消息队列的方式,防止中间件引发的订单丧失。
订单系统设计-5.jpg


比如在订单状态的修改时,假设处置失败,就将这个订单信息插入到消息队列中,重新消费,以此来完成订单的补偿。
这种方式在发送和接收消息时,有可能存在丢消息的可能。


接收消息处置失败时,一定要让消息重试,防止丧失。尤其注意return,continue等关键字。
比如:

订单系统设计-6.jpg

比如一次消费多条记录,一条一条的处置,假设修改状态胜利,就继续处置下一条。假设修改失败,可能会因为return或者continue关键字将其余的消息都丧失掉了。
日万级

那么我们要如何设计一个支持日万级的订单系统呢?
考虑到前面丢单的问题,以及系统的稳定性和可用性,我们要如何停止系统的重构和优化。
之前的系统是很容易支持日万级的订单系统的。
注意以下几点:
1.写数据库的时候,数据库事务的粒度不要太大,防止锁表,关注慢sql。
比如最不要犯的错误就是在数据库事务里同时更新其他数据源,或发送消息到消息中。

订单系统设计-7.jpg

这不只不能保证数据的一致性,还会把数据库的连接耗尽。
2.关注数据异构的性能和稳定性,尤其在网络抖动的情况下,可能会影响用户的体验。
3.关注订单系统的幂等性,防止呈现计费错误,影响后续操作流程。
根本满足订单日万级别订单系统了。
日千万级订单系统:

关键在于一个量,由于量的增大,形成系统负载的过重,导致效劳最终宕机。
哪些是系统的瓶颈:
过重依赖于数据库:

订单系统设计-8.jpg


比如修改订单状态的时候,就需要反查数据库,并停止订单状态的更新,这些操作在高并发场景的时候,会形成数据库资源的抢占,从而影响性能的稳定性。
为了防止数据不一致,恳求访问主要集中在主库上,这样主库压力就会很大。因而就需要分库分表的架构:
订单系统设计-9.jpg

下单效劳也为此也必需改造,支持分库分表的设计,但由于热点数据的存在,可能导致数据库倾斜的问题。引发提早的数据库扩容问题。
由于下单效劳耦合过重,使得即便是多集群的部署架构,也很难实现快速的处置业务响应。更何况,不同业务的订单处置的流程还不一样。使得系统的维护性也越来越差。
比如创建订单的时候由于业务不同
订单系统设计-10.jpg

数码,3c图书等订单包含的信息是不一样的。这就需要特殊处置。
这种特殊处置与系统订单耦合在一起,系统自然就会变得越来越慢。
最后由于数据库存储量的增大,还会导致数据异构性能的直线下降。以及缓存存储容量的不时扩大,这都会极大的影响查询性能,而且还可能呈现业务件的互相影响等问题。
前面的问题:
下单效劳处置接单慢
数据库压力大
数据异构延迟高
缓存数据质量差
这些如何处置呢?
为了应对千万级的订单量,需要将订单效劳停止拆分。
使用单独的接单效劳处置接单,使用订单引擎订单管道处置订单业务逻辑。
双写和数据补偿的方式处置缓存,使用缓存过期的方式控制数据量。
订单系统设计-11.jpg


接下来分析一下实现方案:
订单系统设计-12.jpg

当用户在结算页点击提交订单后,接单效劳会将同一个事务里,将订单插入接单库。将收任务插入到任务库。再由订单引擎停止任务调度。
什么是任务?
任务就是执行订单的操作步骤,比如写订单缓存。减库存,发送订单通知等,,以及前面提到不同的特殊业务流程。这些都是一个个的任务。
我们通过将整个订单处置流程,分解成一个个的任务。逐个单独处置。来应对日千万级别的订单处置压力。其中接单库为多台数据库。
订单系统设计-13.jpg

通过随机的方式写入,之所以没有采用Hash等算法,其原因在于扩展才干更具灵敏性。当遇到流量洪峰降临时,新增数台数据库,对写入逻辑是无感的。
接单库采用一主多从的部署架构,当一台机器故障,可以通过快速切换主从,或者摘除故障机等手腕停止修复。
而其中任务库由订单引擎驱动执行,任务通过订单引擎的效劳编排才干,生成任务队列,首任务执行胜利之后,会插入第二个任务,或者同时插入第三个和第四个任务。

订单系统设计-14.jpg

假设插入任务失败,订单引擎会重新执行当前任务。执行胜利之后,会继续执行插入操作。这里就需要每个任务的业务处置都需要保证幂等性。
方才说的是任务的创建方式,接下来说说任务的线程调度方式:
任务使用多线程的异步方式停止调度。

订单系统设计-15.jpg


并且根据配置:
选择串行执行还是并行执行,有一个点不晓得你有注意到:
前面说了任务线程调度执行,那么假设任务执行失败,订单引擎是如何执行失败的任务呢?
这就是通过任务状态机来实现。
任务状态机就仿佛一个系统的守护线程。任务状态机通过识别任务的状态,来识别每个任务是执行完成,还是执行失败。并根据状态来停止任务调度,并且对屡次执行失败的任务,重试调度的频次也会逐步减弱。当超越一定重试次数之后,
就会告警通知人工干预。

订单系统设计-16.jpg

其实订单引擎真正执行调度远程效劳的,并非订单引擎来完成的,而是由订单引擎调度订单管道,订单管道去调度远程真是的效劳来执行。其原因在于引擎自身就是多线程的设计架构,对线程占用就比较高。而远程调度会注册很多的效劳。
效劳调度也会启动很多多线程去执行。假设共同部署在一个系统里。就会呈现线程数过多。形成cpu飙升的情况。
订单系统设计-17.jpg


接下来我们再说一下订单缓存的实现战略:
接单效劳处置完一些业务逻辑后,最后调用下单效劳提交订单到订单中心。而在此之前,为了保证订单的及时性,在插入订单和任务之后。接单效劳会先将订单通过接口写入到订单中心的缓存中,以便支持用户在支付之后,在我的订单列表中能立即查询到我的订单。
订单系统设计-18.jpg


总体来说,订单中心接到下单效劳之后,会将订单落库,便同步到缓存中,在后续订单中心接收到台账的消息后,也会同时更新数据库和缓存,将订单状态更新完成。
千万级架构整体概括的讲一下:

订单系统设计-19.jpg

用户在结算页点击结算,结算页调用后台的接单效劳,接单效劳收到下单恳求之后,会负责接单,将订单插入到接单库,同时在一个事务里,将首任务插入到任务库,并通知调度器订单引擎开端执行任务。订单引擎根据任务编号,依次执行任务调度,并更新任务状态。并由任务状态机停止任务校验补偿处置。订单引擎通过调度订单管道,实现真实的效劳远程调度。订单管道恳求效劳之后,将处置结果返回给任务引擎。
最后,订单中心会在接单效劳创建订单时,异步地写一份订单缓存到订单中心,然后通过数据异构的方式,再次写一份数据在订单缓存中。
整个流程如何保证:

高可用和高性能
整个订单核心流程 同步执行,只要少数任务比如发送订单通知给下游,系统是采用消息异步的方式执行,以此来保证订单流程的高性能。而整个处置流程基于订单引擎的调度,通过效劳流程编排,确定一个订单的执行步骤,并保证每个环节正确的执行,防止订单丢单,卡单等已成任务的呈现,进而保证订单流程的高可用。
交易平台不时是各个公司的核心流程之一,涉及到数据流和资金流的流转。
秒杀场景下 细节还是有很多不同的。
以减库存为例:
日万级的秒杀系统,采用数据库减库存的方式就可以了。
日千万秒杀系统,更复杂一些。
记录

基于极客时间视频整理。

回复

举报 使用道具

相关帖子
全部回复
暂无回帖,快来参与回复吧
本版积分规则 高级模式
B Color Image Link Quote Code Smilies

做自己的女王ァ
注册会员
主题 10
回复 17
粉丝 0
|网站地图
快速回复 返回顶部 返回列表