Redis - 在电商购物车场景下的实战分析

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis - 在电商购物车场景下的实战分析

1. 购物车需求背景与业务整体设计

1.1 写在前面

1.1.1 需求背景

商城购物车模拟了传统的现实世界中真实存在的购物车的功能,便于用户挑选心仪商品统一结算等。同时还能在这个点上加以创新,加一些其他的功能。比如:比价,推荐(可作为商家的竞价广告位)等,甚至还可以统计数据告诉卖家,有多少人添加了购物车(代表有购物意向),结果没有付款(尝试分析原因)。

1.1.2 购物车的妙用

购物车在实际使用中对用户来说,兼具凑单、促销、收藏的功能。


  1. 凑单

在用户浏览商品详情页的时候,有两种选项:一种是“立即购买”, 另一种是“加入购物车”。当用户本身需求较多,想一次购买多种商品, 或者参与到优惠活动中(如满减、满赠等),这时候会将商品加入购物车进行凑单。

  1. 促销

购物车还有促销方面的功能,用于提高客单价。当有促销活动(满减、满赠)时,用户将商品加入购物车之后,可以查看是否满足优惠条件和优惠之后的金额(不包含优惠券)。

  1. 收藏

对于大部分用户来说,购物车发挥更多的是收藏的作用:“这东西看着不错,等以后再下单。”另外还有筛选的作用。比如笔者网购时, 会先加入购物车收藏,后面有时间再在购物车中筛选之后购买。

1.2 业务设计

1.2.1 通用显示

  1. 商品信息
  2. 促销信息
  3. 选中状态

默认全选、默认全不选、继承上次选中

  1. 结算

1.2.2 离线购物车

离线购物车指的是用户在未登录状态下把商品加入购物车,一般通过创建虚拟用户实现。为了更好的用户体验,需要让用户在下单之前,允许未登录先将商品加入购物车。

用户登录之后,涉及离线购物车和在线购物车合并。首先判断当前是否有离线购物车,然后将离线购物车的数据和在线购物车的数据进行合并。

1.2.3 商品监控

  1. 库存监控

设置库存提醒值,判断当前商品的数量,当库存数大于0并 小于提醒值时,提醒用户库存不足,请尽快下单;当库存数等于0时, 提醒无货。

  1. 状态监控

当商品下架后,提示商品无效;

无效商品进入无效商品列表中,可批量清除。

  1. 价格监控

购物车的商品价格变动时给用户提示,比如降价20元,会对用户的消费决策产生影响。

1.2.4 分类排序

  1. 商家店铺,将不同店铺的商品分开;
  2. 优惠不同,在购物车中将优惠活动相同的商品聚合在一起;
  3. 加入时间,按照加入购物车的时间倒序排列,最近添加的商品排列在 前。

1.2.5 促销信息

购物车中显示促销相关信息,类似满减、满赠、赠品等信息。例如在购物车中显示“满500减100”、“全场满减”、“商品的赠品有哪些”。还可以引导客户去店铺领取优惠券。在购物车中展示促销信息对提高客单价有良好效果,笔者认为目前最好用的购物车非京东莫属。

1.2.6 商品推荐

在购物车底部,是最好的商品宣传位,可以添加为商品推荐区域。 至于商品推荐的内容,会根据用户数据做定向推荐,这里不做扩展。

1.2.7 编辑

编辑购物车时主要可以进行的操作:删除商品、加减商品数量、更改选中状态、更改商品规格等。

1.2.8 结算

在购物车选中商品时,会实时算出订单金额。在购物车中计算时,需要将优惠金额算进去。

计算优惠金额还需要考虑满减促销、多种优惠券同时满足订单时用户自主选择还是推荐最优券等等。

2. 购物车核心链路和技术方案设计

2.1 核心链路

2.2 技术方案设计

部分电商公司对于购物车数据会选择不落库处理,只做Redis缓存;本次案例以Redis为主,同时通过RocketMQ将购物车数据异步更新到MySQL,不需要去保证Redis缓存和MySQL持久化的数据一致性,数据库只是作为数据备份。

