Redis高级用法

可以。你如果已经掌握了 Spring Boot + MyBatis/MyBatis-Plus + Redis 基础 CRUD,那么 Redis 真正值得学的是它在项目中的"高级用法"。

我建议你不要把 Redis 理解成简单的 key-value 缓存,而是把它看成:

缓存 + 分布式锁 + 分布式计数器 + 延迟队列 + 排行榜 + 限流器 + Session/Token 存储 + 消息系统 + 分布式协调组件

下面我按照 Spring Boot 实际项目开发 的角度,从基础一直讲到高级。


一、Spring Boot 中 Redis 的整体架构

在 Spring Boot 中,最常见的是:

text 复制代码
Controller
    ↓
Service
    ↓
RedisTemplate
    ↓
Spring Data Redis
    ↓
Lettuce
    ↓
Redis Server

现在 Spring Boot 默认通常使用 Lettuce 作为 Redis 客户端。

你会经常接触:

java 复制代码
RedisTemplate<String, Object>

以及:

java 复制代码
StringRedisTemplate

二、Redis 在 Spring Boot 中最核心的几个使用场景

实际开发中,可以把 Redis 用法归纳成:

场景 Redis 数据结构
缓存 String
对象缓存 String
Hash 对象 Hash
登录 Token String
验证码 String
计数器 String
点赞 Set
共同关注 Set
排行榜 ZSet
延迟任务 ZSet
消息队列 List / Stream
分布式锁 String
限流 String / Lua
布隆过滤器 Bitmap / RedisBloom
UV 统计 HyperLogLog
地理位置 GEO
实时统计 Bitmap / HyperLogLog

所以学习 Redis 高级用法,本质上就是:

掌握 Redis 数据结构 + Spring Data Redis + Lua + 分布式思想。


三、RedisTemplate 高级配置

首先建议项目中不要直接使用默认的:

java 复制代码
RedisTemplate<Object, Object>

而是自己配置序列化。

例如:

java 复制代码
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory connectionFactory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();

        template.setConnectionFactory(connectionFactory);

        // Key
        StringRedisSerializer stringSerializer =
                new StringRedisSerializer();

        // Value
        GenericJackson2JsonRedisSerializer jsonSerializer =
                new GenericJackson2JsonRedisSerializer();

        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);

        template.setValueSerializer(jsonSerializer);
        template.setHashValueSerializer(jsonSerializer);

        template.afterPropertiesSet();

        return template;
    }
}

这样 Redis 中看到的数据会比较直观:

text 复制代码
user:10001

Value:

json 复制代码
{
    "id": 10001,
    "username": "zhangsan",
    "age": 20
}

而不是:

text 复制代码
\xac\xed\x00\x05...

四、不要把 Redis 当数据库直接用

这是 Redis 初学者非常容易犯的错误。

比如:

java 复制代码
redisTemplate.opsForValue()
        .set("user:10001", user);

然后所有业务都从 Redis 获取用户。

这通常不是最佳方案。

更合理的是:

text 复制代码
MySQL
   ↓
真实数据

Redis
   ↓
热点数据缓存

也就是:

MySQL 是数据源,Redis 是高速缓存。


五、Redis 最经典的高级用法:缓存

假设:

java 复制代码
public User getUserById(Long id) {
    return userMapper.selectById(id);
}

每次查询:

text 复制代码
Controller
 ↓
Service
 ↓
MySQL

如果访问量很大:

text 复制代码
10000 QPS
 ↓
MySQL

数据库压力会非常大。

所以改成:

text 复制代码
Controller
 ↓
Service
 ↓
Redis
 ↓
Redis有数据 → 返回

Redis没有
 ↓
MySQL
 ↓
写入Redis
 ↓
返回

代码:

java 复制代码
public User getUserById(Long id) {

    String key = "user:" + id;

    User user = (User) redisTemplate
            .opsForValue()
            .get(key);

    if (user != null) {
        return user;
    }

    user = userMapper.selectById(id);

    if (user != null) {
        redisTemplate.opsForValue()
                .set(key, user, 30, TimeUnit.MINUTES);
    }

    return user;
}

