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

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

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

秒杀业务

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