首页/新闻资讯/正文详情

Redis分布式唯一ID与秒杀系统实战

发布时间:2026/11/6 16:43:42 来源:云帆数科 栏目:资讯中心
Redis分布式唯一ID与秒杀系统实战
1. Redis全局唯一ID生成实战在分布式系统中生成全局唯一ID是一个常见需求。传统数据库自增ID在分布式环境下存在性能瓶颈而Redis的高性能特性使其成为理想的解决方案。1.1 ID组成结构设计我们设计的64位ID结构如下符号位1bit固定为0保证ID为正数时间戳31bit以秒为单位可使用约69年序列号32bit每秒可生成2^32个不同ID这种设计具有以下优势时间戳在前保证ID趋势递增每秒可生成42亿个ID满足高并发需求无中心节点依赖各服务可独立生成1.2 Redis实现方案Component public class RedisIdWorker { private static final long BEGIN_TIMESTAMP 1640995200L; // 2022-01-01 00:00:00 private static final int COUNT_BITS 32; private StringRedisTemplate stringRedisTemplate; public long nextId(String keyPrefix) { // 1.生成时间戳 LocalDateTime now LocalDateTime.now(); long nowSecond now.toEpochSecond(ZoneOffset.UTC); long timestamp nowSecond - BEGIN_TIMESTAMP; // 2.生成序列号按天分片 String date now.format(DateTimeFormatter.ofPattern(yyyy:MM:dd)); long count stringRedisTemplate.opsForValue() .increment(icr: keyPrefix : date); // 3.拼接并返回 return timestamp COUNT_BITS | count; } }关键设计点解析按天分片计数器避免单个key无限增长便于数据清理位运算拼接通过左移和或运算高效组合时间戳与序列号基准时间使用固定时间戳减少ID长度提示BEGIN_TIMESTAMP应根据业务预期使用年限调整建议设置为系统上线时间2. 秒杀系统核心实现2.1 基础秒杀流程public Result seckillVoucher(Long voucherId) { // 1.查询优惠券 SeckillVoucher voucher seckillVoucherService.getById(voucherId); // 2.校验秒杀时间 if (voucher.getBeginTime().isAfter(LocalDateTime.now())) { return Result.fail(秒杀尚未开始); } if (voucher.getEndTime().isBefore(LocalDateTime.now())) { return Result.fail(秒杀已经结束); } // 3.校验库存 if (voucher.getStock() 1) { return Result.fail(库存不足); } // 4.扣减库存 boolean success seckillVoucherService.update() .setSql(stock stock - 1) .eq(voucher_id, voucherId) .gt(stock, 0) .update(); if (!success) { return Result.fail(库存不足); } // 5.创建订单 VoucherOrder voucherOrder new VoucherOrder(); voucherOrder.setId(redisIdWorker.nextId(order)); voucherOrder.setUserId(UserHolder.getUser().getId()); voucherOrder.setVoucherId(voucherId); save(voucherOrder); return Result.ok(voucherOrder.getId()); }2.2 超卖问题解决方案乐观锁实现方案boolean success seckillVoucherService.update() .setSql(stock stock - 1) .eq(voucher_id, voucherId) .gt(stock, 0) // 核心防超卖逻辑 .update();原理分析在更新时校验库存是否大于0利用数据库行锁保证原子性更新失败时返回库存不足性能优化建议库存预扣减提前将库存加载到Redis异步创建订单使用消息队列削峰库存预热活动前预先分配库存到不同节点3. 一人一单实现方案3.1 同步锁实现演进版本1.0问题public synchronized Result createVoucherOrder(Long voucherId) { // 方法级别锁导致所有用户串行 }版本2.0改进public Result createVoucherOrder(Long voucherId) { synchronized(userId.toString().intern()) { // 用户级别锁 } }但存在事务提交与锁释放时序问题锁在事务内释放事务提交前其他线程可能获取锁最终方案synchronized (userId.toString().intern()) { IVoucherOrderService proxy (IVoucherOrderService) AopContext.currentProxy(); return proxy.createVoucherOrder(voucherId); }3.2 集群环境问题单机锁在集群环境下失效需要使用分布式锁不同JVM的锁互不感知需要跨JVM的互斥机制4. Redis分布式锁实现4.1 基础实现public boolean tryLock(long timeoutSec) { String threadId ID_PREFIX Thread.currentThread().getId(); return Boolean.TRUE.equals( stringRedisTemplate.opsForValue() .setIfAbsent(KEY_PREFIX name, threadId, timeoutSec, TimeUnit.SECONDS) ); } public void unlock() { stringRedisTemplate.delete(KEY_PREFIX name); }4.2 误删问题优化增加锁标识校验public void unlock() { String threadId ID_PREFIX Thread.currentThread().getId(); String id stringRedisTemplate.opsForValue().get(KEY_PREFIX name); if(threadId.equals(id)) { stringRedisTemplate.delete(KEY_PREFIX name); } }4.3 原子性问题解决方案使用Lua脚本保证原子性-- unlock.lua if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 endJava调用private static final DefaultRedisScriptLong UNLOCK_SCRIPT; static { UNLOCK_SCRIPT new DefaultRedisScript(); UNLOCK_SCRIPT.setLocation(new ClassPathResource(unlock.lua)); UNLOCK_SCRIPT.setResultType(Long.class); } public void unlock() { stringRedisTemplate.execute( UNLOCK_SCRIPT, Collections.singletonList(KEY_PREFIX name), ID_PREFIX Thread.currentThread().getId()); }5. 实战经验总结5.1 性能优化关键点库存热点问题使用Redis集群分散压力本地缓存异步刷新策略库存分片如将1000库存分为10个key分布式锁优化锁粒度尽可能小合理设置超时时间不宜过长或过短考虑锁重入需求事务控制避免长事务合理设置事务隔离级别非核心流程可考虑最终一致性5.2 常见问题排查锁未释放确保finally块中释放锁添加锁过期时间作为兜底监控锁持有时间库存不一致定期对账添加库存操作日志实现补偿机制集群时钟不同步部署NTP时间同步服务关键业务使用同一时间源在实际项目中我们还需要考虑限流、降级、熔断等机制来保障系统稳定性。建议在测试环境充分模拟高并发场景通过压测发现潜在问题。

相关推荐

区块链预编译合约:原理、应用与优化策略
区块链预编译合约:原理、应用与优化策略

1. 区块链预编译合约的本质与价值 预编译合约(Precompiled Contract)是区块链底层设计中一个精妙的技术折中方案。它本质上是在虚拟机执行层预设的一组特殊合约地址,这些地址对应的并非普通智能合约字节码,而是直接映射到链底层实… · 2026/11/4 21:41:49

数据库试题刷题:考点映射与SQL关系代数校验
数据库试题刷题:考点映射与SQL关系代数校验

简介:中南大学数据库试题文档面向高校数据库课程备考与自测人群,围绕DBMS基础、三级模式、SQL语言、数据库保护及设计理论等核心考点组织内容,适合期末复习、考研初试梳理和课堂练习后的查漏补缺。压缩包仅含1个doc文件,大小约164… · 2026/11/4 21:41:49

Jev 深度解析:TypeSafe SDK 如何重塑 AI 编程模型接入
Jev 深度解析:TypeSafe SDK 如何重塑 AI 编程模型接入

1. 全网刷屏的 Jev 到底是个什么东西最近技术圈里聊得最多的一个词,非 Jev 莫属。不管你是刷技术社区、翻群聊记录,还是看各种工具链的讨论帖,几乎都能撞见有人在问“Jev 怎么接入”“Jev 密钥在哪申请”“Jev 在 Codex 里怎么用”。我一开始… · 2026/11/4 21:41:49

大模型实操指南:从本地部署到PPT级可控生成
大模型实操指南:从本地部署到PPT级可控生成

1. 这不是“学大模型”,而是重建你和信息世界的关系“大模型相关内容的研究学习”——看到这个标题,我第一反应是笑。不是嘲笑,是那种在实验室熬了三个通宵、刚调通一个LoRA微调任务后,盯着终端里跳出来的loss曲线突然失语的笑。因… · 2026/11/6 15:59:18

高效查找第K大元素:排序、堆与快速选择算法对比
高效查找第K大元素:排序、堆与快速选择算法对比

1. 问题描述与核心挑战 给定整数数组 nums 和整数 k,我们需要找到数组中第 k 个最大的元素。请注意,这里要求的是排序后的第 k 个最大元素,而不是第 k 个不同的元素。 这个问题看似简单,但隐藏着几个关键挑战: 当数组… · 2026/11/6 15:05:13

企业设备数字化管理:易点易动系统实践指南
企业设备数字化管理:易点易动系统实践指南

1. 设备管理在企业数字化转型中的核心价值 设备管理作为企业资产管理的重要组成部分,正在经历从传统人工记录向数字化、智能化管理的转变。在制造业、医疗、教育等行业,设备资产往往占据企业总资产的60%以上,其管理效率直接影响企业运营成本和… · 2026/11/6 15:05:13

企业元宇宙治理框架:技术实现与合规路径
企业元宇宙治理框架:技术实现与合规路径

1. 企业元宇宙治理框架的核心逻辑 企业元宇宙作为数字化转型的新阶段,其治理框架需要兼顾技术创新与合规要求。从技术架构角度看,企业元宇宙本质上是一个由数字孪生、区块链、人工智能等技术构成的复杂系统。这个系统需要解决三个核心问题:如… · 2026/11/6 14:59:51

基于CDC的MySQL实时数据同步方案实践
基于CDC的MySQL实时数据同步方案实践

1. 项目背景与核心价值 在数据驱动的业务场景中,数据库表间数据同步是个高频需求。我最近在电商订单系统中就遇到了这个问题:订单主表数据变更后,需要实时同步到统计分析表和风控表。传统的手动同步或定时任务方式存在延迟高、易出错的问题&a… · 2026/11/6 14:00:34

JSP农贸交易系统开发与智能撮合算法实践
JSP农贸交易系统开发与智能撮合算法实践

## 1. 项目概述与核心价值农贸产品交易系统是连接农产品生产端与消费端的重要数字化桥梁。这个基于JSP技术的交易平台(项目编号g3608)完整包含了程序源码、数据库设计、部署指南和开发环境配置,是一套开箱即用的农产品B2B解决方案。我在参与某… · 2026/11/6 14:00:34

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23

三菱PLC数据采集到数据库的时序设计:Python+MC协议实战
三菱PLC数据采集到数据库的时序设计:Python+MC协议实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11

ASIC主模式RTL设计:状态机与三态驱动的流片级实现
ASIC主模式RTL设计:状态机与三态驱动的流片级实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11

STM32嵌入式C++开发:GDB调试与Renode仿真实战指南
STM32嵌入式C++开发:GDB调试与Renode仿真实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码