这就是最经典的:

Cache Aside Pattern(旁路缓存)


六、缓存更新问题

假设:

text 复制代码
MySQL:

user.name = 张三

Redis:

text 复制代码
user:1
{
    "name": "张三"
}

现在修改:

java 复制代码
userMapper.updateById(user);

如果不处理 Redis:

text 复制代码
MySQL
张三 → 李四

Redis
张三

出现:

缓存和数据库数据不一致

所以更新数据的时候通常:

java 复制代码
@Transactional
public void updateUser(User user) {

    userMapper.updateById(user);

    redisTemplate.delete("user:" + user.getId());
}

下次查询:

text 复制代码
Redis没有
 ↓
MySQL查询李四
 ↓
写入Redis

七、为什么推荐"删除缓存"而不是"更新缓存"

很多人会写:

java 复制代码
userMapper.updateById(user);

redisTemplate.opsForValue()
        .set("user:" + user.getId(), user);

看起来没问题。

但并发情况下可能出现:

text 复制代码
线程A:
更新MySQL

线程B:
查询MySQL旧数据

线程A:
更新Redis新数据

线程B:
把旧数据写入Redis

最终:

text 复制代码
MySQL:新数据
Redis:旧数据

所以实际项目中经常采用:

text 复制代码
更新数据库
 ↓
删除缓存

而不是:

text 复制代码
更新数据库
 ↓
更新缓存

八、缓存穿透

这是 Redis 面试非常重要的知识点。

比如:

http 复制代码
GET /user/999999999

数据库不存在。

流程:

text 复制代码
Redis → 没有
 ↓
MySQL → 没有
 ↓
返回

攻击者不断请求:

text 复制代码
/user/999999999
/user/999999998
/user/999999997
...

每次 Redis 都没有。

于是:

text 复制代码
大量请求
 ↓
Redis
 ↓
MySQL
 ↓
MySQL压力巨大

这叫:

缓存穿透


九、解决缓存穿透:缓存空对象

例如:

java 复制代码
User user = userMapper.selectById(id);

if (user == null) {

    redisTemplate.opsForValue()
            .set(
                "user:" + id,
                "",
                60,
                TimeUnit.SECONDS
            );

    return null;
}

这样:

text 复制代码
第一次请求
Redis没有
 ↓
MySQL没有
 ↓
Redis写入空值

第二次:

text 复制代码
Redis
 ↓
发现空值
 ↓
直接返回

十、缓存击穿

假设:

text 复制代码
商品ID:10001

Redis:
product:10001

这是一个超级热门商品。

突然:

text 复制代码
Redis过期

与此同时:

text 复制代码
10000个请求
 ↓
Redis全部miss
 ↓
10000个请求同时访问MySQL

这就是:

缓存击穿

也叫:

热点 Key 失效问题


十一、解决缓存击穿:互斥锁

核心思想:

text 复制代码
Redis miss
 ↓
抢锁
 ↓
只有一个线程查询MySQL
 ↓
写Redis
 ↓
释放锁

其他线程:

text 复制代码
Redis miss
 ↓
抢不到锁
 ↓
等待
 ↓
再次查询Redis

十二、Redis 分布式锁

最简单的 Redis 锁:

java 复制代码
Boolean success = redisTemplate.opsForValue()
        .setIfAbsent(
                "lock:user:10001",
                "1",
                10,
                TimeUnit.SECONDS
        );

这里:

java 复制代码
setIfAbsent()

对应 Redis:

text 复制代码
SET key value NX EX 10

含义:

text 复制代码
NX:
key不存在才设置

EX 10:
10秒过期

如果:

java 复制代码
success == true

说明抢锁成功。


十三、分布式锁为什么一定要设置过期时间

错误:

