随着中国消费认知的不断升级,网购走近千家万户,越来越被人们所接受。淘宝、唯品会、考拉、京东、拼多多等逐渐成为我们生活的重要组成部分。
除了常规的购物下单外,这些电商平台还经常搞一些双十一活动,秒杀、大促、限时购,各种营销玩法,层出不穷。今天就来跟大家聊一聊电商技术里的库存扣减
当有很多人同时在买一件商品时(假设库存充足),每个人几乎同时下单成功,给人一种并行的感觉。但真实情况,库存只是一个数值,无论是存在mysql数据库还是redis缓存,减值时都要控制顺序,只能串行来扣减,当然为了保证安全性,会设计一些锁控制操作。
超卖
现象,引发资损交易退款
,保证库存扣减可以返还主要是依赖数据库特性来保证扣减的一致性,逻辑简单,开发部署成本很低。
依赖的数据库特性:
最上面会查询当前的剩余库存(可能不准确,但没关系,这里只是第一步粗略校验),前置校验,如果已经没有库存,前置拦截生效,减少对数据库的写操作。毕竟读操作不涉及加锁,并发性能高。数据库包含两张表:库存表、流水表。
1、库存表
字段 | 说明 |
---|---|
sku_id | 商品规格id |
leaved_amount | 剩余可购买数量 |
2、 流水表
字段 | 说明 |
---|---|
id | 主键id |
sku_id | 商品规格id |
order_detail_id | 订单明细id |
quantity_trade | 本次购买扣减的数量 |
单条商品的扣减SQL大致如下:
update inventory
set leaved_amount = leaved_amount - #{count}
where sku_id='123' and leaved_amount >= #{count}
此 SQL 采用数据库自带行锁机制,在 where 条件里判断此次购买的数量小于等于剩余的数量。在扣减服务的代码里,判断此 SQL 的返回值,如果值为 1 ,表示扣减成功。否则,返回 0 ,表示库存不足,需要回滚。
扣减成功后,需要记录扣减流水,并与订单明细记录做关联。
举个极端的例子:最新款iPhone秒杀,库存只有5件,活动期间峰值QPS预估在10W,活动结束后,上面的流水表最终只会插入5条记录,但是查询的QPS却接近 10W QPS
,读的压力非常大。
所以,数据库扣减方案第一次升级主要是针对库存前置校验
模块的优化,作为前置拦截器,承载的流量很大,如果将流量全部压到主库上,很容易把数据压垮。我们考虑把数据库架构升级。
采用了读写分离
方式,新增加了一套从库,借助mysql自带的数据同步能力。库存校验
时读取从数据库。
当然,数据同步有一定的时间延迟,从库的数据新鲜度有一定的滞后性,所以这个库存校验
结果并不一定准确,但却能拦截大部分的无效流量
。最终能不能成功购买,由主库的乐观扣减SQL
来控制,并不会影响最终扣减的准确性。大大减轻主库的查询压力。
引入了从库,确实能分摊主库很大一部分压力,但是面对秒杀这种万级QPS流量,mysql的千级TPS
根本支撑不了,需要进一步升级读取的性能。
库存校验
模块,从redis中查询剩余的库存数据。由于缓存基于内存操作,性能比数据库高出几个数量级,单台redis实例可以达到10W QPS的读性能该方案升级后,基本上解决了在前置库存校验
环节及获取库存数量接口
的性能问题,提高了系统整体性能,提供较好的用户体验。
补充说明:
如果并发量还是很高的话,可以考虑引入缓存集群
,将不同的秒杀商品sku
尽量均匀分布在多个redis节点中,从而分摊掉整体的峰值QPS压力。(参考缓存热点的解决方案)
数据库方案的优点:
ACID
特性,业务上不会出现超卖
、少买
现象数据库方案的不足:
库存主库
,性能压力会比较大。Redis采用单线程的事件模型,具有原子性
的特性。当有多个客户端给Redis发送命令时,Redis会按照接收到的顺序串行化
执行。对于还未被调度的命令,则放在队列里排队等待
。
库存扣减为了保证数据并发安全,要求原子性,而Redis
正好满足扣减类的特殊性要求,是个不错的技术选型。
下面,我们简单来看看基于Redis
如何来设计库存扣减?
首先,设计Redis的数据模型:
剩余库存(k-v结构):
key:sku_leaved_amount_{sku_id}
value:剩余的库存数值
流水(hash结构):
key:inventory_flow_{sku_id}
hash—key:订单明细id(不同业务场景的全局性id,用来做幂等控制)
hash—value:本次购买的数量
对于购物车下单,多个sku批量扣减,我们需要按单个sku循环发起Redis调用。但是多个Redis命令无法保证原子性。我们可以采用lua脚本
形式,将这些命令打包到一个脚本中,作为一个命令发送给Redis执行,从而保证了原子性。
lua 是一个类似 JavaScript、Shell 等的解释性语言,它可以完成 Redis 已有命令不支持的功能。用户在编写完 lua 脚本之后,将此脚本上传至 Redis 服务端,服务端会返回一个标识码代表此脚本。在实际执行具体请求时,将数据和此标识码发送至 Redis 即可。Redis 会和执行普通命令一样,采用单线程执行此 lua 脚本和对应数据。
Lua 脚本执行流程:
批量扣减是对单个扣减的循环调用,所以这里介绍的流程只讲单次扣减的处理步骤。
订单明细id
查询扣减流水,是否已经操作过,做幂等性校验下单购买数
做校验,只要有一个sku 数量不足,则返回失败当Redis扣减成功后,应用程序再将此次扣减异步化
保存到数据库中,持久化存储,毕竟Redis只是临时性存储,有宕机风险,会丢失数据。
缓存方案利弊分析:
Redis
缓存方案,借助了缓存的高性能
,承载更高的并发。但是没有数据库的ACID
特性,极端情况下,可能出现少卖
情况少卖
情况发生,纯缓存方案
需要做大量的对账、异常处理的设计,系统复杂度增加很多。纯缓存方案
适合一些高并发、大流量场景,但对数据准确度要求不是特别苛刻的业务场景。风险:
上述Lua脚本
把多条命令打包在一起,虽然保证了原子性,但不具备事务回滚
特性。比如,库存扣减成功了,此时Redis宕机
,扣减流水并没有插入成功,应用程序认为本次Redis调用
是失败
的,前台给用户反馈错误提示,但是已经扣减的数量不会回滚。当Redis故障修复后,再次启动,此时恢复的数据已经存在不一致了。需要结合Redis
和数据库
做数据核对check,并结合扣减服务的日志,做数据的增量修复。
上面提到的数据库方式是基于单库单表
玩法,虽然借助ACID
特性能保证数据的一致性,但是单台mysql的并发能力有限,如何提升性能?
除了纯缓存
化方案外,我们还可以考虑将库存表
进行水平拆分
,分摊洪峰压力。
假如库存表的QPS要求是1.6万,经过拆分成16张表后,如果数据分布均匀,每个物理表预计处理 1000 QPS,完全处于mysql单实例的承载范围之内。
另外拆分后,单表的数据量也会相应减少很多,假如分表前有一个亿数据,分表后每张表不到1千万,索引查询性能也会快很多。
注意:
同一次扣减业务,库存扣减和插入流水要放在同一个分库中,通过事务保证一致性,满足同时成功或同时失败。如果数据分布和业务请求足够均匀,理论上经过分库分表设计后,整个系统的吞吐量将会是线性的增长,主要取决于分表实例的数量。
还有其他的一些解决方案,这里只是提供一些思路,方案细节就不展开了
1、如果某个sku_id的库存扣减过热,单台实例支撑不了(mysql官方测评:一般单行更新的QPS在500以内),可以考虑将一个sku的大库存拆分成N份,放在不同的库中(也就是说所有子库的库存数总和才是一件sku的真实库存),由于前台的访问流量非常大,按照均分原则
,每个子库分到的流量应该差不多。上层路由时只需要在sku_id
后面拼接一个范围内的随机数
,即可找到对应的子库,有效减轻系统压力。
2、单条sku库存记录更新过热,也可以采用批量提交方式,将多次扣减累计计数,集中成一次扣减,从而实现了将串行处理变成了批处理,也可以大大减轻数据库压力。
3、引入RocketMQ
消息队列,经过前置校验后,如果有剩余库存,则把创建订单的操作封装成消息发送给MQ,订单系统从RocketMQ中以特定的频率消费,创建订单,该方案有一定的延迟性。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/wo4w4y-KG3opXvISveGz2g
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。