【万字长文】说说电商系统常见的 9 个大坑,人麻了……

发表于 2年以前  | 总阅读数:362 次

做为一名程序员,发展方向大致可以分为两个方面:一个是业务架构,一个是技术架构(中间件方向)。

业务架构,取其核心关键词,主要是围绕这不同的业务场景、业务规则,完成业务系统的落地建设,为用户提供在线化的信息服务。

既然说到业务,那方向可就多了去了,如:出行、外卖、充电宝、O2O、内容、社交、生鲜、电商,不同的业务有不同的特点。

面对这么多的业务域,有没有通用技术经验可以抽取,让我们可以以一应百

这里,首推电商业务,电商系统的复杂性很高,对高并发高性能高可用高扩展,等方面要求很高。你在其他业务中可能遇到的问题,在电商系统中基本都会遇到。

作为开发,希望自己成为某几个业务领域的技术专家,最好能先精通电商领域,有很强的借鉴意义。对于你后续拓展熟悉其他业务领域的个性化玩法有很大帮助。

那么,电商领域的技术架构有哪些常见问题?

一、避免重复下单

用户快速点了两次 “提交订单” 按钮,浏览器会向后端发送两条创建订单的请求,最终会创建两条一模一样的订单。

解决方案:

解决方案就是采用幂等机制,多次请求和一次请求产生的效果是一样的。

方案一:

利用数据库自身特性 “主键唯一约束”,在插入订单记录时,带上主键值,如果订单重复,记录插入会失败。

操作过程:

  • 引入一个服务,用于生成一个“全局唯一的订单号”
  • 进入创建订单页面时,前端请求该服务,预生成订单ID
  • 提交订单时,请求参数除了业务参数外,还要带上这个预生成订单ID

方案二:

前端通过js脚本控制,无法解决用户刷新提交的请求。另外也无法解决恶意提交。

不建议采用该方案,如果想用,也只是作为一个补充方案。

方案三:

前后约定附加参数校验。

当用户点击购买按钮时,渲染下单页面,展示商品、收货地址、运费、价格等信息,同时页面会埋上Token信息,用户提交订单时,后端业务逻辑会校验token,有且匹配才认为是合理请求。

注意:同一个 Token 只能用一次,用完后立马失效掉。

<form action="/add-name-v2" method="post">
    {% csrf_token %}
    <input type="text" name="name">
    <input type="submit" value="提交">
</form>

补充:

关于幂等的处理,更多解决方案可以看这两篇文章

  • [高并发下如何保证接口的幂等性?]
  • [幂等设计,都有哪些技术方案?]

二、订单快照,减少存储成本

商品信息是可以修改的,当用户下单后,为了更好解决后面可能存在的买卖纠纷,创建订单时会同步保存一份商品详情信息,称之为订单快照。

同一件商品,会有很多用户会购买,如果热销商品,短时间就会有上万的订单。如果每个订单都创建一份快照,存储成本太高。另外商品信息虽然支持修改,但毕竟是一个低频动作。我们可以理解成,大部分订单的商品快照信息都是一样的,除非下单时用户修改过。

如何实时识别修改动作是解决快照成本的关键所在。我们采用摘要比对的方法‍。创建订单时,先检查商品信息摘要是否已经存在,如果不存在,会创建快照记录。订单明细会关联商品的快照主键。