java 复制代码
redisTemplate.opsForValue()
        .setIfAbsent("lock", "1");

如果 JVM:

text 复制代码
突然宕机

锁就可能永远存在。

导致:

text 复制代码
其他线程
 ↓
永远抢不到锁

所以:

java 复制代码
setIfAbsent(
    key,
    value,
    10,
    TimeUnit.SECONDS
)

是非常重要的。


十四、为什么简单 Redis 锁还不够

假设:

text 复制代码
线程A
 ↓
获取锁
value = A

然后:

text 复制代码
线程A执行很久

锁:

text 复制代码
10秒过期

于是:

text 复制代码
线程B
 ↓
获取锁
value = B

这时候:

text 复制代码
线程A执行结束
 ↓
delete(lock)

问题来了。

A 删除的是:

text 复制代码
B的锁

所以释放锁不能简单:

java 复制代码
redisTemplate.delete(lockKey);

十五、正确释放锁:Value 唯一标识

例如:

java 复制代码
String lockValue = UUID.randomUUID().toString();

Boolean success = redisTemplate.opsForValue()
        .setIfAbsent(
                lockKey,
                lockValue,
                10,
                TimeUnit.SECONDS
        );

释放时:

text 复制代码
检查:

Redis中的value == 当前线程value

如果相同:
    删除

但是:

检查 + 删除必须是原子操作。

所以通常使用 Lua。


十六、Lua 释放 Redis 锁

Lua:

lua 复制代码
if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
else
    return 0
end

Spring Boot:

java 复制代码
DefaultRedisScript<Long> script =
        new DefaultRedisScript<>();

script.setScriptText("""
    if redis.call('get', KEYS[1]) == ARGV[1] then
        return redis.call('del', KEYS[1])
    else
        return 0
    end
""");

script.setResultType(Long.class);

执行:

java 复制代码
redisTemplate.execute(
        script,
        Collections.singletonList(lockKey),
        lockValue
);

这就是 Redis 高级开发里面非常重要的知识:

Lua + Redis 保证原子性。


十七、实际项目中推荐 Redisson

如果你的项目需要大量使用:

  • 分布式锁
  • 可重入锁
  • 看门狗
  • 公平锁
  • 读写锁
  • 信号量
  • CountDownLatch
  • 分布式集合

那么不要自己手写全部 Redis 锁。

可以使用:

Redisson

例如:

java 复制代码
RLock lock = redissonClient.getLock("lock:user:10001");

try {

    lock.lock();

    // 业务代码

} finally {

    lock.unlock();
}

代码非常简单。

Redisson 会帮你处理很多复杂问题。


十八、Redisson 看门狗机制

这是 Redis 分布式锁非常重要的一个高级知识。

假设:

java 复制代码
lock.lock();

业务执行:

text 复制代码
30秒

如果锁只有:

text 复制代码
10秒

就会出现:

text 复制代码
10秒
 ↓
锁自动过期
 ↓
业务还没执行完

Redisson 有:

Watch Dog 看门狗机制

会自动续期:

text 复制代码
获取锁
 ↓
30秒
 ↓
续期
 ↓
30秒
 ↓
续期
 ↓
业务结束
 ↓
释放锁

所以实际生产项目中:

分布式锁优先考虑 Redisson,而不是自己手搓。


十九、缓存雪崩

假设:

text 复制代码
100万个缓存

全部设置:

text 复制代码
30分钟

然后:

text 复制代码
10:30
 ↓
大量缓存同时过期

结果:

text 复制代码
大量请求
 ↓
Redis miss
 ↓
MySQL
 ↓
数据库瞬间压力巨大

这叫:

缓存雪崩


二十、解决缓存雪崩

最常见的方法:

1. TTL 加随机值

不要:

java 复制代码
30分钟

而是:

java 复制代码
30分钟 + 随机0~10分钟

例如:

java 复制代码
long ttl = 30 + ThreadLocalRandom.current()
        .nextLong(10);

