中间件(一):订单系统整体架构

x33g5p2x  于2021-09-28 转载在 其他  
字(7.4k)|赞(0)|评价(0)|浏览(631)

1、订单系统架构

2、订单系统整体架构和流程

现在每日几十万订单,日高峰QPS:2000,大促活动QPS:10000。

目前注册用户几千万,每日活跃用户一两百万,订单数量每日几十万,随着发展很快达到订单量每日百万,不过现在大促都达到单日百万订单。

系统压力来自两方面:1、日益增长的数据量;2、大促活动时每秒上万访问压力。

随着数据库中的订单数据越来越多,数据库的读写性能就会越来越差,尤其在大促活动高峰期的时候,数据库访问压力剧增,读写性能会进一步下降,经常出现请求过慢,请求超时等问题。

订单系统必须得有一个下单模块负责让用户进行下订单。其次当订单创建好之后,就必须要跳转到第三方支付的界面上去,让用户尽快支付。如果用户支付成功了,然后就会回调订单系统的接口。         接着订单系统会去做一些事情,比如扣减商品的库存,更新订单的状态,给用户发券、发货红包或者积分,给用户发送Push去推送订已经支付等待出库的通知。 接着用户就可以从订单系统的查询模块去检索自己的订单,此时可以做一些非核心的业务流程 比较常见的有:选择对商品进行退货、查询订单的物流状态、或者之前没来得及支付现在对订单进行支付,等等。 最后订单系统需要提供一个大促模块,专门去抗双11、双12、618、秒杀活动等特殊大促活动时的瞬时超高并发,这个必须跟正常的下 单流程区分开来。 另外还可能有其他兄弟团队要来获取订单系统的数据,比如大数据团队。 而当前咱们的APP大致是千万注册用户,百万日活,每日几十万订单量,每天高峰期访问每秒两三千的QPS。

3、系统压力

高峰期压力:系统每天高峰期大概会有2000左右的QPS,也就是每秒会有2000左右的请求过来,这就是当前系统的一个最大压力。

4、分析用户行为

像对一个系统的工程师来说,确实是第一 件应该了解的事情,也就是你的APP用户的生活习惯和APP的使用习惯。 这些用户的使用习惯直接决定了他们使用我们APP的频率、时间段和时长,一般每隔几天用一次们的APP?每次使用一般在什么时间 段?每次使用多长时间?

5、推算系统负载

根据用户生活习惯,结合统计数据推算出工作负载。App基本上80%的用户都习惯于在晚上六点过后到凌晨十一点这几个小时使用,这个刚好是大家下班的时间,便于大家购物。所以在这几个小时内,可以认为有80万左右的用户会使用APP。

      对APP,用户大量的浏览商品,搜索商品,然后才会下订单和支付订单,所以用户一般会对APP的界面执行几十次到上百次的点击。 但是大部分点击都是跟一些商品系统、评论系统进行的交互,用户主要是查看商品,查看一些评价,还不是针对订单系统的。
        因此对我们订单系统而言,主要的访问量就是下订单以及对订单的检索、查询,少量的退款等操作。 我们现在每天大概是三五十万个订单,也就对应了百万次下单操作和一些订单查询等操作。看着百万次针对订单系统的请求似乎很多,但是如果均摊到5个小时中呢?每秒钟大概只有几十次请求而已!

       订单系统下单最顶点的高峰时段每秒会有超过2000的请求,这就是订单系统的最高负载。

现在线上的订单系统一共部署了8台机器,每台机器的配置是4核8G,这是互联网公司的标准配置,当然也有不少系统是用2核4G的机器部署的,那也是标准配置。因此高峰期每台机器的请求大概是每秒200~300之间。
        8台订单系统部署的服务器都是连接一台数据库服务器的,数据库服务器的配置是16核32G,而且是SSD固态硬盘的,用的是比较高配置比较贵的机器,因此性能会更好一些。

