Redis 7\.x实战:缓存设计与分布式锁实现

摘要:Redis作为高性能的键值对数据库,凭借其高速读写、支持多种数据结构、可持久化等特性,已成为企业级项目中缓存、分布式锁、消息队列等场景的首选工具。本文基于Redis 7.x,结合电商、微服务等实战场景,详细讲解Redis核心数据结构、缓存设计模式、缓存问题解决(缓存穿透、缓存击穿、缓存雪崩)、分布式锁实现、持久化配置等核心知识点,附完整命令与代码案例,帮助后端开发者、运维工程师快速掌握Redis实战技巧,提升系统性能与稳定性,适合Redis入门与进阶学习。

一、前言:Redis的核心价值与应用场景

Redis 7.x相比之前版本,带来了诸多优化:支持多线程IO,提升读写性能;新增Redis Functions(函数),支持自定义脚本逻辑;优化持久化机制,提升数据安全性;增强集群功能,提升可扩展性。

在企业级项目中,Redis的核心应用场景包括:数据缓存(减轻数据库压力)、分布式锁(解决微服务并发问题)、消息队列(简单的异步通信)、计数器(如点赞数、访问量)、会话存储(如用户登录会话)等。本文聚焦Redis最核心的缓存设计与分布式锁,结合实战场景,解决实际开发中的常见问题。

二、核心基础:Redis 7.x安装与核心数据结构

2.1 Redis 7.x安装(CentOS 8)

bash 复制代码
# 1. 安装依赖
yum install -y gcc gcc-c++ make

# 2. 下载Redis 7.x源码包
wget https://download.redis.io/releases/redis-7.2.4.tar.gz

# 3. 解压源码包
tar -zxvf redis-7.2.4.tar.gz

# 4. 编译安装
cd redis-7.2.4
make
make install PREFIX=/usr/local/redis

# 5. 配置Redis(复制配置文件)
cp redis.conf /usr/local/redis/conf/

# 6. 修改配置文件(/usr/local/redis/conf/redis.conf)
# 允许远程访问(注释bind 127.0.0.1)
# protected-mode no(关闭保护模式)
# daemonize yes(后台运行)
# requirepass 123456(设置密码,可选)

# 7. 启动Redis
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf

# 8. 连接Redis
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379 -a 123456

# 9. 验证启动
127.0.0.1:6379> ping
PONG # 启动成功

2.2 Redis核心数据结构(实战必备)

Redis支持5种核心数据结构,每种结构有其特定的应用场景,掌握其用法是Redis实战的基础。

bash 复制代码
# 1. String(字符串):适用于缓存、计数器、会话存储等场景
# 设置值(key=user:1001, value=JSON字符串)
set user:1001 '{"id":1001,"username":"zhangsan","age":20}'
# 获取值
get user:1001
# 设置过期时间(3600秒)
setex user:1001 3600 '{"id":1001,"username":"zhangsan","age":20}'
# 自增(计数器)
incr like:1001 # 点赞数+1
# 自减
decr like:1001 # 点赞数-1

# 2. Hash(哈希):适用于存储对象(如用户信息、商品信息)
# 设置哈希值(key=user:1001,字段=username,值=zhangsan)
hset user:1001 username zhangsan age 20
# 获取单个字段值
hget user:1001 username
# 获取所有字段值
hgetall user:1001
# 删除字段
hdel user:1001 age

# 3. List(列表):适用于消息队列、最新消息列表等场景
# 从左侧插入
lpush message:1001 "hello" "world"
# 从右侧插入
rpush message:1001 "redis"
# 获取列表所有元素
lrange message:1001 0 -1
# 从左侧弹出
lpop message:1001
# 从右侧弹出
rpop message:1001

# 4. Set(集合):适用于去重、交集、并集等场景(如好友列表、标签)
# 添加元素
sadd tag:1001 java python go
# 获取所有元素
smembers tag:1001
# 判断元素是否存在
sismember tag:1001 java
# 求两个集合的交集(好友共同关注)
sinter tag:1001 tag:1002
# 删除元素
srem tag:1001 go

# 5. Sorted Set(有序集合):适用于排行榜、优先级队列等场景
# 添加元素(score=分数,用于排序)
zadd rank:1001 90 zhangsan 85 lisi 95 wangwu
# 获取有序集合(升序)
zrange rank:1001 0 -1 withscores
# 获取有序集合(降序)
zrevrange rank:1001 0 -1 withscores
# 获取元素分数
zscore rank:1001 zhangsan
# 删除元素
zrem rank:1001 lisi

三、实战模块:缓存设计与分布式锁

3.1 模块1:缓存设计模式(实战案例)

缓存设计的核心是"缓存数据库热点数据",减少数据库访问压力,常用的缓存设计模式包括:Cache-Aside(旁路缓存)、Write-Through(写穿透)、Write-Back(写回),其中Cache-Aside模式最常用。

