视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
电商系统中的下单功能的mysql架构设计
2020-11-09 09:17:20 责编:小采
文档


简单的订单业务的基本模型设计用户、商品(库存)、订单、付款,这里只考虑商品和订单,流程是下订单 -> 减库存,这两步必须同时完成,不能下了订单不减库存(超卖),或者减了库存没有生成订单(少卖)。超卖商家库存不足,消费者下了单买不到东西,体验不好;少卖商家库存积压或者需要反复修改商品信息,反复麻烦,体验也不好。

在系统初期,承接流量小,很多创业团队都是单库的模型(是的,大家都在一起。。)。这种模型带来了极大的方便,不用跨库,更没有跨节点,能够方便的利用数据库提供的事务来实现下单和减库存的原子操作,还能进行各种联表和子查询(运营MM需求再变态,我会SQL能奈我何)。但也正是这些优点,会成为流量上来后对系统进行扩展的绊脚石。联表、子查询、事务都是将多张表绑定在了一起,拆库、拆表就麻烦了。

后期系统流量逐渐升高,单库的读写性能不够,这时候会考虑将数据库进行拆库、分表。比如商品和订单分为两个集群,集群内又根据各自业务维度进行分库和分表,商品可以根据卖家维度来切分,订单一般根据买家维度切分,并且根据卖家维度做冗余。这个时候出现的问题,还是经典问题——数据一致性,数据拆分后商品和订单不在一个库里,怎么保证一致性;买家维度的订单数据怎么和卖家维度的订单数据保证一致性。有两个解决思路:

(1)分布式事务,经典的有基于2PC的实现。优点是封装得足够好后使用起来和单库虽然有区别(主要是复杂查询语句),但总体来说对业务的改动不会很大。缺点是性能太差,本来引入分布式数据库主要是为了成倍的提高性能,但因为分布式事务的引入将这个性能的提升大打折扣,很多时候这个性能是难以接受的。

(2)消息中间件,本文主角,消息中间件的一大职能就是负责各个系统间的交流,非常适合这里的商品和订单系统的同步问题。引入消息中间件后的下单流程是:用户A下订单后给消息中间件发送消息,商品系统订阅订单消息,并扣除相应的库存。

这里有几个注意点:

a、消息的传递是需要时间的,下单前查看有库存,但在并发条件下,实际减库存时可能库存不够,所以必须在库存扣减成功后才能显示订单成功,即下单后标记已下单,但用户对该状态不可见,等待商品系统减库存成功后,再通知订单系统更新状态(仍然是消息中间件的运用哦);

b、对消息的可靠性要求很高,发送消息时返回成功就要保证该消息会被投递,发送失败需要下单业务自己做回滚;

c、消息的可靠性高表示一定会有消息重复,这里需要商品系统自己做幂等,可以通过消息id来做去重,否则会少卖;

d、下单成功失败前端用户都希望尽早得到通知,所以在下单成功后需要设定一个定时消息,在一段时间后如果订单库存还没有扣除成功,这个时候应该通知用户下单失败,并且定期回补这部分多扣的库存。

引入消息中间件,可以很好的解决了分布式数据库数据同步的问题,避免了分布式事务。并且额外的好处是减少了减库存时候的并发锁争抢,性能杠杠的。

下载本文
显示全文
专题