redisTemplate.opsForValue()
        .set(key, value, ttl, TimeUnit.MINUTES);

这样:

text 复制代码
A:30分钟
B:34分钟
C:37分钟
D:31分钟
E:39分钟

不会同时失效。


二十一、缓存预热

如果你知道:

text 复制代码
晚上8点

会有大量用户访问:

text 复制代码
热门课程
热门商品
热门文章

可以提前:

text 复制代码
MySQL
 ↓
Redis

例如项目启动:

java 复制代码
@Component
public class CacheWarmUp {

    @PostConstruct
    public void init() {

        // 查询热门数据

        // 写入 Redis
    }
}

或者通过:

text 复制代码
定时任务
消息队列
后台管理系统

进行缓存预热。


二十二、Redis Hash

如果存储用户信息:

text 复制代码
user:10001

可以使用 Hash:

java 复制代码
redisTemplate.opsForHash()
        .put("user:10001", "name", "张三");

redisTemplate.opsForHash()
        .put("user:10001", "age", 20);

Redis:

text 复制代码
user:10001

name = 张三
age = 20
gender = 男

获取:

java 复制代码
redisTemplate.opsForHash()
        .get("user:10001", "name");

适合:

一个对象里面多个字段,并且可能只修改部分字段。


二十三、Redis Set

Set 最大特点:

元素唯一

例如用户点赞:

text 复制代码
article:10001:likes

加入:

java 复制代码
redisTemplate.opsForSet()
        .add("article:10001:likes", userId);

判断点赞:

java 复制代码
redisTemplate.opsForSet()
        .isMember("article:10001:likes", userId);

取消:

java 复制代码
redisTemplate.opsForSet()
        .remove("article:10001:likes", userId);

非常适合:

text 复制代码
点赞
收藏
关注
标签
黑名单

二十四、Set 的高级用法:共同关注

例如:

text 复制代码
张三关注:
A
B
C
D

李四关注:
B
C
E
F

求共同关注:

java 复制代码
redisTemplate.opsForSet()
        .intersect(
            "user:zhangsan:follow",
            "user:lisi:follow"
        );

结果:

text 复制代码
B
C

这就是 Redis Set 很强大的地方。


二十五、Redis ZSet:排行榜

ZSet:

text 复制代码
member
score

例如游戏积分:

text 复制代码
Tom     1000
Jack    900
Lucy    800

添加:

java 复制代码
redisTemplate.opsForZSet()
        .add("rank:game", "Tom", 1000);

查询排行榜:

java 复制代码
redisTemplate.opsForZSet()
        .reverseRange("rank:game", 0, 9);

就是:

text 复制代码
Top 10

非常适合:

text 复制代码
积分排行榜
销量排行榜
热度排行榜
阅读量排行榜
贡献排行榜

二十六、ZSet 还能做延迟队列

这是一个很重要的高级用法。

比如:

text 复制代码
订单创建
 ↓
30分钟未支付
 ↓
自动取消订单

可以:

java 复制代码
long executeTime =
        System.currentTimeMillis()
        + 30 * 60 * 1000;

redisTemplate.opsForZSet()
        .add(
            "order:delay",
            orderId,
            executeTime
        );

Redis:

text 复制代码
order:delay

ORDER1001 → 176....
ORDER1002 → 176....
ORDER1003 → 176....

定时扫描:

java 复制代码
Set<Object> orders =
        redisTemplate.opsForZSet()
                .rangeByScore(
                    "order:delay",
                    0,
                    System.currentTimeMillis()
                );

拿到到期订单:

text 复制代码
ORDER1001
ORDER1002

然后:

text 复制代码
取消订单

二十七、但是生产环境不一定推荐自己实现延迟队列

因为:

text 复制代码
多个服务实例
 ↓
同时扫描

可能导致:

text 复制代码
同一个任务
 ↓
被多个服务执行

所以需要:

text 复制代码
分布式锁

或者:

text 复制代码
Redis Stream
RabbitMQ
RocketMQ
Kafka

等专业消息系统。


二十八、Redis List

List 可以实现简单队列:

java 复制代码
redisTemplate.opsForList()
        .rightPush("queue", message);

消费:

java 复制代码
redisTemplate.opsForList()
        .leftPop("queue");

结构:

text 复制代码
生产者
 ↓
Redis List
 ↓
消费者

适合简单任务。

但如果要求:

  • 消息确认
  • 消费者组
  • 消息重试
  • 消费进度
  • 消息持久化

更推荐:

Redis Stream


二十九、Redis Stream

Redis Stream 是 Redis 5.0 引入的消息结构。

例如:

text 复制代码
order-stream

生产:

java 复制代码
redisTemplate.opsForStream()
        .add(
            StreamRecords.newRecord()
                .in("order-stream")
                .ofMap(Map.of(
                    "orderId", "10001"
                ))
        );

消费者组:

text 复制代码
order-group

消费者:

text 复制代码
consumer-1
consumer-2
consumer-3

可以实现:

text 复制代码
消息队列
 ↓
消费者组
 ↓
多个消费者

比 List 更适合复杂消息处理。


三十、Redis 计数器

例如文章阅读量:

text 复制代码
article:10001:views

每访问一次:

java 复制代码
redisTemplate.opsForValue()
        .increment("article:10001:views");

Redis:

text 复制代码
10001

然后:

text 复制代码
10002

非常快。

适合:

text 复制代码
阅读量
点赞量
下载量
访问量
在线人数

三十一、Redis 限流

比如:

text 复制代码
登录接口

要求:

一个 IP 1分钟最多请求10次。

可以:

text 复制代码
login:limit:127.0.0.1

使用:

java 复制代码
Long count = redisTemplate.opsForValue()
        .increment(key);

if (count == 1) {
    redisTemplate.expire(
        key,
        1,
        TimeUnit.MINUTES
    );
}

if (count > 10) {
    throw new RuntimeException("请求过于频繁");
}

这就是最简单的:

固定窗口限流


三十二、固定窗口限流的问题

比如:

text 复制代码
12:00:59
请求10次

12:01:00
又请求10次

短短2秒:

text 复制代码
20次请求

所以更高级的限流方式有:

text 复制代码
固定窗口
滑动窗口
令牌桶
漏桶

生产环境可以考虑:

Redisson RateLimiter

例如:

java 复制代码
RRateLimiter limiter =
        redissonClient.getRateLimiter("api:limit");

limiter.trySetRate(
        RateType.OVERALL,
        100,
        1,
        RateIntervalUnit.SECONDS
);

意思:

text 复制代码
整个系统
1秒
最多100次

三十三、Redis Bitmap

Bitmap 非常适合:

签到

例如:

text 复制代码
用户10001
2026年8月

每天一个 bit:

text 复制代码
1 0 1 1 0 1 ...

代表:

text 复制代码
1号:签到
2号:没签到
3号:签到
4号:签到

可以:

java 复制代码
redisTemplate.opsForValue()
        .setBit(
            "sign:10001:202608",
            0,
            true
        );

查询:

java 复制代码
redisTemplate.opsForValue()
        .getBit(
            "sign:10001:202608",
            0
        );

非常节省空间。


三十四、Redis HyperLogLog

如果你要统计:

今天有多少独立用户访问网站?

普通 Set:

text 复制代码
user1
user2
user3
...

如果:

text 复制代码
1000万用户

Set 占用内存会比较大。

HyperLogLog:

java 复制代码
redisTemplate.opsForHyperLogLog()
        .add(
            "uv:20260825",
            userId
        );

统计:

java 复制代码
redisTemplate.opsForHyperLogLog()
        .size("uv:20260825");

特点:

空间占用极小,但结果是近似值。

所以:

text 复制代码
UV统计

非常适合。


三十五、Redis GEO

Redis 可以存储地理位置。

例如:

text 复制代码
商家
经度
纬度

然后查询:

我附近5公里有哪些商家?

Redis GEO 可以完成。

例如:

text 复制代码
餐厅
酒店
充电桩
附近的人

等场景。


三十六、Spring Cache

如果你使用 Spring Boot,实际上还有一种非常重要的方式:

java 复制代码
@Cacheable

例如:

java 复制代码
@Cacheable(
    value = "user",
    key = "#id"
)
public User getUser(Long id) {

    return userMapper.selectById(id);
}

第一次:

text 复制代码
Redis没有
 ↓
执行方法
 ↓
MySQL
 ↓
自动缓存

第二次:

text 复制代码
Redis
 ↓
直接返回

这就是:

Spring Cache 抽象


三十七、@CacheEvict

更新用户:

java 复制代码
@CacheEvict(
    value = "user",
    key = "#user.id"
)
public void updateUser(User user) {

    userMapper.updateById(user);
}

执行:

text 复制代码
更新数据库
 ↓
删除Redis缓存

三十八、@CachePut

如果你希望:

更新数据库以后,同时更新缓存

可以:

java 复制代码
@CachePut(
    value = "user",
    key = "#user.id"
)
public User updateUser(User user) {

    userMapper.updateById(user);

    return user;
}

但是前面说过:

并发场景下缓存更新存在一致性问题。

所以实际项目还是需要根据业务决定。


三十九、缓存一致性高级方案

真正复杂的系统会遇到:

text 复制代码
MySQL
Redis
MQ

之间的数据一致性问题。

常见方案:

方案一

text 复制代码
更新MySQL
 ↓
删除Redis

简单。


方案二

text 复制代码
更新MySQL
 ↓
发送MQ消息
 ↓
删除Redis

适合异步场景。


方案三

text 复制代码
MySQL Binlog
 ↓
Canal / Debezium
 ↓
Redis

这样:

text 复制代码
MySQL发生变化
 ↓
监听Binlog
 ↓
同步Redis

大型系统经常会使用这种思路。


四十、Redis Pipeline

假设你需要执行:

text 复制代码
1000次Redis操作

普通:

text 复制代码
请求
 ↓
Redis
 ↓
返回

请求
 ↓
Redis
 ↓
返回

会产生大量网络 RTT。

Pipeline:

text 复制代码
客户端
 ↓↓↓↓↓
Redis

一次发送大量命令。

Spring:

java 复制代码
redisTemplate.executePipelined(
    new SessionCallback<Object>() {

        @Override
        public Object execute(
                RedisOperations operations) {

            for (int i = 0; i < 1000; i++) {

                operations.opsForValue()
                    .set("key:" + i, i);
            }

            return null;
        }
    }
);

适合:

text 复制代码
批量读
批量写
缓存预热
数据迁移

四十一、Redis Transaction

Redis 也支持事务:

text 复制代码
MULTI
 ↓
命令1
命令2
命令3
 ↓
EXEC

Spring:

java 复制代码
redisTemplate.execute(
    new SessionCallback<Object>() {

        @Override
        public Object execute(
                RedisOperations operations) {

            operations.multi();

            operations.opsForValue()
                    .set("a", "1");

            operations.opsForValue()
                    .set("b", "2");

            return operations.exec();
        }
    }
);

但要注意:

Redis Transaction 和 MySQL Transaction 不是一个概念。

Redis 事务主要解决:

多个 Redis 命令按顺序执行,不被其他客户端插入。

它并不提供 MySQL 那种完整的回滚机制。


四十二、Lua Script

Redis 高级开发非常重要。

比如:

text 复制代码
判断库存
 ↓
扣库存
 ↓
记录订单

如果拆成:

java 复制代码
getStock();

decreaseStock();

record();

并发情况下可能出现问题。

Lua 可以:

lua 复制代码
local stock = redis.call('get', KEYS[1])

if tonumber(stock) > 0 then
    redis.call('decr', KEYS[1])
    return 1