java 复制代码
// 1. Cache-Aside模式(旁路缓存):最常用,适用于读多写少场景
// 核心逻辑:查询时先查缓存,缓存没有则查数据库,再将数据存入缓存;更新时先更数据库,再删缓存
import redis.clients.jedis.Jedis;
import com.alibaba.fastjson.JSON;

public class CacheAsideDemo {
    private final Jedis jedis = new Jedis("127.0.0.1", 6379);
    private final UserDao userDao = new UserDao(); // 数据库操作类

    // 1. 查询用户信息(先查缓存,再查数据库)
    public User getUserById(Long userId) {
        String key = "user:" + userId;
        // 1. 先查缓存
        String userJson = jedis.get(key);
        if (userJson != null) {
            // 缓存命中,返回数据
            return JSON.parseObject(userJson, User.class);
        }
        // 2. 缓存未命中,查数据库
        User user = userDao.selectById(userId);
        if (user != null) {
            // 3. 将数据库数据存入缓存(设置过期时间,避免缓存雪崩)
            jedis.setex(key, 3600, JSON.toJSONString(user));
        }
        return user;
    }

    // 2. 更新用户信息(先更数据库,再删缓存)
    public void updateUser(User user) {
        // 1. 更新数据库
        userDao.update(user);
        // 2. 删除缓存(避免缓存与数据库数据不一致)
        String key = "user:" + user.getId();
        jedis.del(key);
    }

    // 3. 删除用户信息(先删数据库,再删缓存)
    public void deleteUser(Long userId) {
        userDao.deleteById(userId);
        String key = "user:" + userId;
        jedis.del(key);
    }
}

// 2. 缓存key设计规范(避免key冲突、便于管理)
// 规范:业务模块:对象:唯一标识[:属性]
// 示例:
// 用户模块:user:1001(用户信息)、user:1001:orders(用户订单)
// 商品模块:product:2001(商品信息)、product:2001:stock(商品库存)
// 缓存过期时间:根据业务场景设置,热点数据可设置1-2小时,非热点数据可设置更久

3.2 模块2:缓存常见问题解决(穿透、击穿、雪崩)

缓存使用过程中,容易出现缓存穿透、缓存击穿、缓存雪崩三个问题,若不解决,会导致数据库压力剧增,甚至系统崩溃,本文提供针对性的解决方案。

java 复制代码
// 1. 缓存穿透:查询不存在的数据,缓存和数据库都没有,导致每次都查数据库
// 解决方案:缓存空值、布隆过滤器(推荐)
// 方案1:缓存空值(简单易实现,适合数据量不大的场景)
public User getUserById(Long userId) {
    String key = "user:" + userId;
    String userJson = jedis.get(key);
    if (userJson != null) {
        // 缓存命中(包括空值)
        return JSON.parseObject(userJson, User.class);
    }
    // 查数据库
    User user = userDao.selectById(userId);
    if (user != null) {
        jedis.setex(key, 3600, JSON.toJSONString(user));
    } else {
        // 缓存空值,设置较短的过期时间(如60秒),避免缓存占用过多空间
        jedis.setex(key, 60, JSON.toJSONString(null));
    }
    return user;
}

// 方案2:布隆过滤器(适合数据量大、查询频繁的场景,提前过滤不存在的key)
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

public class BloomFilterDemo {
    // 初始化布隆过滤器(预计数据量100万,误判率0.01)
    private final BloomFilter<Long> bloomFilter = BloomFilter.create(
            Funnels.longFunnel(),
            1000000,
            0.01
    );

    // 系统启动时,将所有用户ID存入布隆过滤器
    public void initBloomFilter() {
        List<Long> allUserId = userDao.selectAllUserId();
        for (Long userId : allUserId) {
            bloomFilter.put(userId);
        }
    }

    // 查询前先通过布隆过滤器判断key是否存在
    public User getUserById(Long userId) {
        // 布隆过滤器判断不存在,直接返回null,不查缓存和数据库
        if (!bloomFilter.mightContain(userId)) {
            return null;
        }
        // 后续逻辑和Cache-Aside模式一致
        String key = "user:" + userId;
        String userJson = jedis.get(key);
        if (userJson != null) {
            return JSON.parseObject(userJson, User.class);
        }
        User user = userDao.selectById(userId);
        if (user != null) {
            jedis.setex(key, 
相关推荐
Juicedata5 小时前
分布式架构下配额设计:JuiceFS 的实现与典型案例
分布式·架构
NCIN EXPE10 小时前
redis 使用
数据库·redis·缓存
hERS EOUS11 小时前
nginx 代理 redis
运维·redis·nginx
NoSi EFUL12 小时前
redis存取list集合
windows·redis·list
Deepincode13 小时前
Redis源码探究系列—SDS 扩容策略与内存预分配机制
redis
程序员老邢13 小时前
【技术底稿 19】Redis7 集群密码配置 + 权限锁死 + 磁盘占满连锁故障真实排查全记录
java·服务器·经验分享·redis·程序人生·微服务
coNh OOSI15 小时前
Redis——Windows安装
数据库·windows·redis
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.15 小时前
Redis主从复制配置全攻略
数据库·redis·笔记