项目概述
本项目基于 SpringBoot 构建,采用前后端分离架构。核心目标是模拟大众点评业务场景,重点解决高并发下的性能瓶颈。技术栈涵盖 SpringBoot、MyBatis-Plus、MySQL、Redis 集群以及 RabbitMQ 消息队列。
主要功能模块包括短信登录、商户查询缓存、优惠券秒杀、附近商户搜索、UV 统计、用户签到、好友关注及达人探店等。其中分布式锁、缓存一致性策略及异步处理是贯穿项目的关键技术点。
会话管理与权限控制
Redis 替代 Session 的必要性
在集群部署模式下,多台 Tomcat 服务器并不共享内存中的 Session 存储空间。当请求被负载均衡切换到不同节点时,会导致用户状态丢失。因此,我们采用 Redis 集中存储用户信息,以 Token 作为唯一 Key 值。
Token 机制流程:
- 用户注册或登录后,生成随机 Token 存入 Redis。
- 客户端在后续请求中携带该 Token。
- 服务端拦截器校验 Token 有效性,并刷新过期时间。
拦截器分层设计
系统设置了双层拦截器以实现职责分离与性能优化:
- 第一层(全局处理):负责获取 Token、查询 Redis 中的用户信息、将用户数据存入 ThreadLocal,并统一刷新 Token 有效期。这确保了所有请求都能获取到当前用户上下文。
- 第二层(业务验证):专注于特定路径的登录校验。如果路径需要登录但用户未通过验证,直接拦截。
这种设计避免了在每个方法中重复查询 Redis,同时保证了非登录接口不会无谓地消耗资源。
缓存一致性与常见问题
Cache Aside 模式
为了保证数据库与缓存的一致性,我们采用 Cache Aside 模式。更新数据时,先更新数据库,再删除缓存。对于读操作,若缓存未命中则回源数据库并回填缓存。
在高并发写场景下,使用 Redisson 实现的读写锁来保证线程安全。读操作加共享锁,允许读读不互斥;写操作加排他锁,确保读写互斥,避免脏数据产生。
缓存穿透、雪崩与击穿
1. 缓存穿透
指大量请求访问数据库中不存在的数据,导致缓存无法命中,压力直达数据库。
解决方案:
- 参数校验:如 ID 必须为长整型,非法请求直接返回。
- 布隆过滤器:提前将有效 ID 存入过滤器,过滤掉无效请求。
- 缓存空值:对查询结果为空的请求,也缓存一个短过期的空值对象。
2. 缓存雪崩
大量 Key 在同一时刻失效,导致瞬间流量冲击数据库。
解决方案:
- 随机过期时间:在基础过期时间上增加随机偏移量,避免集体失效。
- 热点数据预热:提前将高频数据加载至缓存。
- 限流降级:配合熔断机制保护数据库。
3. 缓存击穿
热点 Key 失效时,大量并发请求同时访问数据库。
解决方案:
- 互斥锁:利用 Redis
setnx实现分布式锁,同一时刻只允许一个线程重建缓存。注意设置合理的锁超时时间,防止死锁。 - 逻辑过期:不设置物理过期时间,而是在数据结构中维护逻辑过期字段。后台异步线程重建缓存,主线程直接返回旧数据。此方案牺牲空间换取时间,适用于读多写少的热点场景。
高并发秒杀方案
资格预检与原子性
秒杀的核心在于库存扣减的准确性。我们使用 Redis + Lua 脚本实现资格预检。Lua 脚本在 Redis 中是原子执行的,能够一次性完成库存判断、用户去重、扣减库存等操作,避免了多线程竞态条件。