业务上来说,购物车其实是临时性的数据。仅仅是把一些商品再购物车里进行暂存,迟早会购买(从购物车里删除),或者长时间没有购买,已经遗忘了加购过什么商品。就算在极端情况下丢失数据,也影响不大,这时用户重新加入就好了。

2.2.1 Redis

  • 缓存穿透
    当请求穿透缓存时,通过写入空缓存、分布式锁限制MySQL的负载。

2.2.2 表结构

-- auto-generated definition
create table cart
(
    id              bigint auto_increment comment '主键ID'
        primary key,
    user_id         bigint         default 0                 not null comment '用户ID',
    product_sku_id  bigint         default 0                 not null comment '商品SKU ID',
    product_sku_num int            default 0                 not null comment '商品SKU数量',
    add_amount      decimal(10, 2) default 0.00              not null comment '加购价格',
    selected_status tinyint        default 1                 not null comment '选中状态 0:未选中 1:已选中',
    is_deleted      tinyint        default 0                 not null comment '是否删除 0:未删除 1:已删除',
    create_time     datetime       default CURRENT_TIMESTAMP not null comment '创建时间',
    update_time     datetime       default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '修改时间'
)
    comment '购物车表';
create index idx_product_sku_id
    on cart (product_sku_id);
create index idx_user_id
    on cart (user_id);

2.2.3 MQ

加入购物车/更新购物车通过RocketMQ异步入库

3. 购物车的阈值检查与重复加入逻辑

3.1 为什么淘宝购物车要设置上限?

3.1.1 回归原始 - 拟物

实体购物车因为有物理的空间限制,理论上可以购买的商品件数和空间是有限的,因此电商的购物车其实在拟物化上也沿袭了这一设计。

站在平台和商家的立场考虑,购物车上限的提示是在一定程度上引导用户去结算或者清理的,提升购物车商品的曝光量,同时也是希望用户把购物车和收藏夹的场景区分开来的,保留购物车的核心功能。

3.1.2 需求大小与价值衡量

  1. 需求大小

从我自身的使用上,我目前还未遇到过购物车超过上限的情况,但是基于淘宝天猫这么大超过8亿的用户群体,碰到购物车超过上限的比例如果只有1%,那绝对值也有庞大的800万用户。

  1. 价值衡量

电商购物最终一定是以交易成交为目的的,也就是解决这个问题能否提升用户下单率和成交件数。这个其实是不一定的,当购物车上限过多时,有可能用户的购买决策会更难,周期可能会更长,同时购物车过多商品用户也会表示很难找到自己想结算的商品,所以在需求的价值上来说是需要慎重衡量的。

  1. 解决方案

(1)引导用户结算或者清理;

(2)引导用户先添加收藏夹再添加购物车;

(3)类似花呗限时提额的操作;

(4)类似美团外卖多个购物车的场景;

(5)在大促是限时提高购物车的上限。

3.1.3 技术和性能

在大促时,系统本来已经面临千万级上亿级别的并发量,为了避免购物车商品图片、价格等信息加载不出来,出现卡顿等情况,设置上限是保证用户体验的一个手段,当用户不能添加购物车需要清理购物车,和进入购物车出现卡顿或加载不出来相比,影响相对较小。

购物车结算涉及到跨店铺满减、商品库存、优惠券、订单金额计算等多达几十个服务的调用

因此技术上为了避免宕机或者影响用户无法结算等糟糕的体验,设置购物车上限是一种产品上的妥协。

3.2 购物车需要设置哪些上限

  1. 购物车单个SKU上限
  2. 购物车加购SKU上限

3.3 重复加入

  1. 不校验重入逻辑
  2. 校验重入逻辑
@Slf4j
@Component
public class RedissonUtils {
    @Resource
    private RedissonClient redissonClient;
    public boolean lock(String key, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(key);
        try {
            return lock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            log.error("[RedissonUtils][lock] - tryLock异常", e);
        }
        return false;
    }
    public void unLock(String key) {
        RLock lock = redissonClient.getLock(key);
        if (ObjectUtils.isNotEmpty(lock)) {
            lock.unlock();
        }
    }
}