现在线上这样的一个机器部署情况,在高峰期每秒2000以上请求的情况下是很轻松可以抗住的因为4核8G的机器一般每秒钟抗几百请求都没问题,现在才每秒两三百请求,CPU资源使用率都不超过50%。可以说8台4核8G的机器,每台机器每秒高峰期两三百请求是很轻松的。
        然后数据库服务器因为用的是16核32G的配置,因此之前压测的时候知道他即使每秒上万请求也能做到,只不过那个已经是他的极限了,会导致数据库服务器的CPU、磁盘、网络、IO、内存的使用率几乎达到极限。但是一般来说在每秒四五千的请求的话,这样的数据库服务器是没什么问题的,何况经过线上监控统计,现在数据库服务器在高峰期的每秒请求量也就是三四千的样子,因此基本上还没什么大问题。

6、目前系统最明显的技术问题

这个步骤8那里的多个子步骤全部执行完毕,加起来大概需要1秒~2秒的时间
        有时候在高峰期负载压力很高的时候,如果数据库的负载较高,会导致数据库服务器的磁盘、IO、CPU的负载都很高,会导致数据库上执行的SQL语句性能有所下降。 因此在高峰期的时候,有的时候甚至需要几秒钟的时间完成上述几个步骤

先针对步骤8里的子步骤过多,速度过慢,让用户支付之后等待时间过长的问题,就是订单系统第一个亟需解决的问题

 7、第三方系统

订单支付时的核心流程图

在订单支付的时候,大部分核心步骤,其实都是在自己公司的系统里完成的,比如你更新订单的状态,是在自己公司的订单系统内部完 成的;你扣减库存,是找自己公司内部的库存系统完成的;你在增加积分的时候,是找自己公司内部的积分系统完成的;你在派发优惠 券、红包的时候,是找自己公司内部的营销系统完成的。 

发货:一般电商公司内部都会有自己的仓储系统,管理各种仓库和商品的发货,通常来说会选择去找一个距离你用户最近的一个仓库,然后从 里面调度一些商品进行发货,在发货的时候还需要调用第三方物流公司的系统,通知物流公司去仓库里取货发货。
对于物流公司而言,必然会由自己的物流系统收到货运通知之后,自动通知自己的快递员或者运输队到对方仓库里取货,然后去派发货

物给购买商品的用户。

8、系统耦合

订单系统跟促销系统是强耦合的。因为促销系统任何一点接口修改,都会牵扯你围着他转,去配合他, 耗费你们订单团队的人力和时间,说明你们两个系统耦合在一起了。  

订单系统要调用仓储系统的接口去发货,仓储系统在接到订单系统的调动之后,又要同时去调用第三方物流系统去生成物流单,通知人 家去取货。
        所以在上图的流程中,必须要等到第三方物流系统返回确认信息之后,仓储系统才能返回结果,订单系统才能结束对仓储系统的调用

跟第三方系统的交互往往是最麻烦的。

假如你调用他的接口,结果他的接口有时候速度很快只要20ms,有时候速度很慢要200ms,有时候调用很正常,有时候偶尔会调用失败几次,你怎么办?第三方系统,永远是不能完全信任的,你的系统跟第三方系统耦合在一起的痛苦:对方不可控,导致你的系统的性能和稳定性也不可控。

9、大数据

一个个面向互联网的电商APP,要服务的是100万用户。所以每天如果有100万用户来访问你的APP,积累下来的一些浏览行为、访问行为、交易行为都是各种数据,这个数据量很大,所以你****可以称之为“大数据”

大数据团队每天要负责的事情,说白了就是去尽可能的搜集每天100万用户在你的APP上的各种行为数据。
        比如用户搜索了什么东西,点击了什么东西,评论了什么东西。还有就是搜集用户在APP里的交易数据,比如最核心的一种,就是我们的订单数据。 订单数据就直观的代表了用户在APP里的所有的交易。

         然后大数据团队搜集过来大量的数据之后,就形成了所谓的“大数据”。接着他用这些大数据可以计算出很多东西。 最常见的就是数据报表,比如说用户行为报表,订单分析报表,等等。这些数据报表都是提供给老板来看的。

