秒杀系统设计(二):从Lua分布式锁到Redisson的进阶之路
在上一章我们用 Lua 脚本实现了一个“能用”的分布式锁,但实战一跑,问题很快暴露出来:不可重入、不可重试、锁超时释放以及主从一致性风险。表面上看只是几个角落,实际上是高并发系统里最容易出事故的地方。本篇将把视角从“自己写锁”转向“框架化落地”,引入 Redisson,并深入它的实现原理与核心源码流程,真正弄明白它为什么可靠。 一、Lua 脚本方案的四个痛点在 Redis 上用 Lua + setnx/expire 做锁的“原型”非常清爽,但代价是稳定性与可维护性的长期欠账。 第一是不可重入。单线程同一业务流程多层调用时,第一次加锁成功,第二次会被视为“抢锁”,直接失败。业务上最常见的表现就是“本来是自己持有的锁,却把自己拒之门外”。 第二是不可重试。Lua 脚本只返回成功或失败,如果失败,调用方只能自己写 while 循环 + sleep,既丑又不精确,也缺乏被唤醒的机制;线程只能靠轮询消耗 CPU。 第三是锁超时释放的风险。为了防止死锁,我们会设置过期时间。但业务耗时无法完全预测,若业务执行超时,锁会被 Redis 自动释放,其他线程趁机进入,导致并发安全失效。 第...
Spring容器中的中的对象与"代理对象"(Proxy)——及 Java 基础对象相关面试知识复习
在 Spring Boot 开发中,事务管理是核心场景之一,而事务的实现依赖于 Spring 的代理机制。这一机制初学时往往让人困惑:为何加了 @Transactional 注解的方法,调用时并非原始对象执行?带着这个问题,我们从 Spring Boot 代理对象与事务的关联入手,逐步回溯 Java SE 基础中的对象、引用、equals 方法、字符串常量池等核心知识点,打通从框架到基础的逻辑链路,帮你彻底理解底层原理与实际开发中的避坑点。 一、Spring Boot 中的对象与代理对象引入及 @Transactional 事务实践1.1 核心问题:为何事务方法需通过代理对象调用?在 Spring Boot 的 MVC 三层架构中,我们通常在 Service 层添加 @Transactional 注解实现事务管理。但很多开发者会遇到一个经典问题:同一 Service 类中,非事务方法调用事务方法时,事务失效。这一问题的根源就是 Spring 的代理机制——@Autowired 注入的 Service 实例,并非我们编写的原始类对象,而是 Spring 动态生成的代理对象。 Spr...
Redis实战:彻底攻克缓存穿透与缓存击穿
在上一篇文章中,我们探讨了缓存的更新策略及其在分布式场景下的一致性挑战。今天,我们将视角深入到高并发场景下最令人头秃的两个问题:缓存穿透与缓存击穿。 本文将结合 hm-dianping 项目实战,拆解我们是如何通过封装通用的 CacheClient 工具类,利用空值缓存、互斥锁以及逻辑过期这三把利剑,优雅地应对高并发流量冲击的。同时,文末的知识小窗还将带你深入理解 Java 范型与 JUC 并发编程的精髓。 一、 拨开云雾:理解缓存问题的本质在分布式系统中,缓存就像是数据库的一道防洪堤坝。一旦这道堤坝出现裂缝,滔天洪水(高并发流量)就会瞬间冲垮后方脆弱的数据库。 1. 缓存穿透 (Cache Penetration)问题描述:请求直接穿透了缓存层,打到了数据库,但数据库里也没这个数据。典型场景:恶意用户使用脚本,不断请求 id = -1 或不存在的 UUID。后果:Redis 命中率为 0,数据库压力激增,可能瞬间宕机。核心矛盾:数据库中不存在的数据,正常情况下不会被写入缓存,导致后续请求依然无法命中。 2. 缓存击穿 (Cache Breakdown)问题描述:一个热点 Key...
秒杀系统设计(一):从超卖事故到全局唯一ID与乐观锁
秒杀(Seckill)是电商系统中最具挑战性的业务场景之一,其核心特征是瞬时高并发。在短短几秒钟内,流量峰值可能达到平时的成百上千倍。这种场景下,系统不仅要抗住流量,更要保证数据的绝对准确(不能超卖)和业务规则的严格执行(一人一单)。 本文将作为《黑马点评》秒杀篇分析的第一章,从最基础的超卖问题入手,一步步构建全局唯一 ID,并深度辨析乐观锁与悲观锁。 一、 灾难前夜:超卖问题的诞生1. 什么是超卖?简单来说,就是卖出的商品数量超过了实际库存。例如秒杀库存只有 100 件,最终却产生了 105 个订单。这在电商业务中是严重的生产事故,可能导致平台亏损和用户投诉。 2. 为什么会超卖?从技术角度看,超卖的本质是竞态条件 (Race Condition)。在传统的多线程环境下,扣减库存通常分为两步: 查询库存:SELECT stock FROM table WHERE id = 1 扣减库存:UPDATE table SET stock = stock - 1 WHERE id = 1 这看似逻辑正确,但在高并发下: 线程 A 查询库存,发现 stock = 1。 线...
深入理解缓存更新策略:聊聊常见业务场景怎么用缓存?
在高并发系统中,缓存是提升性能的关键手段。但是,如何保证缓存与数据库的数据一致性,一直是令初学者头疼的问题。本文将深入探讨缓存更新的各种策略,帮助你在实际项目中做出正确的技术选型。 一、什么是缓存?缓存(Cache) 是一种存储技术,它将频繁访问的数据保存在读取速度更快的存储介质中,以减少对慢速存储(如数据库、磁盘)的访问次数,从而提升系统性能。 缓存的本质缓存的核心思想是空间换时间。通过在内存中保存热点数据的副本,我们可以: 减少数据库压力:避免大量请求直接打到数据库。 提升响应速度:内存读取速度远超磁盘 IO,响应时间从毫秒级降至微秒级。 提高系统吞吐量:单位时间内可以处理更多请求。 缓存的层次缓存并不只是指 Redis,它是一个广泛的概念,存在于计算机系统的各个层次: CPU 缓存:L1、L2、L3 缓存,减少对内存的访问。 浏览器缓存:缓存静态资源(如图片、CSS、JS),减少 HTTP 请求。 CDN 缓存:内容分发网络,将资源缓存到离用户更近的节点。 应用缓存:如本地内存缓存(Guava Cache、Caffeine)、分布式缓存(Redis、Memcached...
深入解析会话管理:从Cookie、Session到Redis分布式Session
大家好,我是Ea1XonCodeHou,今天开始分享一些关于经典项目:黑马点评中关于Redis深入学习与分布式内容的技术博客。在Web开发中,用户认证与会话管理是核心功能之一。随着架构从单体演进到分布式集群,会话管理方案也在不断迭代。本文主要基于Redis+Token这个新的会话管理方式深入理解从传统的Cookie、Session到现代的Token、JWT,以及如何在分布式环境下使用Redis实现高效的Session共享。 一、 核心概念详解1. Cookie定义:Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。 特点: 存储位置:客户端(浏览器)。 容量限制:通常不超过4KB。 安全性:较低,容易被拦截或篡改(虽然可以通过 HttpOnly 和 Secure 属性增强安全性)。 用途:主要用于会话状态管理(如用户登录状态)、个性化设置、浏览器行为跟踪。 2. Session定义:Session 是服务器端的一种会话技术。当用户访问服务器时,服务器会为该用户创建一个唯一的 Session 对象,并...
My first blog in hexo!
欢迎来到我的个人博客!大家好!欢迎访问我的个人博客网站。我是 Ea1XonCodeHou,很高兴能在我的个人博客与大家分享我的想法、开发路上的学习心得和技术经验。 关于我我是一名正在学习编程和技术的大学生/开发者,来自武汉大学计算机学院软件工程专业(WHU-SE)。目前就读于大三年级,对Web开发技术正在学习途中,并准备与2026上半年开始实习/求职,目前平时大部分时间正在学习优秀项目/编写个人项目/练习Leetcode算法题目。希望能多学习一些JavaWeb开发技术栈。通过这个博客,我希望能够: 利用博客记录我在后端开发学习路线的学习历程和技术心得 分享结合网课自学途中获得的开发经验 与同在自学技术求职或者志同道合的朋友们交流讨论 记录从自学到求职生活中的点点滴滴 关于这个网站这个博客网站是基于 Hexo 静态博客框架搭建的,托管在 GitHub Pages 上。选择这个技术栈的原因: 为什么选择 Hexo? 简洁高效:Hexo 是一个快速、简洁且高效的博客框架 Markdown 支持:支持 Markdown 语法,写作体验非常友好 ...