public class DigestTest {
    public static void encodeStr(String data) {
        String encodeS = DigestUtils.md5Hex(data);
        System.out.println(encodeS);
    }
    public static void main(String[] args) {
        String data = "网销投连险是保险公司的一款保险产品,在互联网金融上还是很常见的。" + "比如京东天天盈,网易有钱零钱++。这些保险削弱了保险的保障功能,降低成本,从而提高保险的理财功能提高理财收益。"
                      + "投连险基本和银行结构性理财产品一样,信息披露度不高,但是有保险公司兜底,不至于整个平台跑路。"
                      + "投资投连险可以想象为投资一个起点低的银行理财产品吧。网销投连险一般都受益在4-6%,不承诺保本。"
                      + "经常爆出保险公司的保障型长期投连险出现投资亏损新闻,但是网销短期投连险投资型投连险目前没有出现亏损,基本也能按照预期收益兑付。"
                      + "网销投连险安全性和收益性都比较居中,短期产品危险系数不高,但是在债券违约的大环境下,长期产品安全性没有太大保障。" + "不过好在保险公司没有跑路风险,至少不会把本金损失殆尽啊。";
        encodeStr(data);
    }
}

由于订单快照属于非核心操作,即使失败也不应该影响用户正常购买流程,所以通常采用异步流程执行。

三、购物车,混合存储

购物车是电商系统的标配功能,暂存用户想要购买的商品。分为添加商品、列表查看、结算下单三个动作。

技术设计并不是特别复杂,存储的信息也相对有限(用户id、商品id、sku_id、数量、添加时间)。这里特别拿出来单讲主要是用户体验层面要注意几个问题:

添加购物车时,后端校验用户未登录,常规思路,引导用户跳转登录页,待登录成功后,再添加购物车。多了一步操作,给用户一种强迫的感觉,体验会比较差。有没有更好的方式?

如果细心体验京东、淘宝等大平台,你会发现即使未登录态也可以添加购物车,这到底是怎么实现的?

细细琢磨其实原理并不复杂,服务端这边在用户登录态校验时,做了分支路由,当用户未登录时,会创建一个临时Token,作为用户的唯一标识,购物车数据挂载在该Token下,为了避免购物车数据相互影响以及设计的复杂度,这里会有一个临时购物车表。

当然,临时购物车表的数据量并不会太大,why?用户不会一直闲着添加购物车玩,当用户登录后,查看自己的购物车,服务端会从请求的cookie里查找购物车Token标识,并查询临时购物车表是否有数据,然后合并到正式购物车表里。

特别说明:

临时购物车是不是一定要在服务端存储?未必。

有架构师倾向前置存储,将数据存储在浏览器或者APP LocalStorage,这部分数据毕竟不是共享的,但是不太好的增加了设计的复杂度。

  • 客户端需要借助本地数据索引,远程请求查完整信息
  • 如果是登录态,还要增加数据合并逻辑

考虑到这两部分数据只是用户标识的差异性,所以作者还是建议统一存到服务端,日后即使业务逻辑变更,只需要改一处就可以了,毕竟自运营系统,良好的可维护性也需要我们非常关注的。

四、库存超卖

常见的库存扣减方式有:

  • 下单减库存:即当买家下单后,在商品的总库存中减去买家购买数量。下单减库存是最简单的减库存方式,也是控制最精确的一种,下单时直接通过数据库的事务机制控制商品库存,这样一定不会出现超卖的情况。但是你要知道,有些人下完单可能并不会付款。
  • 付款减库存:即买家下单后,并不立即减库存,而是等到有用户付款后才真正减库存,否则库存一直保留给其他买家。但因为付款时才减库存,如果并发比较高,有可能出现买家下单后付不了款的情况,因为可能商品已经被其他人买走了。
  • 预扣库存:这种方式相对复杂一些,买家下单后,库存为其保留一定的时间(如 30 分钟),超过这个时间,库存将会自动释放,释放后其他买家就可以继续购买。在买家付款前,系统会校验该订单的库存是否还有保留:如果没有保留,则再次尝试预扣;如果库存不足(也就是预扣失败)则不允许继续付款;如果预扣成功,则完成付款并实际地减去库存。

至于采用哪一种减库存方式更多是业务层面的考虑,减库存最核心的是大并发请求时保证数据库中的库存字段值不能为负数。

方案一:

