尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Java程序员一周搞定Redis:从命令到分布式锁的实战路线

Java程序员一周搞定Redis:从命令到分布式锁的实战路线 又一个周末我在群里看到有人在问“Java程序员怎么用一周把Redis捡起来”。底下回复五花八门有让直接刷面试题的有让去看源码的还有让先去背两万字命令文档的。看得我直摇头——这套路我太熟了当年就是这么劝退自己的。说句实在话一周时间想成为Redis专家不现实但对一个写过CRUD、用过缓存、被分布式问题折腾过的Java后端来说一周从“会用”到“会选型、会避坑、会排查”完全做得到。这篇东西就是给这类Java程序员准备的。我把一周的路线拆成五个阶段从命令行手感、Java客户端集成、核心场景落地、可靠性兜底一直到最后的线上排查。不走弯路不堆术语每个阶段都有可以直接抄的配置和代码。你能得到什么一套经过验证的学习路径一套能应对大多数缓存场景的代码模板以及一堆常规文档里压根不会写的踩坑体验。1. 第一天的核心任务先忘掉各种注解把Redis当成一个有网络的HashMapJava程序员上手Redis最容易犯的毛病就是跳过了基本功直接冲到缓存注解里去。结果就是东西确实跑起来了但出了问题完全不知道从哪里下手排查。你要问我第一天该干什么我的建议特别朴素打开命令行把它当成一个“通过网络访问的HashMap”来玩。1.1 为什么说先玩命令行比写Java代码更重要你想想你在业务代码里写redisTemplate.opsForValue().set(key, value)背后真正发生的事情无非就是通过TCP协议往Redis服务器发了一条命令。这条命令长什么样长这样SET key value如果你连这条命令都说不出来那你写的那层Java封装就等于是在一个黑盒上面盖了另一层黑盒。以后线上Redis出现慢查询、出现CPU飙升、出现大Key告警你连排查入口都找不到。我见过不少同事Redis用了两三年连redis-cli进去敲INFO看一下内存和命中率都不会这种基础不补上后面全是窟窿。第一天最该做的是在本机把Redis跑起来。别用Docker别偷懒直接编译安装或者用发行版自带的包管理器装一个。为什么因为你得亲手感受一下redis-server启动时打印的那些日志得知道数据目录在哪得搞明白redis-cli连接时用什么端口和密码这些是你后面排查问题时的“肌肉记忆”。装好之后把下面这几组命令老老实实敲一遍# 基础读写 SET user:1:name zhangsan GET user:1:name EXPIRE user:1:name 60 TTL user:1:name # 判存在、删Key EXISTS user:1:name DEL user:1:name TYPE user:1:name # 查看当前库所有Key生产环境慎用 KEYS *KEYS *在生产环境是个危险动作会在Key数量大的时候阻塞Redis主线程这个我们后面会专门聊。第一天你用它来观察数据写入情况没问题但脑子里要刻下一句话这玩意儿线上碰都别碰。1.2 五种数据结构用生活化的方式去理解很多教程喜欢用晦涩的定义去解释Redis的五种基础数据结构我不这么干。我用的是最土的办法——把它映射成Java里已经有的东西你瞬间就通了Redis数据结构等价Java概念典型用途String单个字符串或数字缓存JSON、计数器、分布式IDHashMapString, String缓存对象字段单字段读写ListLinkedList消息队列、时间线列表SetHashSet去重、共同好友、随机抽奖ZSetTreeMap 分数排序排行榜、延迟队列比如Hash你就记住它是“节约内存的对象缓存”。你要缓存一个用户信息用String你得把整个对象序列化成一个JSON串塞进去改一个字段就得整体覆盖用Hash你就能把用户ID当Key把姓名、年龄、手机号分别当Field存改哪个字段就动哪个字段这在某些高并发场景下能省下不少序列化开销。ZSet是另一个线上出场率极高的结构。它的本质是每个成员绑定一个分数Redis按分数排序存储。你不光可以做排行榜分数就是得分还能做延时队列的底层实现——把执行时间当分数轮询时用ZRANGEBYSCORE把到期任务取出来处理。很多Java程序员第一反应是这不就是个带排序的集合吗但真到用的时候能想到用ZSet的人反而不多。1.3 关于Key设计早养成习惯早省心这一小节不写代码但我觉得比任何代码都重要。Redis没有表结构的概念Key设计全靠自觉。我见过最离谱的线上事故是有人把Key命名成user_12345_info过两天又有人写成了userInfo:12345两个人各写各的缓存数据互相覆盖查了一整天最后才发现是Key命名冲突。我给自己定的命名规则用到现在没出过岔子业务域:对象类型:ID:字段修饰符比如user:profile:10001order:detail:202401150001product:stock:SKU888这套规则的好处是你用冒号分段Redis里这些Key可以被前缀搜索虽然生产环境要慎用更主要是所有团队成员能一眼看出这个Key是干什么的、属于哪个模块。同时要养成给Key加上过期时间的习惯哪怕你设计的时候认为这个数据永远不会变也请设置一个TTL兜底。Redis不是你的硬盘内存是有限的没有过期策略的缓存只会让内存慢慢涨到不可收拾。2. 第二天到第三天Java客户端选型和Spring Boot集成命令行玩顺了数据结构心里有数了接下来要干的事就是把它接进Java工程。很多新手在这个环节会陷入选择困难Jedis、Lettuce、Redisson到底该用哪个网上答案众说纷纭今天这个推荐那个明天那个又翻案。我直接给你一个没有广告法风险的实用结论。2.1 Jedis、Lettuce、Redisson的定位差异先把三者的本质说透。Jedis最老牌的客户端直来直去API基本是Redis命令的Java映射。它的特点是简单透明但线程安全方面做得比较差。多线程环境要共用实例得靠连接池来保证不然会有线程安全问题。Lettuce基于Netty的异步客户端线程安全你的应用可以和Redis保持长连接多个线程共享一个连接实例也没问题。Spring Data Redis在Spring Boot 2.x之后默认用的就是它。Redisson定位不只是客户端更像一个“住在Redis上的Java分布式工具包”。分布式锁、分布式集合、信号量、延迟队列这些高阶能力它有现成的模板。封装程度很高用起来很爽但代价是你的代码和它的API绑得比较死出问题的时候需要理解它的内部逻辑。选型的判断标准不复杂大部分Java项目用了Spring Boot那就以Spring Data Redis Lettuce作为标配。如果你有大量的分布式协同需求比如分布式锁、分布式Map直接把Redisson加进来没必要自己用Lettuce去拼这些轮子。不推荐上来就用Jedis写裸命令除非你的项目就是简单的Redis操作不想引入Spring Data那层封装。但即使如此我仍然建议Spring Boot项目优先考虑默认的Lettuce因为社区更新和踩坑人数决定了它的稳定性上限。2.2 Spring Boot里的基础配置和序列化坑先看一个最基础的配置spring: data: redis: host: 127.0.0.1 port: 6379 password: database: 0 timeout: 3s lettuce: pool: max-active: 16 max-idle: 8 min-idle: 2 max-wait: 3s这套配置里max-active是最大连接数并不是越大越好。你想想数据库连接池的道理连接数是受Redis服务端性能和应用线程数共同制约的。一般压测时逐步往上调看到一个拐点再往上加连接数反而导致线程切换开销变大吞吐量掉头向下。max-wait设成3秒是防止连接池被耗尽时请求无限等下去客户端快速失败后能尽早触发降级逻辑。配置落定紧接着就会踩到第一个大坑——序列化。Spring Data Redis默认用的是JDK序列化听我一句劝这个默认配置在真实项目里就是个坑。JDK序列化出来的二进制内容人类完全不可读。出现线上问题你拿redis-cli去查数据看到的是一堆\xAC\xED\x00\x05t...这样的乱码。查错靠猜调试靠蒙。更麻烦的是对象结构发生变化之后JDK序列化的反序列化兼容性非常差经常直接抛异常。所以我在项目里必改配置换成JSON序列化器Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); GenericJackson2JsonRedisSerializer jsonSerializer new GenericJackson2JsonRedisSerializer(); StringRedisSerializer stringSerializer new StringRedisSerializer(); // Key用String序列化可读性强 template.setKeySerializer(stringSerializer); template.setHashKeySerializer(stringSerializer); // Value用JSON序列化方便排查 template.setValueSerializer(jsonSerializer); template.setHashValueSerializer(jsonSerializer); template.afterPropertiesSet(); return template; } }这里有个容易忽略的细节Key和HashKey用String序列化Value和HashValue用JSON序列化。为什么Key要区分开因为Redis里Key是查找依据你用JDK序列化出来的Key在命令行里根本没法读也没法按前缀匹配。而Value是可读性要求相对低的但用JSON时人类还能看懂排查问题方便很多。2.3 为什么我不建议在业务代码里到处用RedisTemplateRedisTemplate用起来很顺手功能全面但顺手不意味着你应该到处滥用。最简单的例子——查询用户详情。新手写法通常是public UserVO getUserById(Long id) { String cacheKey user:profile: id; UserVO vo (UserVO) redisTemplate.opsForValue().get(cacheKey); if (vo ! null) { return vo; } UserVO dbVO userMapper.selectById(id); redisTemplate.opsForValue().set(cacheKey, dbVO, 30, TimeUnit.MINUTES); return dbVO; }这段代码问题在哪里缓存击穿、缓存穿透、缓存雪崩这三个经典问题一个都没防。后面我们会专门讲怎么在代码里挡这三位“老朋友”。这里先给你一个设计上的建议把缓存操作收敛到一个独立的CacheService里不要让业务代码直接操作RedisTemplate。为什么要这么做因为缓存策略在业务里是会被反复调整的——今天你要加空值缓存明天要加逻辑过期后天可能在缓存前面再加一层本地缓存。如果你每个Service都直接操作RedisTemplate改一次策略就得把所有调用点翻出来改一遍改到后面你会发现不敢动了。收敛成几个带语义的接口比如queryWithCache、deleteCache、tryLockAndQuery业务代码干净缓存策略也可维护。3. 第四天到第五天Java业务里最高频的四个Redis场景到了这一阶段工具层面的东西基本够了真正的分水岭在于你有没有处理过真实业务场景。我带过的开发者里有人命令背得滚瓜烂熟一遇到需求就不知道用哪个结构有人RedisTemplate用得溜但问起缓存一致性就支支吾吾。这一阶段的重点是四个场景——缓存读写、分布式锁、计数器与排行榜、轻量消息队列。3.1 缓存穿透、击穿、雪崩三位老朋友的防御姿势这三个名字听着吓人本质就三句话穿透查一个缓存和数据库里都不存在的Key每次请求都直打数据库。击穿某个热点Key过期的一瞬间大量请求同时打到数据库。雪崩大量Key在同一时间批量过期数据库瞬间压力暴增。我见过太多人把这三个概念倒背如流一写代码还是裸奔。所以直接给你一套可以抄的防御组合穿透核心是让“不存在”也能被缓存。查询结果为空时往缓存里写一个空值并设置短期过期时间比如3到5分钟。另一个更优雅的姿势是布隆过滤器启动时加载全量Key查询前先判断Key是否存在不存在直接挡回去。布隆的缺点是存在误判率以及数据新增时需要同步更新过滤器工程上稍微重一些。我的建议大部分项目直接用空值缓存就够了轻量且有效。击穿核心是给重建缓存这个动作加锁。同一时刻只允许一个线程去查数据库、回填缓存其他线程等待后直接命中缓存。要注意这里的锁必须是分布式环境下的锁而不是单机JVM的synchronized。实现手段可以直接上Redisson的RLock这也是我推荐引入Redisson的一个重要理由。重置缓存时记得做双重检查——拿到锁后再查一次缓存防止在等待锁的过程中缓存已经被别人重建了。雪崩防御核心是打散过期时间。不要在设置TTL时全用同一个数值随机加一个偏移量比如基础过期时间30分钟实际TTL是30 random(0~300)秒。这样即使一批Key同时被写入过期时间也会天然错开避免了集体壮烈。这里把三兄弟的防御策略、实现位置和代价整理成一张表以后面试和工作都用得上问题核心防御手段实现位置代价穿透空值缓存 / 布隆过滤器读取缓存后、查DB前额外内存开销布隆需维护击穿互斥锁重建缓存查DB的回填逻辑处增加锁等待时间雪崩过期时间加随机偏移写入缓存设置TTL处几乎为零3.2 分布式锁这么用才算是锁对了用Redis做分布式锁是Java后端绕不开的话题。但我想先说一个反直觉的结论如果只用SETNX去实现一个分布式锁绝对不是只有“坑”而是生产事故级别的挑战。这里面的关键问题有三层第一层锁没有设置过期时间。拿到锁的线程执行到一半挂了锁永远不释放其他线程全部饥饿。解决方式是用SET key value NX PX 30000一次性设置锁和过期时间保证原子性。这里有个细节很多人用两步走——先SETNX再EXPIRE程序在执行完SETNX之后崩溃了锁依然会永久存在。所以必须一股脑完成绝不能分开。第二层锁过期时间到了但业务还没执行完。A线程拿到锁处理耗时2秒锁过期时间设了1秒锁自动释放B线程拿到同一把锁进来了并发问题复燃。Redisson对这个问题的处理方式是看门狗机制——锁快到期时自动续期。如果你不用Redisson得自己在代码里起一个定时任务给锁续期非常麻烦。这也是我建议直接用Redisson的原因。第三层误删别人的锁。A线程处理完准备释放锁但它持锁期间锁已过期且被B线程获取。A释放锁的时候DEL掉的其实是B的锁。这个问题的标准解法是加锁时设置一个唯一标识如UUID释放锁时先判断当前持有者的标识是不是自己是才DEL。判断和删除两步又要保证原子性所以得用Lua脚本if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end我用Redisson的时候这部分细节它内部已经处理了但你要理解它底层在干什么不然遇到锁突然失效的诡异场景你连排查方向都没有。3.3 计数器和排行榜用对数据结构省下的不只是内存再举两个最常见的真实需求。计数器。比如文章阅读量用户每点一次就加一。你可以用INCR article:read:10086Redis单线程执行INCR天然是原子的避免了在应用层加锁。但注意一个细节——如果这是热点文章用一个Key承载所有点击这个Key的访问频率可能达到每秒上万次就成了“热Key”。一个常用的优化方案是把计数的Key拆成多个比如article:read:10086:0、:1、:2每个Key只承担部分流量读取时把多个Key的值累加。这就是分片计数本质上是在单点写瓶颈和读复杂度之间做权衡。排行榜。ZSet就是为这个场景设计的。每个用户ID作为成员得分作为排名依据ZADD写入ZREVRANGE取出前N名。整个过程不涉及数据库的ORDER BY性能好得离谱。但要提醒一点ZSet的基本操作复杂度是O(log(N))对于万级、十万级用户毫无压力对于千万级用户ZSet占用的内存和维护成本会迅速上升这时候就得考虑降级方案比如只维护TopN的过滤逻辑或者定期归档冷数据。3.4 轻量消息队列和延迟队列的快落如果项目里还没有引入专门的消息中间件Redis的List结构完全可以顶一阵子。生产者用LPUSH往队列里塞任务消费者用BRPOP阻塞弹出这是一个极简但可用的队列模型。BRPOP的B代表Blocking没有任务时消费者线程阻塞等待而不是空轮询可以大幅降低CPU消耗。延迟队列则可以用ZSet实现——任务执行时间戳作为分数消费者线程每隔一段时间用ZRANGEBYSCORE把小于当前时间戳的任务取出来执行。不需要引入定时任务框架Redis自己就能扛。这套方案能支撑的量级取决于任务量和消费速度通常中小业务用起来绰绰有余。不过我得说句实在话如果队列场景是核心链路或者需要消息确认、死信、有序消费、消息回溯这些能力还是老老实实引入专业的消息中间件。Redis这套方案适合的场景是“轻量、临时、后续好替换”用得太重只会给自己挖坑。4. 第六天的份量持久化、高可用和性能兜底到了这个阶段基础用法已经掌握得差不多了能处理日常业务场景了。最后这两天的重点不是新功能而是可靠性。你要在脑子里建立一套关于“Redis什么时候会挂、挂了会怎样、怎么恢复”的完整认知。4.1 持久化选择RDB和AOF不是二选一Redis是一个内存数据库数据默认是放在内存里的如果不配置持久化进程一退出数据就全部蒸发。很多Java程序员平时写代码没太在意这个真到线上宕机才发现缓存数据全丢所谓“缓存没了再查库就行”只是理想情况——如果缓存里存的是正在给外部系统处理的中间状态或者热点数据刚被缓存就被清空数据库会瞬间被流量冲垮。Redis的持久化有两种方案RDB按时间间隔把内存里的全量数据生成快照写入磁盘。优点是恢复快文件紧凑缺点是你设置的间隔内如果宕机这段时间的写入会全部丢失。AOF把每次写命令追加到日志文件恢复时重放日志。你可以配置成每秒刷盘一次最多丢一秒数据缺点是文件越来越大恢复速度比RDB慢。混合持久化Redis 4.0之后支持RDB和AOF混用AOF文件头部用RDB格式存全量数据后面追加增量命令兼顾恢复速度和数据安全性。我的配置建议不折腾直接Redis 6.x以上版本打开aof-use-rdb-preamble yes同时开启RDB和AOF这基本是当前最稳妥的姿势。数据安全优先级高的业务appendfsync设置为everysec就够了没必要用always因为每次写命令都刷盘会显著拉低性能。4.2 主从、哨兵、集群到底该上哪个这个问题堪称Java面试里的常青树但在真实项目里很多人把它理解成了一种“配置选择题”。我按线上部署的场景给你拆开主从复制一个主节点负责写多个从节点负责读。读写分离降低了单节点压力但主节点宕机时从节点不会自动上位需要人工干预。哨兵模式在主从复制基础上加了一层哨兵进程监控主节点状态主节点挂了能自动把一个从节点提升为新的主节点。对于大多数中小项目哨兵模式已经足够。集群模式Redis官方集群。数据分片放在多个主节点上每个主节点又有从节点做高可用。容量和吞吐量可以水平扩展但客户端和运维复杂度都上一个台阶。我的经验判断标准特别朴素缓存数据量预计不超过单机内存用哨兵模式超过单机内存且持续增长直接上集群。不要一上来就搞个大集群运维成本、客户端配置成本、排查问题的成本都会成倍上升。4.3 内存淘汰策略驱逐哪条数据Redis也得讲道理内存是有上限的到达上限之后新写入的数据怎么办这就是内存淘汰策略要回答的问题。我把几个主流策略用大白话翻译一下策略含义适用场景noeviction内存满了直接报错必须保证数据完整不建议开启allkeys-lru从所有Key中淘汰最久没访问的通用缓存场景最推荐volatile-lru只从设置了过期时间的Key里淘汰最久没访问的希望未设置过期时间的Key永远不被驱逐allkeys-lfu淘汰访问频率最低的Key有明显冷热分布的场景volatile-ttl优先淘汰剩余存活时间短的Key适合短时效数据实际项目里我基本上就推荐allkeys-lru。原因很简单缓存场景下数据是否被淘汰本来就不该由业务逻辑来保障业务保障靠的是数据库Redis这层就是尽力而为。如果担心某些核心Key被淘汰后雪崩那就给这些Key加长TTL或者单独部署一套不淘汰的Redis。4.4 大Key和热KeyJava程序员最该学会的体检项目这个问题前面提了好几次到这里展开说。什么是大Key字符串值超过10KB或者集合类型成员数量巨大、总内存占用过高都算。大Key的问题在于Redis是单线程处理命令的操作一个几百KB的Hash整个Redis实例都会卡一下。如果多个大Key集中被访问线上服务延迟曲线会直接拉出一条长长的尖峰。排查办法命令是现成的redis-cli --bigkeys它会扫描整个实例并输出各个类型里最大的几个Key。线上执行时建议用--i 0.1加一个间隔慢慢扫别一口气把CPU打满。热Key就更隐蔽了。某个Key的访问频率高到让单个Redis实例的CPU饱和就算你开再多客户端也没用瓶颈全在这个Key上。排查用redis-cli --hotkeys前提是开启了maxmemory-policy allkeys-lfu因为热Key统计依赖LFU的访问频次信息。找到热Key后应对方案有三板斧加本地缓存前置拦截大多数请求、Key内容分片、必要时对该Key做读写分离。记住一点Redis单线程的执行模型决定了单个Key的操作是串行的同构于单线程Java程序里你要对一段热点代码做优化——拆细、分散、减少冲突。5. 第七天性能排查和那些不得不说的经验教训到了最后一天不再学新功能而是用一套“体检排障”的方法把前面学的东西串起来。很多人学了七天Redis命令也熟代码也会写一遇到线上问题还是抓瞎就是因为缺少一套排查的路径依赖。5.1 排查问题时的第一反应先看慢查询Redis自身的慢查询日志是排查命令问题的第一入口。慢查询阈值设置如下CONFIG SET slowlog-log-slower-than 5000 CONFIG SET slowlog-max-len 128单位是微秒也就是命令执行超过5毫秒就记录下来。然后随时可以看SLOWLOG GET 50注意一个关键逻辑Redis是单线程的慢命令不光慢自己还阻塞整个实例。一个执行了30秒的KEYS *会让所有其他命令排队30秒。很多时候你感觉服务变慢去查数据库、查网络其实问题就在这——某个同事执行了一条慢命令把整个Redis拖垮了。所以看到SLOWLOG里出现命令的第一反应不是“这条命令有毛病”而是“这条路命令影响了谁”。能改业务就改业务比如KEYS换成SCAN集合操作别再全量捞。5.2 排查响应延迟时的第二反应网络和连接池另一个常见的“伪Redis问题”其实是连接池配置不当。比如连接池max-active设了8应用有20个线程同时去读缓存剩下12个线程全部在max-wait那里排队等待性能表现就明显恶化。这时候Redis本身速度快得飞起慢的是你应用端的获取连接逻辑。排查方法不复杂看看连接池的活跃连接数、等待获取连接的线程数、等待时间是不是接近max-wait上限。如果是调大max-active和max-idle后再压测对比持续观察拐点。还有一个容易被忽略的细节——每次操作Redis时频繁创建连接而不是从连接池复用对Lettuce来说这是致命的反模式一定要保证连接池配置生效而不是走默认单连接。5.3 监控指标里最值得盯的四项真正解决线上问题光靠直觉和临时排查是不够的得有长期数据支撑。我强烈建议每个Redis实例都接入监控重点盯下面四项命中率INFO stats里看keyspace_hits和keyspace_misses。命中率过低说明缓存设计有问题八成是Key设置不合理或者过期时间太短。内存INFO memory里看used_memory。持续上涨不加控制最终会触发内存淘汰或OOM。配套定期执行redis-cli --bigkeys诊断内存分布。连接数INFO clients里看connected_clients。异常升高往往是连接泄漏或者流量突增需要结合客户端连接池配置一起看。命令延迟INFO commandstats里可以看到每个命令的调用次数和耗时。结合慢查询一起分析能快速定位是哪个命令在拖性能。这里要特别说一句不要只等出事了才来盯指标。我建议在项目上线前就把这些监控项配好让告警在最早期就暴露风险。Redis这种组件很多问题是一点点积累出来的比如内存缓慢增长、大Key逐渐扩大在告警触发之前往往已经有几周甚至几个月的潜伏期了。5.4 实战踩坑记录这些经验是我真金白银换来的最后分享几个我在实际项目里踩过、也帮别人排过的坑都很典型而且常规文档里不会写这么细。第一坑RedisTemplate的Cacheable缓存穿透。Spring Cache注解用起来真爽Cacheable(key #id, unless #result null)一行搞定你以为unless挡住空值就不会穿透了吗错了unless只是不缓存空值查询照常打到数据库。防线还得自己加返回空时手动写入一个短TTL的空值Key或者统一封装一层空值判断逻辑。注解只是帮你省了代码没帮你省掉系统设计。第二坑大批量写入时单条循环调用。有一次同事导入十万条数据代码是for循环里一条条redisTemplate.opsForValue().set()结果导入任务跑了快四十分钟。Redis本身处理十万次命令很快但这个循环里每次调用都要走一次网络往返一次0.1毫秒十万次就是十秒起步再加上应用端的序列化和连接池排队时间一下子就上去了。优化时分批用pipeline或者RedisTemplate的executePipelined把命令批量发给服务端合并网络往返导入时间直接降到十几秒。第三坑上线前没有验证序列化配置。Spring Data Redis默认JDK序列化如果生产环境的Redis里存的是JDK序列化的数据你改了配置切到JSON序列化这部分老Key全都解析不了。很多人上线后才发现然后只能一边滚配置一边清脏数据。我的建议是在开发早期就确定序列化方案一旦线上有数据更改成本就会陡增。第四坑把Redis当成数据库用。有人在Redis里存订单数据而且不设置TTL问起来还理直气壮——“反正内存够大”。后来数据量涨到几十个G一次主从切换导致全量同步直接拖垮了主节点。Redis是缓存不是数据库这条界限必须清晰。它的数据再快都要接受“随时可能被淘汰、被清空”的事实真正的持久化存储必须在数据库里有一份。6. 最后一天应该怎么收尾前面五块内容其实已经把一周的路线铺完了。第一天建手感第二天到第三天做集成第四天到第五天过场景第六天补可靠性第七天练排查。这个节奏我自己带人验证过不止一次。不是让人背完所有命令才动手而是边用边学用场景驱动知识把Redis的每个能力点和真实的业务需求对上号。只剩最后一点建议把这一周学到的内容想办法落到一个真实或模拟的项目改造里。比如找一个你手头普通的“查详情”接口自己试着加上缓存、加上空值防御、加上分布式锁、加上热Key分析。光看不练五天后你连SET带NX的语法都会觉得陌生练过一次这些点才会真正长在你身上。我见过很多学Redis的人上来就啃源码或者啃一本几百页的文档最后往往是坚持不下去。反倒是像这样“带着具体问题去查、去用、去试错”的路径最能在短时间内形成战斗力。一周的时间很紧但足够把Redis从熟悉的陌生人变成一个顺手好用的工具。希望这篇东西能让你少走几步弯路。
返回列表