end

return 0

Redis 执行 Lua:

text 复制代码
整个脚本
 ↓
Redis内部原子执行

所以:

复杂 Redis 原子操作,Lua 是核心武器。


四十三、库存扣减

例如秒杀:

text 复制代码
库存100

1000个人同时购买。

不能:

java 复制代码
Integer stock = getStock();

if (stock > 0) {
    decrement();
}

因为:

text 复制代码
线程A:100
线程B:100
线程C:100

大家都判断:

text 复制代码
stock > 0

然后一起扣。

所以应该使用:

text 复制代码
Lua

一次完成:

text 复制代码
判断库存
+
扣库存

四十四、秒杀系统 Redis 架构

典型架构:

text 复制代码
              Nginx
                ↓
          Spring Boot
                ↓
          Redis预扣库存
                ↓
             MQ
                ↓
          异步创建订单
                ↓
             MySQL

Redis:

text 复制代码
商品库存
用户是否购买
秒杀资格
限流

MQ:

text 复制代码
异步削峰

MySQL:

text 复制代码
最终订单数据

这就是 Redis 在高并发系统中的经典应用。


四十五、Redis 防止重复提交

例如:

text 复制代码
用户提交考试

前端可能连续点击:

text 复制代码
提交
提交
提交

可以:

text 复制代码
submit:exam:userId:examId

第一次:

java 复制代码
setIfAbsent()

成功:

text 复制代码
允许提交

第二次:

text 复制代码
已经存在
 ↓
拒绝

你的 IELTS 平台这种考试提交、订单提交、任务提交场景都非常适合这个方案。


四十六、Redis Token 管理

登录后:

text 复制代码
token
 ↓
Redis

例如:

text 复制代码
login:token:abc123

Value:

json 复制代码
{
    "userId": 10001,
    "username": "zhangsan",
    "role": "student"
}

然后:

text 复制代码
请求
 ↓
Authorization
 ↓
Token
 ↓
Redis
 ↓
用户信息

这样可以实现:

text 复制代码
Token过期
强制下线
踢人
单点登录
多端登录控制

四十七、Redis 实现单点登录

例如:

text 复制代码
用户A
 ↓
PC
 ↓
token1

用户A
 ↓
手机
 ↓
token2

Redis:

text 复制代码
user:10001:tokens

token1
token2

如果要求:

同一用户只能登录一个设备。

则:

text 复制代码
user:10001:token

直接保存当前 Token。

新设备登录:

text 复制代码
生成token2
 ↓
覆盖token1

token1 再访问:

text 复制代码
Redis查询
 ↓
token不一致
 ↓
登录失效

四十八、Redis Key 设计非常重要

生产项目中不要随便:

text 复制代码
user
user1
user2

建议:

text 复制代码
业务:对象:标识

例如:

text 复制代码
user:10001
user:10001:profile

article:10001
article:10001:views
article:10001:likes

exam:10001
exam:10001:submit:user:20001

order:10001
order:10001:status

lock:order:10001

这样非常容易维护。


四十九、Redis TTL 一定要合理

不要:

java 复制代码
set(key, value);

然后永不过期。

否则:

text 复制代码
Redis
 ↓
Key越来越多
 ↓
内存越来越大

一般缓存:

text 复制代码
5分钟
30分钟
1小时
1天

根据业务设计。


五十、Redis 内存淘汰策略

Redis 内存满了怎么办?

常见策略:

text 复制代码
noeviction
allkeys-lru
volatile-lru
allkeys-lfu
volatile-lfu
allkeys-random
volatile-random

其中项目里比较值得理解:

LRU

Least Recently Used:

最近最少使用。

LFU

Least Frequently Used:

最不经常使用。

如果你的系统是典型:

text 复制代码
热门数据
+
大量冷数据

LFU 通常非常值得考虑。


五十一、Redis 持久化

Redis 虽然主要用于缓存,但它也支持持久化。

主要两个:

