风和日丽的一天,接到产品的一个需求:直播间需要增加主播服务套餐购买的能力,每个套餐包含n次连麦服务;用户购买之后主播给用户提供连麦服务,每完成一次连麦服务扣减一次。
下单和库存扣减是经典的后端入门项目,我们这里主要针对项目中的难点以及一些注意事项进行详细阐述。首先进行简单的需求拆解,项目的主要模块包括支付、订单、服务记录等,我们将从这几个模块来针对性分析。
一、下单
首先,我们会给用户展示一个商品列表页,包含商品的简单介绍和商品id、商品价格等。用户选定某种商品之后,调起购买接口,传入商品价格和商品id。
商品价格
这里注意,虽然购买接口需要传入商品的实际价格,但实际下单时商品的价格应该以后端维护的价格为准,主要是防止有人修改接口传入的价格导致购买金额和实际金额不符。另外,一般需要校验接口传入价格和后端维护的价格是否一致,如果不一致,返回错误提示,类似“商品金额发生变化,请刷新后重试”;如果一致,走后续的下单流程。
支付&订单数据的一致性
支付系统的数据库维护在支付侧,订单数据维护在我们这一侧,属于两个不同的服务。不同于传统的一个数据库使用本地事务,要保证两个服务的数据一致性,我们先引入分布式事务的概念。
常用的分布式事务一致性解决方案包含二阶段和三阶段提交,但传统的分布式事务不适用于微服务下的事务管理,主要有以下几点原因:
1、微服务之间无法直接进行数据访问,通常通过rpc或者api进行数据访问,无法使用统一的事务管理器管理RM。
2、不同微服务使用的数据源类型可能不同,可能包含NoSql等不支持事务的数据库;
3、即使微服务的数据源都支持事务,用一个大事务将微服务管理起来,大事务维持的时间较长,影响系统性能。
我们此处的支付和订单采用业务补偿模式,业务补偿模式是指业务在调用时正常提交,当一个服务失败时,对其依赖的所有上游服务都进行业务补偿操作。这种方案可以达到最终一致性的方案,但此方案的实时性较差,但对于一般的支付场景的话可以使用。
我们这里采用的是附录2中的重试模式,对于一条链路上的操作,通过定时任务,对每个环节不断重试直至成功为止;对应到我们的流程里就是下单操作。对于需要重试的接口,需要做成幂等性。
二、库存扣减
我们上架的主播服务套餐主要是n次主播连麦服务,每次用户购买完成后,可享受n次连麦服务,这里就涉及到一个库存扣减的问题。我们需要保证主播的服务次数不多于用户的付费次数。
鉴于我们的服务qps比较小,我们这里直接使用数据库行锁+CAS来实现简单的库存扣减不超卖的能力。
数据库行锁是指在sql里指定库存>0时再进行update操作;CAS主要是指在sql里指定初始库存,以初始库存为update的查询条件,如果当前库存等于初始库存,再执行update操作。我们这里只简单使用了数据库行锁指定条件来保证,CAS的操作暂无必要。
三、主播服务能力的限制
// todo 未完待续 等待继续补充
附录:
1. 为什么每个面试官都和数据一致性过不去? https://juejin.cn/post/6844904162115878919?searchId=2023091914554426EA38C03A317997C38D
2. 聊聊 分布式系统 中的补偿机制设计问题 https://blog.csdn.net/2301_78526383/article/details/131348926
3. 基于MySQL 和 Redis 扣减库存的方法 https://juejin.cn/post/7230042979549478970?searchId=20230919202136A430C03E43F9E21E4C3D
网友评论