• Redis如何助力高并发秒杀系统?看完这篇我彻底懂了!!

Redis如何助力高并发秒杀系统?看完这篇我彻底懂了!!

2025-05-28 02:37:08 栏目:宝塔面板 126 阅读

秒杀业务

在电商领域,存在着典型的秒杀业务场景,那何谓秒杀场景呢。简单的来说就是一件商品的购买人数远远大于这件商品的库存,而且这件商品在很短的时间内就会被抢购一空。比如每年的618、双11大促,小米新品促销等业务场景,就是典型的秒杀业务场景。

秒杀业务最大的特点就是瞬时并发流量高,在电商系统中,库存数量往往会远远小于并发流量,比如:天猫的秒杀活动,可能库存只有几百、几千件,而瞬间涌入的抢购并发流量可能会达到几十到几百万。

所以,我们可以将秒杀系统的业务特点总结如下。

图片

(1)限时、限量、限价

在规定的时间内进行;秒杀活动中商品的数量有限;商品的价格会远远低于原来的价格,也就是说,在秒杀活动中,商品会以远远低于原来的价格出售。

例如,秒杀活动的时间仅限于某天上午10点到10点半,商品数量只有10万件,售完为止,而且商品的价格非常低,例如:1元购等业务场景。

限时、限量和限价可以单独存在,也可以组合存在。

(2)活动预热

需要提前配置活动;活动还未开始时,用户可以查看活动的相关信息;秒杀活动开始前,对活动进行大力宣传。

(3)持续时间短

购买的人数数量庞大;商品会迅速售完。

在系统流量呈现上,就会出现一个突刺现象,此时的并发访问量是非常高的,大部分秒杀场景下,商品会在极短的时间内售完。

秒杀三阶段

通常,从秒杀开始到结束,往往会经历三个阶段:

  • 准备阶段:这个阶段也叫作系统预热阶段,此时会提前预热秒杀系统的业务数据,往往这个时候,用户会不断刷新秒杀页面,来查看秒杀活动是否已经开始。在一定程度上,通过用户不断刷新页面的操作,可以将一些数据存储到Redis中进行预热。
  • 秒杀阶段:这个阶段主要是秒杀活动的过程,会产生瞬时的高并发流量,对系统资源会造成巨大的冲击,所以,在秒杀阶段一定要做好系统防护。
  • 结算阶段: 完成秒杀后的数据处理工作,比如数据的一致性问题处理,异常情况处理,商品的回仓处理等。

Redis助力秒杀系统

我们可以在Redis中设计一个Hash数据结构,来支持商品库存的扣减操作,如下所示。

seckill:goodsStock:${goodsId}{
 totalCount:200,
 initStatus:0,
 seckillCount:0
}

在我们设计的Hash数据结构中,有三个非常主要的属性。

  • totalCount:表示参与秒杀的商品的总数量,在秒杀活动开始前,我们就需要提前将此值加载到Redis缓存中。
  • initStatus:我们把这个值设计成一个布尔值。秒杀开始前,这个值为0,表示秒杀未开始。可以通过定时任务或者后台操作,将此值修改为1,则表示秒杀开始。
  • seckillCount:表示秒杀的商品数量,在秒杀过程中,此值的上限为totalCount,当此值达到totalCount时,表示商品已经秒杀完毕。

我们可以通过下面的代码片段在秒杀预热阶段,将要参与秒杀的商品数据加载的缓存。

/**
 * @author binghe
 * @description 秒杀前构建商品缓存代码示例
 */
public class SeckillCacheBuilder{
    private static final String GOODS_CACHE = "seckill:goodsStock:"; 
    private String getCacheKey(String id) { 
        return  GOODS_CACHE.concat(id);
    } 
    public void prepare(String id, int totalCount) { 
        String key = getCacheKey(id); 
        Map goods = new HashMap<>(); 
        goods.put("totalCount", totalCount); 
        goods.put("initStatus", 0); 
        goods.put("seckillCount", 0); 
        redisTemplate.opsForHash().putAll(key, goods); 
     }
}

秒杀开始的时候,我们需要在代码中首先判断缓存中的seckillCount值是否小于totalCount值,如果seckillCount值确实小于totalCount值,我们才能够对库存进行锁定。在我们的程序中,这两步其实并不是原子性的。如果在分布式环境中,我们通过多台机器同时操作Redis缓存,就会发生同步问题,进而引起“超卖”的严重后果。

在电商领域,有一个专业名词叫作“超卖”。顾名思义:“超卖”就是说卖出的商品数量比商品的库存数量多,这在电商领域是一个非常严重的问题。那么,我们如何解决“超卖”问题呢?

Lua脚本完美解决超卖问题

我们如何解决多台机器同时操作Redis出现的同步问题呢?一个比较好的方案就是使用Lua脚本。我们可以使用Lua脚本将Redis中扣减库存的操作封装成一个原子操作,这样就能够保证操作的原子性,从而解决高并发环境下的同步问题。

例如,我们可以编写如下的Lua脚本代码,来执行Redis中的库存扣减操作。