10、几百行的大SQL直接查线上库的危害

我们的订单数据库里的数据量是很大的,最开始每天APP就几百个订单,到现在每天小几十万订单,我们每个月都新增千万级订单数据。 现在表里已经有的订单都有千万以上了,

      就以我们现在数据库里千万级数据来说,每次老板要看交易报表的时候,数据报表系统运行一个几百行的大SQL到我们库里,这种级别的SQL在这种量级下,快则三五秒,慢则几十秒。

这种几百行的大SQL执行是非常消耗CPU的,对磁盘IO的负载也是很重的,尤其是每天不止老板一个人要看数据报 表,这个报表系统是对公司开放的,包括副总,高管,中层经理,运营,产品经理,全公司几十个人都会看这些报表。
        每次当有几十个几百行的大SQL同时运行在我们订单数据库里的时候,都会导致我们的数据库CPU负载很高,磁盘IO负载很高!一旦我们的数据库负载很高,直接会导致我们的订单系统执行的一些增删改查的操作性能大幅度下降!

11、订单系统的问题

11.1、支付前----用户未支付

        首先是在一个订单支付之前,用户一旦下了订单,就在订单数据看创建订单状态为未支付,就会锁定对应的商品库存,别人就不能买了。然后万 一用户一直没支付,还得一个后台线程不停的扫描数据库里的待支付订单,去自动取消长时间没支付的订单。

但是如果这种订单有几十万甚至几百万之多呢?不停的让后台线程扫描,性能很差,也非常的不方便。

11.2、支付后----复杂操作

支付订单之后要经历更新订单状态、扣减库存、发送Push推送、增加积分、派发优惠券和红白、通知仓储系统发货,等等过程。 这一系列的过程要是都执行下来,那性能真是太差了!
而且不光是这样,在这个调用链路中,订单系统还跟仓储系统耦合在了一起,仓储系统是跟第三方物流系统耦合在一起的。 这种耦合,就导致了第三方物流系统如果性能出现抖动,会导致我们的核心链路的性能也会抖动,第三方物流系统的接口如果调用失 败,会导致我们的核心链路也出现部分失败。

11.3、支付后 ---- 退款/退款失败

订单支付过后,如果用户要退款,这个时候涉及到自己公司内部系统的一系列回滚,比如更新订单状态、增加库存、收回优惠券和红包、减少积分,通知取消发货,等等。
而且此时还得调用第三方支付系统进行退款,但是万一在这里退款失败了呢?那用户就拿不到自己的钱了,所以还得

11.4、大数据团队压力

如果有几十个人同时看报表,几十个几百行的大SQL运行在订单数据库里,瞬间会导致我们的CPU和磁盘IO负载过高,导致我们订单系统自己的CRUD操作的性能下降

 11.5、双11压力

平时晚上的高峰使用期,最顶峰的时候大概是每秒2000左右的请求压力到订单系统。

如果用户每秒会发起2000个请求到我们的订单系统的各类接口,包括下单接口、退款接口、查询接口等等,那么你觉得我们的订单系统每秒会执行多少条SQL在订单数据库上?

比如每秒订单系统的各类接口被调用2000次,平均每个接口会执行多少次数据库操作?
一般你可以认为平均每个接口会执行2~3次的数据库操作。 一般一个接口根据业务复杂度的不同,有的接口可能处理一个请求要执行五六次数据库操作,有的接口可能是1次数据库操作+两三个

其他系统的接口调用(比如库存系统、营销系统)。

结合线上数据库的可视化监控界面,基本可以知道,平均每次订单系统的接口调用,会执行2次数据库操作,我 们观察数据库的监控界面,在最高峰的时候,每秒大概是有4000左右的请求