text 复制代码
RDB
AOF

RDB

定时生成快照:

text 复制代码
Redis
 ↓
dump.rdb

优点:

text 复制代码
文件小
恢复快

缺点:

text 复制代码
可能丢失最后一次快照之后的数据

五十二、AOF

AOF:

text 复制代码
记录写命令

例如:

text 复制代码
SET user:1 Tom
INCR counter
DEL user:2

Redis 重启:

text 复制代码
读取AOF
 ↓
重新执行命令

优点:

text 复制代码
数据更完整

缺点:

text 复制代码
文件更大
恢复速度相对慢

生产环境经常:

text 复制代码
RDB + AOF

一起使用。


五十三、Redis 主从复制

架构:

text 复制代码
        Master
        /    \
       /      \
 Slave1       Slave2

Master:

text 复制代码

Slave:

text 复制代码

可以:

text 复制代码
读写分离

五十四、Redis Sentinel

如果 Master 挂了:

text 复制代码
Master
  X

谁来接管?

Sentinel:

text 复制代码
Sentinel
 ↓
监控Master
 ↓
发现Master挂掉
 ↓
选择Slave
 ↓
提升为Master

实现:

Redis 高可用


五十五、Redis Cluster

如果单台 Redis:

text 复制代码
内存不够

可以:

text 复制代码
Redis Cluster

例如:

text 复制代码
Node1
Node2
Node3
Node4
Node5
Node6

数据根据:

text 复制代码
Hash Slot

分布到不同节点。

例如:

text 复制代码
keyA → Node1
keyB → Node3
keyC → Node5

这样可以:

横向扩展 Redis。


五十六、Spring Boot + Redis Cluster

Spring Boot 一般只需要配置:

yaml 复制代码
spring:
  data:
    redis:
      cluster:
        nodes:
          - 192.168.1.101:6379
          - 192.168.1.102:6379
          - 192.168.1.103:6379

Lettuce 会负责:

text 复制代码
Key
 ↓
计算 Slot
 ↓
找到对应节点

一个完整的 Spring Boot Redis 技术体系

你可以把它记成这张图:

text 复制代码
                    Redis
                      │
        ┌─────────────┼─────────────┐
        ↓             ↓             ↓
      缓存           并发          数据结构
        │             │             │
   Spring Cache     分布式锁      String
   Cache Aside      Redisson       Hash
   穿透             Lua            List
   击穿             看门狗         Set
   雪崩                            ZSet
        │                           │
        ↓                           ↓
    一致性                      排行榜
    Binlog                      延迟队列
    MQ                          Bitmap
                                GEO
                                HyperLogLog
                                Stream
        │
        └──────────────┬──────────────┐
                       ↓              ↓
                     高并发           高可用
                       │              │
                     限流          Sentinel
                     秒杀          Cluster
                     库存          主从
                     削峰
相关推荐
paopaokaka_luck1 小时前
基于springboot3+vue3的车间生产管理系统(Echarts图形化分析、BI报表)
java·前端·spring boot·学习·echarts
摇滚侠4 小时前
《SpringBoot 3:入门与应用实战》第 7 章 AOP 思想与实现 阅读笔记 13
java·spring boot·笔记
FYKJ_20104 小时前
springboot网上购书商城---附源码15749
java·spring boot·后端·python·spark·django·php
爱学堂IT分享4 小时前
码神之路-Netty-从零实现RPC框架+SpringBoot实战项目教程
spring boot·网络协议·rpc
evans在进步5 小时前
Spring Boot 启动流程与 @SpringBootApplication 核心原理详解
java·spring boot·后端
fatcoder5 小时前
玩转 Redis · Set 篇
前端·redis·后端
摇滚侠5 小时前
《SpringBoot 3:入门与应用实战》第 6 章 Spring Boot 最佳实践 阅读笔记 12
android·spring boot·笔记
FfHUCisI5 小时前
Golang Redis 分布式锁
redis·分布式·golang