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

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

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

秒杀业务

在电商领域,存在着典型的秒杀业务场景,那何谓秒杀场景呢。简单的来说就是一件商品的购买人数远远大于这件商品的库存,而且这件商品在很短的时间内就会被抢购一空。比如每年的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 双主架构 循环复制 Deepseek 宝塔面板 Linux宝塔 Docker 生命周期 JumpServer JumpServer安装 堡垒机安装 Linux安装JumpServer 序列 核心机制 esxi esxi6 root密码不对 无法登录 web无法登录 Windows Windows server net3.5 .NET 安装出错 宝塔面板打不开 宝塔面板无法访问 SSL 堡垒机 跳板机 HTTPS 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 无法访问宝塔面板 Windows宝塔 Mysql重置密码 HTTPS加密 连接控制 机制 ES 协同 Oracle 处理机制 Serverless 无服务器 语言 OB 单机版 Spring SQL 动态查询 scp Linux的scp怎么用 scp上传 scp下载 scp命令 技术 存储 索引 运维 缓存方案 缓存架构 缓存穿透 分页查询 架构 InnoDB 日志文件 MIXED 3 Rsync RocketMQ 长轮询 配置 响应模型 修改DNS Centos7如何修改DNS 监控 Redis 电商 系统 HexHub Linux 安全 服务器 聚簇 非聚簇 MySQL 9.3 异步化 防火墙 黑客 查询 数据 主库 sftp 服务器 参数 group by 自定义序列化 管理口 数据库锁 SQLark PostgreSQL 业务 SQLite-Web SQLite 数据库管理工具 开源 存储引擎 线上 库存 预扣 Doris SeaTunnel MVCC 人工智能 向量数据库 推荐系统 R edis 线程 共享锁 PG DBA 网络架构 工具 网络配置 加密 场景 流量 数据备份 AI 助手 Ftp redo log 重做日志 ​Redis 机器学习 推荐模型 信息化 智能运维 B+Tree ID 字段 • 索引 • 数据库 RDB AOF Redis 8.0 缓存 高可用 Canal GreatSQL 连接数 Python 优化 万能公式 INSERT COMPACT 核心架构 订阅机制 网络故障 Postgres OTel Iceberg Hash 字段 同城 双活 云原生 IT运维 微软 SQL Server AI功能 不宕机 Web 自动重启 prometheus Alert Netstat Linux 服务器 端口 引擎 性能 大模型 SVM Embedding 高效统计 今天这篇文章就跟大家 OAuth2 Token Entity 开发 分库 分表 虚拟服务器 虚拟机 内存 向量库 Milvus ZODB Undo Log 单点故障 DBMS 管理系统 MongoDB 容器 sqlmock 崖山 新版本 mini-redis INCR指令 JOIN 数据集成工具 容器化 LRU 悲观锁 乐观锁 openHalo 窗口 函数 分布式 集中式 排行榜 排序 磁盘架构 SpringAI Testcloud 云端自动化 Redka 数据脱敏 加密算法 Redisson 锁芯 QPS 高并发 大表 业务场景 EasyExcel MySQL8 Recursive PostGIS 启动故障 StarRocks 数据仓库 分页 数据结构 意向锁 记录锁 Pottery 聚簇索引 非聚簇索引 数据类型 分布式架构 分布式锁​ 模型 原子性 AIOPS R2DBC 事务 Java SSH IT Caffeine CP 网络 MCP 开放协议 InfluxDB 1 工具链 发件箱模式 池化技术 连接池 Web 接口 dbt 数据转换工具 RAG HelixDB filelock 数据分类 部署 对象 速度 服务器中毒 字典 传统数据库 向量化 读写 Go 数据库迁移 事务隔离 数据页 优化器 单线程 仪表盘 双引擎 频繁 Codis 分页方案 排版 Order LLM 线程安全 Crash 代码 List 类型 UUIDv7 主键 订单 Pump 事务同步 日志 Ansible