线上数据库是部署了一台服务器的,用的是高配置的16核32G以及SSD固态硬盘的机器,因此观察线上数据库的情况,在每秒4000请求的时候,虽然CPU、磁盘、IO等负载较高,但是基本还在承受范围内。

去年双11的时候,公司也搞了一场活动,当时公司用户量很少,那年双11就几十万用户参与 了,但是就这样,在双11购物最高峰的时候,也达到了每秒几千的QPS

很多顶级大电商公司的系统,可能会在双11购物最高潮的时候,系统QPS达到百万级别,也就是每秒百万请求。

Version:0.9 StartHTML:0000000105 EndHTML:0000000373 StartFragment:0000000141 EndFragment:0000000333

11.6、今年的双11活动对系统压力会有多大?

公司现在积累的注册用户已经千万级了,平时的日活用户都百万级, 今年的双11参与活动的用户预计有可能会达到两三百万。如果有200万用户参与双11活动,预计有可能今年双11最高峰的时候,会达到每秒至少1万的QPS。光是系统被请求的QPS就会达到1万以上,那么系统请求数据库的QPS就会达到2万以上。仅仅凭借我们目前的数据库性能,是无论如何扛不住每秒2万请求的。

总结 

12、系统核心链路

所谓核心链路指的是对你的系统进行的数据更新的操作,这才是核心链路,因为查询操作一般来说不涉及复杂的业务逻辑,主要是对数据的展示。
        你的系统的核心链路分析一下,有哪些步骤,这些步骤各自的性能如何,综合起来让你的核心链路的性能如何?在这里是否有改进的 空间?

13、解决方法----消息中间件

13.1、同步调用

用户发起一个请求,系统A收到请求,接着系统A必须立马去调用系统B,直到系统B返回了,系统A 才能返回结果给用户,这种模式其实就是所谓的“同步调用”。
这个同步的意思,就是各个系统的联动都是同步依次进行的,一个系统先动,然后立马带动另外一个系统一起动,最后大家依次干完了以后,再返回结果

13.2、异步调用

因为系统A要做的事 情只是接收请求,发送消息到MQ,然后就返回结果给用户,系统B他就不管了。 然后系统B根据自己的情况,可能会在系统A投递消息到MQ之后的1秒内,也可能是1分钟之后,也可能是1小时之后,多长时间都有可 能,反正不管是多长时间后,系统B肯定会从MQ里获取到一条属于自己的消息。 然后获取到消息之后,根据消息的指示再完成自己的工作。 

所谓异步调用,意思就是系统A先干了自己的工作,然后想办法去通知了系统B。 但是系统B什么时候收到通知?什么时候去干自己的工作?这个系统A不管,不想管,也没法管,跟他就没关系了。 但是最终在正常下,系统B总会获取到这个通知,然后干自己该干的事儿。

13.3、消息中间件作用

消息中间件,其实就是一种系统,他自己也是独立部署的,然后让我们的两个系统之间通过发
消息和收消息,来进行异步的调用,而不是仅仅局限于同步调用。

作用:包括异步化提升性能,降低系统耦合,流量削峰,等等

13.3.1、异步

比现在假设系统A要调用系统B干一个事儿,然后系统A先执行一些操作,需要耗费20ms,接着系统B执行一些操作要耗费

200ms,总共就要耗费220ms。

系统A干完自己的事情,就20ms,然后发送一个消息到MQ,就5ms,然后就直接返回结果给用户了。 也就是说,用户仅仅等待25ms就收到了结果。 然后系统B从MQ里获取消息,接着花费200ms去执行,但是这个200ms就跟用户没关系了,用户早就收到结果了,他也不关心你花
200ms还是2s去干自己的事。

消息中间件居然可以用来优化系统性能。

13.3.2、解耦

系统A同步调用系统B,会产生耦合。如果系统B要是突然出现故障了,是不是会导致系统A调用系统B感知到这个故障?因为系统A调用系统B肯定是返回异常的,此时系统A是不是也得返回异常给用户?而且系统A是不是还要去处理这个异常?
        一切都是因为系统A和系统B通过同步调用的模式耦合在了一起,所以一旦系统B出现故障,很可能会影响系统A也有故障而且系统A还得去关心系统B的故障,去处理对应的异常,

