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# 1. 安装依赖yuminstall-ygcc gcc-cmake# 2. 下载Redis 7.x源码包wgethttps://download.redis.io/releases/redis-7.2.4.tar.gz# 3. 解压源码包tar-zxvfredis-7.2.4.tar.gz# 4. 编译安装cdredis-7.2.4makemakeinstallPREFIX/usr/local/redis# 5. 配置Redis复制配置文件cpredis.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-h127.0.0.1-p6379-a123456# 9. 验证启动127.0.0.1:6379pingPONG# 启动成功2.2 Redis核心数据结构实战必备Redis支持5种核心数据结构每种结构有其特定的应用场景掌握其用法是Redis实战的基础。# 1. String字符串适用于缓存、计数器、会话存储等场景# 设置值keyuser:1001, valueJSON字符串setuser:1001{id:1001,username:zhangsan,age:20}# 获取值get user:1001# 设置过期时间3600秒setex user:10013600{id:1001,username:zhangsan,age:20}# 自增计数器incr like:1001# 点赞数1# 自减decr like:1001# 点赞数-1# 2. Hash哈希适用于存储对象如用户信息、商品信息# 设置哈希值keyuser:1001字段username值zhangsanhset user:1001 username zhangsan age20# 获取单个字段值hget user:1001 username# 获取所有字段值hgetall user:1001# 删除字段hdel user:1001 age# 3. List列表适用于消息队列、最新消息列表等场景# 从左侧插入lpush message:1001helloworld# 从右侧插入rpush message:1001redis# 获取列表所有元素lrange message:10010-1# 从左侧弹出lpop message:1001# 从右侧弹出rpop message:1001# 4. Set集合适用于去重、交集、并集等场景如好友列表、标签# 添加元素sadd tag:1001javapython go# 获取所有元素smembers tag:1001# 判断元素是否存在sismember tag:1001java# 求两个集合的交集好友共同关注sinter tag:1001 tag:1002# 删除元素srem tag:1001 go# 5. Sorted Set有序集合适用于排行榜、优先级队列等场景# 添加元素score分数用于排序zadd rank:100190zhangsan85lisi95wangwu# 获取有序集合升序zrange rank:10010-1withscores# 获取有序集合降序zrevrange rank:10010-1withscores# 获取元素分数zscore rank:1001 zhangsan# 删除元素zrem rank:1001 lisi三、实战模块缓存设计与分布式锁3.1 模块1缓存设计模式实战案例缓存设计的核心是“缓存数据库热点数据”减少数据库访问压力常用的缓存设计模式包括Cache-Aside旁路缓存、Write-Through写穿透、Write-Back写回其中Cache-Aside模式最常用。// 1. Cache-Aside模式旁路缓存最常用适用于读多写少场景// 核心逻辑查询时先查缓存缓存没有则查数据库再将数据存入缓存更新时先更数据库再删缓存importredis.clients.jedis.Jedis;importcom.alibaba.fastjson.JSON;publicclassCacheAsideDemo{privatefinalJedisjedisnewJedis(127.0.0.1,6379);privatefinalUserDaouserDaonewUserDao();// 数据库操作类// 1. 查询用户信息先查缓存再查数据库publicUsergetUserById(LonguserId){Stringkeyuser:userId;// 1. 先查缓存StringuserJsonjedis.get(key);if(userJson!null){// 缓存命中返回数据returnJSON.parseObject(userJson,User.class);}// 2. 缓存未命中查数据库UseruseruserDao.selectById(userId);if(user!null){// 3. 将数据库数据存入缓存设置过期时间避免缓存雪崩jedis.setex(key,3600,JSON.toJSONString(user));}returnuser;}// 2. 更新用户信息先更数据库再删缓存publicvoidupdateUser(Useruser){// 1. 更新数据库userDao.update(user);// 2. 删除缓存避免缓存与数据库数据不一致Stringkeyuser:user.getId();jedis.del(key);}// 3. 删除用户信息先删数据库再删缓存publicvoiddeleteUser(LonguserId){userDao.deleteById(userId);Stringkeyuser:userId;jedis.del(key);}}// 2. 缓存key设计规范避免key冲突、便于管理// 规范业务模块:对象:唯一标识[:属性]// 示例// 用户模块user:1001用户信息、user:1001:orders用户订单// 商品模块product:2001商品信息、product:2001:stock商品库存// 缓存过期时间根据业务场景设置热点数据可设置1-2小时非热点数据可设置更久3.2 模块2缓存常见问题解决穿透、击穿、雪崩缓存使用过程中容易出现缓存穿透、缓存击穿、缓存雪崩三个问题若不解决会导致数据库压力剧增甚至系统崩溃本文提供针对性的解决方案。// 1. 缓存穿透查询不存在的数据缓存和数据库都没有导致每次都查数据库// 解决方案缓存空值、布隆过滤器推荐// 方案1缓存空值简单易实现适合数据量不大的场景publicUsergetUserById(LonguserId){Stringkeyuser:userId;StringuserJsonjedis.get(key);if(userJson!null){// 缓存命中包括空值returnJSON.parseObject(userJson,User.class);}// 查数据库UseruseruserDao.selectById(userId);if(user!null){jedis.setex(key,3600,JSON.toJSONString(user));}else{// 缓存空值设置较短的过期时间如60秒避免缓存占用过多空间jedis.setex(key,60,JSON.toJSONString(null));}returnuser;}// 方案2布隆过滤器适合数据量大、查询频繁的场景提前过滤不存在的keyimportcom.google.common.hash.BloomFilter;importcom.google.common.hash.Funnels;publicclassBloomFilterDemo{// 初始化布隆过滤器预计数据量100万误判率0.01privatefinalBloomFilterLongbloomFilterBloomFilter.create(Funnels.longFunnel(),1000000,0.01);// 系统启动时将所有用户ID存入布隆过滤器publicvoidinitBloomFilter(){ListLongallUserIduserDao.selectAllUserId();for(LonguserId:allUserId){bloomFilter.put(userId);}}// 查询前先通过布隆过滤器判断key是否存在publicUsergetUserById(LonguserId){// 布隆过滤器判断不存在直接返回null不查缓存和数据库if(!bloomFilter.mightContain(userId)){returnnull;}// 后续逻辑和Cache-Aside模式一致Stringkeyuser:userId;StringuserJsonjedis.get(key);if(userJson!null){returnJSON.parseObject(userJson,User.class);}UseruseruserDao.selectById(userId);if(user!null){jedis.setex(key,