4. 购物车加入商品多线程并发问题解决

相关文章
|
13天前
|
存储 NoSQL 前端开发
Redis专题-实战篇一-基于Session和Redis实现登录业务
本项目基于SpringBoot实现黑马点评系统,涵盖Session与Redis两种登录方案。通过验证码登录、用户信息存储、拦截器校验等流程,解决集群环境下Session不共享问题,采用Redis替代Session实现数据共享与自动续期,提升系统可扩展性与安全性。
92 3
Redis专题-实战篇一-基于Session和Redis实现登录业务
|
13天前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
79 1
Redis专题-实战篇二-商户查询缓存
|
4月前
|
缓存 监控 NoSQL
Redis 实操要点:Java 最新技术栈的实战解析
本文介绍了基于Spring Boot 3、Redis 7和Lettuce客户端的Redis高级应用实践。内容包括:1)现代Java项目集成Redis的配置方法;2)使用Redisson实现分布式可重入锁与公平锁;3)缓存模式解决方案,包括布隆过滤器防穿透和随机过期时间防雪崩;4)Redis数据结构的高级应用,如HyperLogLog统计UV和GeoHash处理地理位置。文章提供了详细的代码示例,涵盖Redis在分布式系统中的核心应用场景,特别适合需要处理高并发、分布式锁等问题的开发场景。
277 41
|
4月前
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
1036 7
|
4月前
|
机器学习/深度学习 存储 NoSQL
基于 Flink + Redis 的实时特征工程实战:电商场景动态分桶计数实现
本文介绍了基于 Flink 与 Redis 构建的电商场景下实时特征工程解决方案,重点实现动态分桶计数等复杂特征计算。通过流处理引擎 Flink 实时加工用户行为数据,结合 Redis 高性能存储,满足推荐系统毫秒级特征更新需求。技术架构涵盖状态管理、窗口计算、Redis 数据模型设计及特征服务集成,有效提升模型预测效果与系统吞吐能力。
346 2
|
5月前
|
缓存 NoSQL Java
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
105 5
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
|
5月前
|
NoSQL 算法 安全
redis分布式锁在高并发场景下的方案设计与性能提升
本文探讨了Redis分布式锁在主从架构下失效的问题及其解决方案。首先通过CAP理论分析,Redis遵循AP原则,导致锁可能失效。针对此问题,提出两种解决方案:Zookeeper分布式锁(追求CP一致性)和Redlock算法(基于多个Redis实例提升可靠性)。文章还讨论了可能遇到的“坑”,如加从节点引发超卖问题、建议Redis节点数为奇数以及持久化策略对锁的影响。最后,从性能优化角度出发,介绍了减少锁粒度和分段锁的策略,并结合实际场景(如下单重复提交、支付与取消订单冲突)展示了分布式锁的应用方法。
362 3
|
5月前
|
存储 NoSQL Java
从扣减库存场景来讲讲redis分布式锁中的那些“坑”
本文从一个简单的库存扣减场景出发,深入分析了高并发下的超卖问题,并逐步优化解决方案。首先通过本地锁解决单机并发问题,但集群环境下失效;接着引入Redis分布式锁,利用SETNX命令实现加锁,但仍存在死锁、锁过期等隐患。文章详细探讨了通过设置唯一标识、续命机制等方法完善锁的可靠性,并最终引出Redisson工具,其内置的锁续命和原子性操作极大简化了分布式锁的实现。最后,作者剖析了Redisson源码,揭示其实现原理,并预告后续关于主从架构下分布式锁的应用与性能优化内容。
242 0
|
5月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
5月前
|
缓存 NoSQL Java
Redis+Caffeine构建高性能二级缓存
大家好,我是摘星。今天为大家带来的是Redis+Caffeine构建高性能二级缓存,废话不多说直接开始~
720 0