系统B故障,就成了 他自己的事了,他要自己等故障恢复了,继续去完成他要干的活儿,此时就对系统A没任何影响了。
因为通过引入MQ,两个系统实现了异步化调用,也就实现了解耦,系统A并没有跟系统B耦合,所以互相之

间并没有任何影响。

13.3.3、流量削峰

        假设系统A是不操作数据库的,因此只要多部署几台机器,就可以抗下每秒1万的请求,比如部署个20台机器,就可以轻松抗下每秒上万请求。

        然后系统B是要操作一台数据库服务器的,那台数据库的上限是接收每秒6000请求,那么系统B无论部署多少台机器都没用,因为他依赖的数据库最多只能接收每秒6000请求。
        系统A会瞬间把1万QPS转发给系统B,假设你系统B也部署20台机器,系统B自己可以抗住1万QPS,那么数据库呢?

        数据库是抗不下来1万QPS的,此时系统B如果对数据库发起1万QPS的请求,一定会瞬间压垮数据

MQ这个技术抗高并发的能力远远高于数据库,同样的机器配置下,如果数据库可以
抗每秒6000请求,MQ至少可以抗每秒几万请求。

为什么呢?因为数据库复杂啊,他要能够支持你执行复杂的SQL语句,支持事务等复杂的机制,支持你对数据进行增删改查,听着简 单,其实是很复杂的!所以一般数据库单服务器也就支撑每秒几千的请求。

        但是MQ就不一样了,他的核心功能就是让你发消息给他,再让别人从他这里获取消息,这个就简单的多了,所以同等机器配置下, MQ一般都能抗几万并发请求。

        所以只要你引入一个MQ,那么就可以让系统A把每秒1万请求都作为消息直接发送到MQ里,MQ可以轻松抗下来这每秒1万请求

系统b只要慢慢的从MQ里获取消息然后执行数据库读写操作即可,这个获取消息的速度是系统B自己可以控制的,所以系统B完 全可以用一个比较低的速率获取消息然后写入数据库,保证对数据库的QPS不要超过他的极限值6000。
        这个时候因为系统A发送消息到MQ很快,系统B从MQ消费消息很慢,所以MQ里自然会积压一些消息 不过不要紧,MQ一般都是基于磁盘来存储消息的,所以适当积压一些消息是可以的。

        当系统A的高峰过去,每秒可能就恢复到1000 QPS了,此时系统b还是以每秒6000QPS的速度获取消息写入数据库,那么自然MQ里积 压的消息就会慢慢被消化掉了。
MQ进行流量削峰的效果,系统A发送过来的每秒1万请求是一个流量洪峰,然后MQ直接给扛下来了,都存储自己本地磁****盘,这个过程就是流量削峰的过程,瞬间把一个洪峰给削下来了,让系统B后续慢慢获取消息来处理。

14、MQ解决梳理

        支付订单流程中步骤过多,导致性能很差。这个问题可以用MQ来解决,让订单系统仅仅完成最核心的一些步骤和调用,然后发送消息到MQ,比如仓储系统之类的就可以从MQ里获取消息,然后慢慢的执行一些很耗时的步骤。

        还有比如订单系统在退款的时候,可能会遇到第三方支付系统退款失败的问题,从而影响整个退款流程的失败,这个问题也可以用MQ解决。可以让订单系统在退款的时候完成公司内部各个系统的流程,然后发送消息到MQ,由一个专门的服务去负责调用第三方支付系统,处理可能出现的失败。
        在双11大促活动的时候,也可以让瞬间涌入的大量下单请求到MQ里去排队,然后让订单系统在后台慢慢的获取订单,以数据库可以接受的速率完成操作,避免瞬间请求量过大击垮数据库。

相关文章