local resultFlag = "0" 
local n = tonumber(ARGV[1]) 
local key = KEYS[1] 
local goodsInfo = redis.call("HMGET",key,"totalCount","seckillCount") 
local total = tonumber(goodsInfo[1]) 
local alloc = tonumber(goodsInfo[2]) 
if not total then 
    return resultFlag 
end 
if total >= alloc + n  then 
    local ret = redis.call("HINCRBY",key,"seckillCount",n) 
    return tostring(ret) 
end 
return resultFlag

我们可以使用如下的Java代码来调用上述Lua脚本。

public int secKill(String id, int number) { 
    String key = getCacheKey(id); 
    Object seckillCount =  redisTemplate.execute(script, Arrays.asList(key), String.valueOf(number)); 
    return Integer.valueOf(seckillCount.toString()); 
}

这样,我们在执行秒杀活动时,就能够保证操作的原子性,从而有效的避免数据的同步问题,进而有效的解决了“超卖”问题。

本文地址:https://www.yitenyun.com/245.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 TIME_WAIT 运维 负载均衡 JumpServer SSL 堡垒机 跳板机 HTTPS HexHub Docker 服务器 服务器性能 管理口 JumpServer安装 堡垒机安装 Linux安装JumpServer Deepseek 宝塔面板 Linux宝塔 生命周期 esxi esxi6 root密码不对 无法登录 web无法登录 SQL 查询 序列 核心机制 Windows Windows server net3.5 .NET 安装出错 HTTPS加密 Windows宝塔 Mysql重置密码 开源 PostgreSQL 存储引擎 锁机制 宝塔面板打不开 宝塔面板无法访问 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 行业 趋势 Oracle 处理机制 无法访问宝塔面板 Undo Log 机制 监控 连接控制 InnoDB 数据库锁 Spring Redis 异步化 优化 万能公式 机器学习 动态查询 Serverless 无服务器 语言 ES 协同 响应模型 group by 索引 技术 openHalo 分页查询 scp Linux的scp怎么用 scp上传 scp下载 scp命令 Postgres OTel Iceberg 缓存方案 缓存架构 缓存穿透 工具 高可用 存储 GreatSQL 连接数 数据 主库 SVM Embedding R edis 线程 日志文件 MIXED 3 Linux 安全 国产数据库 SQLite-Web SQLite 数据库管理工具 加密 场景 R2DBC Netstat Linux 服务器 端口 启动故障 ​Redis 推荐模型 Recursive 自定义序列化 防火墙 黑客 云原生 RocketMQ 长轮询 配置 SQLark 共享锁 向量数据库 大模型 OB 单机版 AI 助手 Hash 字段 PG DBA Rsync Ftp 信息化 智能运维 不宕机 磁盘架构 电商 系统 架构 向量库 Milvus 数据分类 Python Canal 修改DNS Centos7如何修改DNS 业务 IT运维 流量 传统数据库 向量化 线上 库存 预扣 filelock 分库 分表 • 索引 • 数据库 MVCC redo log 重做日志 语句 同城 双活 聚簇 非聚簇 MySQL 9.3 sftp 服务器 参数 PostGIS mini-redis INCR指令 人工智能 推荐系统 频繁 Codis MongoDB MCP 开放协议 Doris SeaTunnel 缓存 Redisson 锁芯 失效 高效统计 今天这篇文章就跟大家 工具链 主从复制 代理 数据备份 数据类型 虚拟服务器 虚拟机 内存 事务 Java 开发 INSERT COMPACT prometheus Alert 千万级 大表 窗口 函数 SSH 容器 数据结构 ZODB 发件箱模式 EasyExcel MySQL8 引擎 性能 Web 分布式架构 分布式锁​ 聚簇索引 非聚簇索引 QPS 高并发 网络架构 网络配置 崖山 新版本 数据脱敏 加密算法 B+Tree ID 字段 RDB AOF 分页 核心架构 订阅机制 速度 服务器中毒 Go 数据库迁移 Web 接口 分布式 集中式 自动重启 OAuth2 Token Redis 8.0 数据集成工具 读写 容器化 网络故障 播客 模型 数据页 DBMS 管理系统 StarRocks 数据仓库 池化技术 连接池 微软 SQL Server AI功能 Redka SpringAI JOIN 排行榜 排序 Caffeine CP MGR 分布式集群 网络 部署 原子性 Entity 事务隔离 LRU 业务场景 Valkey Valkey8.0 Pottery Testcloud 云端自动化 数据字典 兼容性 dbt 数据转换工具 分页方案 排版 优化器 事务同步 1 ReadView 意向锁 记录锁 sqlmock 关系数据库 悲观锁 乐观锁 UUIDv7 主键 日志 Weaviate 单点故障 单线程 仪表盘 对象 Order AIOPS UUID ID InfluxDB 编程 Pump RAG HelixDB Ansible IT 双引擎 Crash 代码 分布式锁 Zookeeper 产业链 恢复数据 字典 订单 LLM List 类型 线程安全 国产 用户 慢SQL优化 表空间 拦截器 动态代理 解锁 调优 Next-Key RR 互联网 GitHub Git 快照读 当前读 视图 神经系统 矢量存储 数据库类型 AI代理 查询规划 count(*) count(主键) 行数 算法 CAS 技巧 多线程 并发控制 恢复机制 闪回