通常在扣减库存的场景下使用行级锁,通过数据库引擎本身对记录加锁的控制,保证数据库的更新的安全性,并且通过where语句的条件,保证库存不会被减到 0 以下,也就是能够有效的控制超卖的场景。

update ... set amount = amount - 1 where id = $id and amount - 1 >=0

方案二:

设置数据库的字段数据为无符号整数,这样减后库存字段值小于零时 SQL 语句会报错。

五、商家发货,物流单更新 ABA 问题

举个例子:

商家发货,填写运单号,开始填了 123,后来发现填错了,然后又修改为 456。

此时,如果就为某种特殊场景埋下错误伏笔,具体我们来看下

过程:

  • 开始「请求A」发货,调订单服务接口,更新运单号 123
  • 但是响应有点慢,超时了
  • 此时,商家发现运单号填错了,发起了「请求B」,更新运单号为 456 ,订单服务也响应成功了
  • 这时,「请求A」触发了重试,再次调用订单服务,更新运单号 123,订单服务也响应成功了
  • 订单服务最后保存的 运单号 是 123

是不是犯错了!!!!

那么有什么好的解决方案吗?

很多人可能会说,不重试不就可以了,要知道重试机制 是高可用服务的重要保障手段,很多重试是框架自动发起的。

理想的解决方案:

数据库表引入一个额外字段 version,每次更新时,判断表中的版本号与请求参数携带的版本号是否一致

update order
set logistics_num = #{logistics_num} , version = #{version} + 1
where order_id= 1111 and version = #{version}
  • 一致:才触发更新
  • 不一致:说明这期间执行过数据更新,可能会引发错误,拒绝执行。

六、账户余额更新,保证事务

用户支付,我们要从买家账户减掉一定金额,再往卖家增加一定金额,为了保证数据的完整性可追溯性,变更余额时,我们通常会同时插入一条记录流水

账户流水核心字段:流水ID、金额、交易双方账户、交易时间戳、订单号、

注意:账户流水只能新增,不能修改和删除。流水号必须是自增的。

后续,系统对账时,我们只需要对交易流水明细数据做累计即可,如果出现和余额不一致情况,一般以交易流水为准来修复余额数据。

更新余额记录流水 虽属于两个操作,但是要保证要么都成功,要么都失败。要做到事务。

数据库的事务隔离级别有:读未提交(RU)读已提交(RC)可重复读(RR)串行化(Serializable)

常用的隔离级别是 RC 和 RR ,因为这两种隔离级别都可以避免脏读。

  • [跑了4个实验,实战讲解 MySQL的行锁、间隙锁...]
  • [InnoDB解决幻读的方案 -- LBCC&MVCC]

当然,如果涉及多个微服务调用,会用到分布式事务

分布式事务,细想下也很容易理解,就是将一个大事务拆分为多个本地事务,本地事务依然借助于数据库自身事务来解决,难点在于解决这个分布式一致性问题,借助重试机制,保证最终一致是我们常用的方案。

七、MySQL读写分离带来的数据不一致问题

互联网业务大部分都是 读多写少,为了提升数据库集群的吞吐性能,我们通常会采用 主从架构读写分离

部署一个主库实例,客户端请求所有写操作全部写到主库,然后借助 MySQL 自带的 主从同步 功能,做一些简单配置,可以近乎实时的将主库的数据同步给 多个从库实例,主从延迟非常小,一般不超过 1 毫秒

客户端请求的所有读操作全部打到 从库,借助多实例集群提升读请求的整体处理能力。

这个方案看似天衣无缝,但实际有个 副作用

主从同步虽然近乎实时,但还是有个 时间差 ,主库数据刚更新完,但数据还没来得及同步到从库,后续读请求直接访问了从库,看到的还是旧数据,影响用户体验。

任何事情都不是完美的,从主同步也是一样,没有完美的解决方案,我们要找到其中的平衡取舍点。

我们以电商为例,看看如何从 产品层面 来化解这个问题

为了实验的真实性,Tom哥 特意在淘宝下了一笔购物订单

在下单确认页面,点击购买按钮,进入了支付页面

输入支付宝支付密码,进入支付成功页面,页面有查看订单详情的入口。

点击 查看交易详情 ,才跳到真正的 订单详情页,可以查看订单的支付状态(订单数据取自从库)

看懂了吗?

我们在支付成功后,并没有立即跳到 订单详情页,而是增加了一个 无关紧要的 中间页(支付成功页),一是告诉你支付的结果是成功的,钱没丢,不要担心;另外也可以增加一些推荐商品,引流提升网站的GMV。最重要的,增加了一个缓冲期,为 订单的主从库数据同步 争取了更多的时间。

可谓一举多得,其他互联网业务也是类似道理。

是不是又学了一招

八、历史订单,归档

根据二八定律,系统绝大部分的性能开销花在20%的业务。数据也不例外,从数据的使用频率来看,经常被业务访问的数据称为热点数据;反之,称之为冷数据。

在了解的数据的冷、热特性后,便可以指导我们做一些有针对性的性能优化。这里面有业务层面的优化,也有技术层面的优化。比如:电商网站,一般只能查询3个月内的订单,如果你想看看3个月前的订单,需要访问历史订单页面。

实现思路:

1、冷热数据区分的标准是什么?要结合业务思考,可能要找产品同学一块讨论才能做决策,切记不要拍脑袋。以电商订单为例:

  • 方案一:以“下单时间”为标准,将3 个月前的订单数据当作冷数据,3 个月内的当作热数据。
  • 方案二:根据“订单状态”字段来区分,已完结的订单当作冷数据,未完结的订单当作热数据。
  • 方案三:组合方式,把下单时间 > 3 个月且状态为“已完结”的订单标识为冷数据,其他的当作热数据。

2、如何触发冷热数据的分离

  • 方案一:直接修改业务代码,每次业务请求触发冷热数据判断,根据结果路由到对应的冷数据表或热数据表。缺点:如果判断标准是 时间维度,数据过期了无法主动感知。
  • 方案二:如果觉得修改业务代码,耦合性高,不易于后期维护。可以通过监听数据库变更日志 binlog 方式来触发
  • 方案三:常用的手段是跑定时任务,一般是选择凌晨系统压力小的时候,通过跑批任务,将满足条件的冷数据迁移到其他存储介质。在途业务表中只留下来少量的热点数据。

3、如何实现冷热数据分离,过程大概分为三步:

  • 判断数据是冷、还是热
  • 将冷数据插入冷数据表中
  • 然后,从原来的热库中删除迁移的数据

4、如何使用冷热数据

  • 方案一:界面设计时会有选项区分,如上面举例的电商订单
  • 方案二:直接在业务代码里区分。

九、订单分库分表,多维度查询

如果电商网站的订单数过多,我们一般会想到 分库分表 解决策略。没问题,这个方向是对的。

但是查询维度很多

1、买家,查询 我的订单 列表,需要根据 buyer_id 来查询

2、查看订单详情,需要根据 order_id 来查询

3、卖家,查询 我的销售 列表,需要根据 seller_id 来查询

而订单分表只有一个分表键,如何满足多维度 SQL 操作呢?

我们一般是基于买家维度来设计,下图是 淘宝 的订单列表

一个订单号 19 位,我们会发现同一个用户不同订单的最后 6 位都是一样的,没错,那是用户id的后6位。

这样,上文中 场景1场景2 的查询可以共性抽取, 采用 buyer_idorder_id后六位 作为分表键,对 1 000 000 取模,得到买家维度的订单分表的编号。

至于 场景3 卖家维度的订单查询,我们可以采用数据异构方式,按 seller_id 维度另外存储一份数据,专门供卖家使用。

本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/b50dAKULjzJjfRdoZmxwJw

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237270次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8108次阅读
 目录