Spring Boot集成Redis实战:缓存、分布式锁与序列化方案详解

发布时间:2026/10/10 21:40:53

Spring Boot集成Redis实战:缓存、分布式锁与序列化方案详解 说起 springboot 使用 redis这大概是 Java 后端开发里最经典也最多坑的组合之一。不管是做缓存、分布式锁、Session 共享还是排行榜、计数统计Redis 几乎都能插上一脚而 Spring Boot 又把它包装成了“引入依赖就能用”看起来很简单实际上序列化、连接池、版本前缀这些细节稍不小心就能让你折腾一个下午。这篇文章我就按自己踩坑和填坑的顺序把从环境搭建、基础配置、序列化方案到缓存治理、分布式锁、主从部署这类实战内容一次性讲透适合刚接触 Spring Boot 想快速把 Redis 跑起来的同学也适合已经在用但经常被各种诡异问题卡住的人对照排查。1. 为什么是 Spring Boot Redis1.1 Spring Boot 给你的东西比想象中多很多新手以为 Spring Boot 集成 Redis 就是加个spring-boot-starter-data-redis依赖然后随便注入一个RedisTemplate就能开始读写。这个认知方向是对的但只对了一半。Spring Boot 真正提供的是一整套自动配置它会在你引入依赖后自动创建RedisConnectionFactory、RedisTemplate、StringRedisTemplate这些 Bean还会根据配置自动检测你用的是 Lettuce 还是 Jedis。你不需要手写连接池不需要自己管理线程模型甚至不需要写 XML 配置。但“自动配置”也意味着默认值不一定适合你的业务。比如默认的RedisTemplate使用 JDK 序列化存进去的 key 在可视化工具里是一堆\xAC\xED\x00\x05t...乱码比如默认的 Lettuce 在低版本下连接池配置需要额外引入commons-pool2否则你以为配了连接池实际上根本没生效。这些都属于典型的“框架帮你做了事但没告诉你它替你做了什么”。1.2 常见使用场景与选型判断我从实际项目里总结下来Redis 在 Spring Boot 里最常用的场景是这几类缓存热点数据缓存、接口响应缓存、验证码存储这是最普遍的需求。分布式锁多个实例同时扣库存、下单、发券需要用 Redis 做跨 JVM 的互斥。Session 共享多个 Spring Boot 项目负载均衡部署时用 Redis 保存 Session解决登录状态不同步的问题。排行榜与计数用 ZSet 做排行榜用 INCR 做访问量、点赞数的原子自增。限流与消息队列基于INCR做滑动窗口限流用List的BRPOPLPUSH做简单可靠的消息队列。这里有个选型判断要提前说清楚不要什么数据都往 Redis 塞。像订单明细、用户全量信息、对账数据这类要求强一致的数据老老实实放在 MySQL。Redis 定位是缓存和加速不是万能数据库。我在项目里见过有人把主库数据全部冗余进 Redis结果缓存和库对不上排查到怀疑人生。读多写少、允许秒级不一致的数据才适合放进缓存。1.3 数据类型与业务模型的对应关系Redis 五种基础数据类型经常被面试问到但真正在业务中能把它们对应到合适场景的人并不多。数据类型底层结构常见使用场景注意事项StringSDS 动态字符串缓存键值对、计数器、分布式 ID单 value 不要超过 512MB大文本别硬塞Hash哈希表 ziplist对象属性存储、购物车适合频繁改某几个字段的场景List双向链表 quicklist消息队列、时间线、最新列表LPOP/RPUSH组合可以做队列Set哈希表 intset去重、抽奖、好友关注关系并集、交集、差集运算能力强ZSet跳表 哈希表排行榜、延时队列score 支持小数排序效率高拿电商项目举例商品详情适合用 String 存 JSON购物车适合用 Hash每个用户一个 key商品 ID 作为 field数量作为 value排行榜适合用 ZSet用户的消费金额或者积分作为 score。理解数据结构背后的适用场景比死记命令要重要得多。2. 环境准备与基础集成2.1 Redis 服务端的安装方式本地开发的话Linux 和 macOS 装 Redis 都比较省事。Ubuntu 直接用apt install redis-serverCentOS 用yum install redis或者编译安装源码。Windows 要单独说一下官方已经明确不支持 Windows 版本网上那些 Windows 版 Redis 大多是微软以前维护的老分支或者第三方编译产物只适合本地临时测试生产环境不要考虑。Win 上最推荐的方式是装 WSL2 或者 Docker Desktop然后用 Linux 容器跑 Redis。Docker 安装是最省心也最接近生产环境的方案docker run -d \ --name redis \ -p 6379:6379 \ -v /data/redis:/data \ redis:7.2 \ redis-server --appendonly yes --requirepass yourpassword需要注意几点-p 6379:6379是把容器端口映射到宿主机不映射的话宿主机应用访问不到-v挂载数据目录不然容器删了数据全丢--appendonly yes开启 AOF 持久化这个我后面会专门讲。密码如果本地测试不需要可以先不加但如果是云服务器必须加密码否则 Redis 默认监听所有网卡的时候会被爆破。2.2 Spring Boot 依赖与核心配置引入依赖很简单Maven 项目在pom.xml里加dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency如果你要用连接池还需要再加入dependency groupIdorg.apache.commons/groupId artifactIdcommons-pool2/artifactId /dependency配置文件里Spring Boot 2.x 和 3.x 的配置前缀不一样这是很多人踩得最多的一次坑spring: data: redis: host: 127.0.0.1 port: 6379 password: yourpassword database: 0 timeout: 3s lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0Spring Boot 2.x 用的前缀是spring.redisSpring Boot 3.x 改成了spring.data.redis。如果你在 3.x 里继续写spring.redis不会启动报错但是所有配置都不会生效连接会默认走 127.0.0.1:6379 无密码等你部署到服务器上会突然发现连不上这种问题排查起来相当隐蔽。确定自己项目版本的最快办法是看一眼启动 Banner 或者pom.xml里的spring-boot-starter-parent版本号。2.3 连接工厂与连接池参数别乱调Lettuce 是 Spring Boot 2.0 之后默认的 Redis 客户端底层基于 Netty性能和并发能力都不错。但 Lettuce 本身默认是“每个连接可以共享”如果你不做连接池配置高并发情况下容易出现连接争抢和超时。所以生产环境那几条连接池参数基本是必须配的max-active最大连接数一般取 8~16 足够撑死 32之前有团队开到 100 直接把 Redis 服务端连接数打满。max-idle最大空闲连接数建议和max-active一致不然高并发瞬间需要新建连接会有开销。min-idle最小空闲连接数设为 1~2 可以避免流量波动时频繁建连。timeout连接超时时间单位毫秒或带s后缀设太短会导致瞬时流量下大量操作超时。连接池参数并不是越大越好Redis 服务端默认maxclients是 10000但每个连接都要占用一个 file descriptor应用侧连接池开太大反而增加线程切换和内存消耗。我之前遇到过连接池max-active配成 200结果应用启动时就建立了大量空闲连接不仅 Redis 内存多了不少开销重启时客户端重连风暴也把服务压垮了。3. 数据访问与序列化方案3.1 RedisTemplate 与 StringRedisTemplate 怎么选Spring Boot 默认注入了两个模板类RedisTemplateObject, Object和StringRedisTemplate。区别在于 StringRedisTemplate 的 key 和 value 都强制用 String 类型实际写入 Redis 时默认使用 UTF-8 编码RedisTemplate 则是泛型类型默认采用 JDK 序列化器。从实战角度我建议缓存 JSON 字符串、计数器、验证码、Token 这类场景一律用 StringRedisTemplate省心、可读、跨语言兼容。只有在需要直接操作对象、并且确定只有 Java 服务自己读写时才考虑自定义 RedisTemplate 配合 JSON 序列化器。这背后的逻辑很简单Redis 只认字节数组你在应用层看到的是某个类的实例但到了 Redis 层面它就只是一串字节如果序列化方式选择不对存进去能读出来但换一种语言、换一个客户端就完全不认识了。3.2 各种序列化器的优劣对比序列化器可读性性能安全性建议场景JdkSerializationRedisSerializer差一般有反序列化漏洞风险几乎不建议用StringRedisSerializer好高安全key 统一用这个GenericJackson2JsonRedisSerializer好中等需要管理class字段大多数业务对象缓存Jackson2JsonRedisSerializer好中等需要指定具体类型单一类型的 value 缓存Fastjson2JsonRedisSerializer好高注意配置安全开关追求性能时选用这里值得展开说的是为什么我不建议用默认的 JDK 序列化。第一它序列化出来的数据是一坨二进制乱码在可视化工具里根本没法排查第二JDK 序列化会把对象完整类名写进去一旦你的实体类改了包名或者字段老缓存全部反序列化失败第三Java 原生序列化存在安全风险如果 Redis 数据被恶意篡改反序列化可能触发远程代码执行。所以我的习惯是key 全部用 StringSerializervalue 用 GenericJackson2Json这样既能看到明文又能自然的处理类型信息。3.3 自定义 RedisTemplate 的完整写法在 Spring Boot 中使用 Redis 时我会在自己的配置类里重新定义 RedisTemplate把默认行为矫正过来Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); // key 采用 String 序列化 StringRedisSerializer stringSerializer new StringRedisSerializer(); // value 采用 JSON 序列化保留类型信息 GenericJackson2JsonRedisSerializer jsonSerializer new GenericJackson2JsonRedisSerializer(); template.setKeySerializer(stringSerializer); template.setHashKeySerializer(stringSerializer); template.setValueSerializer(jsonSerializer); template.setHashValueSerializer(jsonSerializer); template.afterPropertiesSet(); return template; } }这套配置的核心逻辑是key 和 field 一定要用字符串因为我们的 key 基本都是business:entity:id这种可读形式用字符串存储才能在命令行里正常看到value 则要看存的内容存 JSON 字符串就用 String存对象就考虑 GenericJackson2Json。用GenericJackson2JsonRedisSerializer时序列化结果里会多一个class字段它是用来在反序列化时还原具体类型的副作用是数据体积增大约 20%但换来的是不用自己写类型转换值得。3.4 序列化相关的高频踩坑点坑一key 乱码。典型表现是可视化工具里看到\xAC\xED\x00\x05t\x00\x0auser:1这样的 key。原因是默认 RedisTemplate 用 JdkSerializationRedisSerializer 对 key 做了 JDK 序列化。解决就是严格按照我上面的配置key 用 StringRedisSerializer。坑二LocalDateTime 反序列化失败。实体类里有LocalDateTime字段时Jackson 默认不认识这个类型即使加了Jackson2JsonRedisSerializer也会报错。解决方法是给 ObjectMapper 注册JavaTimeModuleObjectMapper mapper new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); GenericJackson2JsonRedisSerializer serializer new GenericJackson2JsonRedisSerializer(mapper);坑三对象没有无参构造器报错。JSON 反序列化默认通过无参构造器创建对象你的 DTO 如果只有全参构造器反序列化直接抛异常。开发规范里我要求所有参与 Redis 缓存的对象必须保留无参构造顺手也解决了 Jackson 的一大半问题。4. 缓存注解与缓存治理实战4.1 注解式缓存Cacheable / CachePut / CacheEvictSpring Cache 抽象层是 Spring Boot 使用 Redis 最舒服的入口不需要手写 RedisTemplate 也能做缓存。启用方式是在启动类或任意配置类加EnableCaching然后在 Service 方法上标注Cacheable(value product, key #id) public Product getProduct(Long id) { return productMapper.selectById(id); } CachePut(value product, key #product.id) public Product updateProduct(Product product) { productMapper.updateById(product); return product; } CacheEvict(value product, key #id) public void deleteProduct(Long id) { productMapper.deleteById(id); }Cacheable先查缓存没命中就执行方法并把结果写入缓存CachePut不管缓存有没有都执行方法然后更新缓存CacheEvict执行完删除缓存。这套机制要理解透很多人会犯的错误是在更新操作上用了Cacheable结果数据改了缓存还是老的页面一直显示旧数据。更新就选CachePut删除就选CacheEvict这没得商量。4.2 缓存 Key 策略和过期时间设计缓存 key 的规范值得认真设计我总结的原则是“业务前缀 实体名 主键”例如product:detail:1001。在注解里用 SpEL 表达式可以做到动态拼接Cacheable(value product, key product:detail: #id)有人会问#id和product:detail: #id区别在哪。前者生成的 key 只有1001不同业务间极易冲突后者有前缀约束隔离性明显更好。另外注意如果两个方法的参数名都叫 id但语义不同建议在表达式里加上业务标识。过期时间设计上如果所有 key 都统一用配置的默认过期时间会出现缓存同时过期的大问题。热 key 一起失效瞬间请求全部打到数据库这就是缓存雪崩的雏形。我的做法是给同一类数据设置基础过期时间加随机增量比如600 RandomUtil.randomInt(120)秒不同 key 的实际过期时间错开数据库压力曲线就不会出现明显尖峰。4.3 缓存穿透、击穿、雪崩的应对思路这三兄弟是 Redis 面试题里的常客也是线上事故的高发区实战中必须知道怎么预防。问题现象常见解决方案缓存穿透查询不存在的 key缓存和数据库都没有请求直接打到 DB缓存空值、布隆过滤器、接口层参数校验缓存击穿某个热点 key 过期瞬间大量并发同时回源 DB互斥锁、逻辑过期、不给热点 key 设过期时间缓存雪崩大量 key 同时过期或 Redis 宕机流量全部打向 DB过期时间随机化、多级缓存、Redis 高可用缓存穿透我见过最典型的案例是电商的“查询不存在的商品 ID”有人写爬虫把所有不存在的 ID 都请求一遍每次都会穿透到数据库。最简单的治理方案是把查询结果为 null 也缓存起来过期时间设短一点比如 60 秒同时在 Service 层做参数合法性校验非法 ID 直接返回。如果要更严谨用布隆过滤器在缓存之前拦截一波不存在的 key就是相对重量级的方案了。缓存击穿的核心是热点 key 过期时“大量线程同时去数据库查”。最常用的解法是互斥锁即查询 DB 之前先尝试拿 Redis 分布式锁拿到的线程去查库并回填缓存其他线程等待后重查缓存。另一个思路是逻辑过期缓存不设置物理过期时间而是 value 里写入过期时间戳读到时发现逻辑过期就异步更新适合能接受短暂脏数据的场景。缓存雪崩和击穿的区别在于规模一个 key 和多个 key。除了过期时间加随机数高并发项目里建议再上一级本地缓存如 Caffeine做兜底Redis 挂了还有本地 JVM 缓存扛住一部分数据库就不至于被打瘫。4.4 缓存治理热 Key、大 Key 与内存淘汰策略Redis 用得好不好光会读写远远不够还得会“治理”。线上排查的第一步是看监控指标包括缓存命中率、Redis 内存水位、慢查询数量。这些数据可以用redis-cli INFO stats和redis-cli INFO memory拿到也可以接入 Prometheus Grafana。热 key 的处理手段无非这么几招一是把这个 key 的副本复制多份比如原本的 keyproduct:1001复制成product:1001:0到product:1001:9十个副本读的时候随机选一个避免单分片热点二是把热点数据做本地缓存Redis 压力直接降下来三是限流削峰。大 key 则要注意 String 类型的 value 超过 10KB、Hash 或 ZSet 元素超过 5000 个都属于偏大的范围会对阻塞删除、内存碎片、网络传输都造成压力。处理方式是拆分把大 key 拆成多个小 key或者把 Hash 的 field 拆分到多个主键下。内存淘汰策略也要提前定好。Redis 默认是noeviction内存满了写操作直接报错。如果你的 Redis 主要做缓存建议设成allkeys-lru让 Redis 自动淘汰最久没用的 key。配置方式可以在 redis.conf 里改也可以运行时执行redis-cli CONFIG SET maxmemory-policy allkeys-lru需要注意的是如果 Redis 同时也存了分布式锁、秒杀库存这类不能丢的数据一律配置“不淘汰”或者单独分实例别把所有鸡蛋放在同一个allkeys-lru的篮子里。5. 分布式锁的实现与优化5.1 为什么单机锁解决不了多实例问题很多人一开始做秒杀、扣库存下意识用synchronized或者ReentrantLock本地测试一切正常一上多节点生产环境就开始超卖。原因很简单synchronized 锁的是单个 JVM 内部的对象监视器多实例部署时每个实例各有各的锁请求分散到不同机器锁就形同虚设。分布式锁的本质是把“互斥判断”放到所有实例都能访问的共享存储上Redis 就是最常用的共享存储。核心流程是线程 A 在 Redis 里设置一个锁 key设置成功则获得锁执行完删除锁 key线程 B 也去设置同样的 key发现已存在就等一等再试。关键在于“设置 key”的原子性你不能先判断 key 不存在再设置两个线程同时判断都会通过锁就失效了。5.2 基于 SET NX EX 的简易实现Redis 在 2.6.12 之后提供了全新的 SET 指令在一条命令里同时支持NX和EX这是实现分布式锁最基础的原子操作SET product:lock:1001 uuid-12345 NX EX 30NX表示 key 不存在才设置成功EX 30表示过期时间 30 秒。拿锁的 Java 写法大致是Boolean locked stringRedisTemplate.opsForValue() .setIfAbsent(lockKey, requestId, Duration.ofSeconds(30)); if (Boolean.TRUE.equals(locked)) { try { // 执行具体业务 } finally { // 释放锁 } }释放锁时需要特别注意不能用简单的del命令。因为如果线程 A 执行业务超时锁自动过期了线程 B 拿到了新锁这时 A 才执行完去删 key就会把 B 的锁误删掉。解决办法是执行一个 Lua 脚本先对比 value 是否自己的 requestId是自己的才删不是就不动if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end这个写法虽然能用但还缺一块最重要的能力自动续期。如果业务执行时间超过 30 秒没等释放锁就自动过期了其他线程进来了分布式锁等于失效。简易实现只适合执行时间可控、超时场景影响小的业务。5.3 用 Redisson 解决续期和重入问题解决续期和重入问题最省事的方式是用 Redisson。Redisson 封装了锁的超时续期能力它内置一个“看门狗”机制如果拿到锁的线程还在运行看门狗会每 10 秒默认锁过期时间的 1/3自动把锁的过期时间延长到 30 秒直到线程释放锁。这样业务执行再久只要 JVM 没挂锁就不会被其他线程抢走。引入 Redisson 的方式很简单dependency groupIdorg.redisson/groupId artifactIdredisson-spring-boot-starter/artifactId version3.23.5/version /dependency使用方式Autowired private RedissonClient redissonClient; public void deductStock(Long productId) { RLock lock redissonClient.getLock(stock:lock: productId); lock.lock(); try { // 扣库存业务 } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }可能有同学会问为什么不直接自己写续约定时任务。可以写但容易出 bug。看门狗的判活逻辑、锁计数、线程归属判断这些都是经过大量生产环境锤炼的自己造的轮子很难覆盖所有边界。Redisson 还支持公平锁、读写锁、红锁等多种模式日常业务里getLock加上看门狗已经能满足九成场景。5.4 锁粒度与锁超时优化的经验锁粒度是分布式锁设计里最容易被忽视的点。比如电商下单锁库存如果你用全局锁lock:stock那所有商品的扣减全部串行并发能力直线下降。正确做法是按商品维度加锁lock:stock:{productId}不同商品之间互不阻塞压力就被分散了。同理用户维度的操作建议用lock:user:{userId}。还有一个经验锁的过期时间不要套模板50ms 能做完的业务和 5 秒才能做完的业务完全不是一个量级。Redisson 默认 30 秒看门狗够用但如果你自己实现那只直接 SET NX EX 的方案EX的时长需要基于业务耗时评估一般按接口 P99 耗时乘以 3 到 5 倍比较安全。过短导致误删锁过长导致故障时锁长时间占坑这个权衡要结合业务和监控不断调。6. 部署层面主从复制与集群方案6.1 主从复制搭建与原理单机 Redis 一旦宕机缓存全灭数据库要裸奔硬扛流量所以生产环境至少要上主从架构。主从的核心思路是主节点负责写从节点负责同步数据、分担读压力。搭建方式有手动配置和 Docker 编排两种手动方式在从节点的 redis.conf 里配置replicaof 192.168.10.10 6379 replica-read-only yes注意老配置项叫slaveofRedis 5 之后改名replicaof含义一样。Docker 里我习惯用 docker-compose 分端口跑一主一从services: redis-master: image: redis:7.2 ports: - 6379:6379 command: redis-server --appendonly yes redis-replica: image: redis:7.2 ports: - 6380:6379 command: redis-server --slaveof redis-master 6379主从复制的原理可以简单理解为“先全量后增量”从节点第一次连接主节点时主节点生成 RDB 快照发给从节点从节点加载恢复此后主节点的每次写入命令都会异步同步给从节点从节点在自己的进程里执行一遍。因为同步是异步的主从之间天然有短暂延迟所以读从库做业务时对一致性敏感的数据要格外小心比如库存操作绝对不能走从库。6.2 哨兵与 Redis Cluster 的适用边界主从复制解决了分布式存储但没解决“主节点挂了怎么办”。主节点宕机后从节点虽然有完整数据但应用不会自动把写请求切过去整个写能力就断了。哨兵模式Sentinel就是来解决这个问题的它持续监控主从的健康状态主节点不可用时自动把某个从节点提升为主节点客户端通过哨兵就能感知到新主节点的地址。哨兵至少部署 3 个节点才能避免脑裂其实就是哨兵自己也需要“多数确认”才能判定主节点宕机。而 Redis Cluster 则是更大的架构选择它把数据分片到 16384 个槽位里每个节点负责一部分槽位支持水平扩展。Cluster 模式下单个 key 的读写会被路由到正确的节点但 Lua 脚本、事务这类操作要求 key 都在同一个节点业务复杂度会上升。我的选型建议是数据量几 GB 以内、并发中等的场景主从 哨兵足够数据量几十 GB 以上或者需要无限横向扩容再考虑 Cluster。不要一开始就上 Cluster分片带来的运维成本和管理复杂度会吃掉你不少开发时间。6.3 可视化客户端与日常运维工具命令行工具redis-cli永远是最可靠的但看数据、调 key、分析大 key 时可视化客户端能明显提升效率。我个人常用的是 Redis InsightRedis 官方出品免费、Another Redis Desktop Manager开源、还有经典的需要付费授权的 Redis Desktop Manager。Redis Insight 最实用的功能是内存分析它能扫出大 key 排行、key 数量分布、内存占用 Top N这些信息对缓存治理来说至关重要。另外两点提醒一是在生产环境别开着客户端做KEYS *全量扫描会阻塞单线程的 Redis 非常久应该用SCAN游标式遍历二是线上操作尽量只读命令执行前想清楚会不会影响线上流量。运维层面还建议把慢查询日志打开Redis 的slowlog能记录执行时间超过阈值的命令redis-cli CONFIG SET slowlog-log-slower-than 10000 redis-cli CONFIG SET slowlog-max-len 128 redis-cli SLOWLOG GET 50阈值单位是微秒10000 表示命令执行超过 10 毫秒就记录。看到慢查询先查 key 是否太大、是否使用KEYS、是否频繁SORT这类 O(N) 命令对症下药。7. 常见问题排查与排错实录7.1 应用连接不上 Redis 的标准排查路线“连接不上 Redis”是所有 Spring Boot 项目使用 Redis 时出现频率最高的问题我遇到过无数的同学截图问这个包括项目工具场景里经常出现的黑马点评案例。这种问题的排查思路要固定下来按顺序走一遍基本都能定位。第一步先确认 Redis 服务是否真的在跑。命令行执行redis-cli -h 127.0.0.1 -p 6379 ping返回PONG说明服务正常。这里要强调排查问题不要一上来就怀疑代码先验证我给你这个“基础命令”它排除的是服务端故障、网络不通、配置错误里的大多数。第二步确认 Spring Boot 里的配置是否真的生效。这一步最常见的坑就是我前面说的spring.redis和spring.data.redis前缀问题以及密码如果 Redis 设置了 requirepass 而 Spring 配置没写密码或者密码写错现象就是启动能成功但第一次读写时报NOAUTH Authentication required。第三步检查 Redis 的bind配置。redis.conf 默认bind 127.0.0.1表示只允许本机访问。如果你的 Spring Boot 应用和 Redis 不在同一台机器必须把 bind 改成实际 IP 或0.0.0.0同时确认服务器安全组和防火墙放行了 6379 端口。这个能用telnet 服务器IP 6379直接验证不通就是网络或防火墙的问题和代码半毛钱关系没有。7.2 防火墙、密码与 Docker 端口映射细节有一次同事在云服务器上部署 Spring Boot 和 Redis本地怎么都连不上最后发现是 Docker 容器启动时忘了加-p 6379:6379Redis 跑在容器内默认网络里宿主机根本访问不到。Docker 部署的排查重点永远先看端口映射docker ps docker logs redis docker exec -it redis redis-cli -a yourpassword ping密码这个问题也值得单独说。Spring Boot 配置里的 password 如果包含$、#、这类特殊字符在 YAML 里不加引号会被解析成占位符或注释。比如密码是abc$123写password: abc$123时 Spring 会尝试解析${123}然后报错。稳妥做法是password: abc$123生产环境更推荐把密码放到环境变量里通过${REDIS_PASSWORD}注入密码不硬编码在配置文件里。7.3 连接池打满与慢操作排查连接池打满的典型报错是RedisConnectionFailureException: Cannot get Jedis connection或者 Lettuce 的Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException。原因通常有四类连接池max-active太小应用代码里 RedisTemplate 在事务或循环里被大量占用Redis 服务端maxclients太小Redis 服务本身有阻塞命令导致所有请求排队。排查思路第一眼先看 Redis 服务端连接数redis-cli INFO clients看到connected_clients等于或接近上限再看应用日志。如果是应用侧连接池占满加大max-active只是临时缓解真正要做的是找出谁在慢操作。最常见的阻塞命令就是KEYS。举一个我真实遇到过的案例一个管理后台功能用了KEYS user:*做模糊匹配用户上线之初数据量小没感觉数据到 2000 万 key 之后这个命令一次执行几十秒期间 Redis 整个服务被阻塞所有业务连接全部排队。把KEYS换成SCAN之后服务立刻恢复。这个教训非常值钱任何模糊匹配需求在 Redis 里都不要用KEYS生产环境我会在 redis.conf 里把KEYS命令直接 rename 掉来防呆。7.4 Redis 重启后数据丢失的处理Redis 重启数据全没也是新手经常问的问题根源在于对持久化机制没理解透。Redis 默认开启了 RDB 快照持久化但快照默认每 5 分钟或 100 个写入条件才触发一次两次快照之间的写操作在宕机重启后会全部丢失。要降低丢失窗口必须开启 AOF 持久化appendonly yes appendfsync everysecappendfsync everysec表示每秒钟把写命令刷到磁盘一次这是性能和数据安全的折中点最多丢 1 秒数据。更稳妥的always每次写都刷盘性能损失很大绝大多数业务没必要。RDB 和 AOF 可以同时开启Redis 重启时会优先用 AOF 恢复数据因为它的日志更完整。对应的热门搜索词里有个“redis aop与rdb”我猜想说的是 AOF 与 RDB 这对持久化方案。这两种方案各有优缺点简单对比是RDB 文件小、加载快但丢数据可能多AOF 数据完整度高、可读性好但文件大、加载慢。现实生产环境基本都是 RDB AOF 混合使用既有 RDB 的快速加载能力又有 AOF 的近实时备份兜底。最后分享一个我在实际项目里摸索出来的习惯Spring Boot 使用 Redis 时开发环境、测试环境、生产环境的配置可以用同一套代码但连接信息和密码必须走不同的 profile 或配置中心。每次改动 Redis 相关配置后先用redis-cli模拟一次连接再启动 Spring Boot这两步能过滤掉九成以上的“配置类”问题。先保证基础设施是通的再让框架接管这样排查问题时边界就非常清晰。等这段用顺了再往分布式锁、缓存治理、多级缓存这些方向深入你会发现 Redis 在 Spring Boot 里的潜力远比想象中要大。
延伸阅读

更多相关文章

2026/10/10 21:35:52

重构分布式大模型训练轨迹:从Trace到关键路径分析

分布式大模型训练跑起来之后,真正让人头疼的往往不是模型不收敛,而是 GPU 利用率看着还行,训练吞吐却始终上不去。排查这类问题,最直接的手段是拿到一份完整的训练轨迹(trace),看清每个 rank 在…

2026/10/10 21:35:52

本地部署大模型接入企业微信:Ollama+Flask实现合规AI自动回复

1. 先想清楚:你接入的到底是“微信”还是“微信生态”先说结论:这篇想讲的事,就是把一个本地跑起来的大语言模型,接到微信生态里,让它替你回复消息。模型名字我用的“龙虾”——这是社区里对某类开源中文大模型的一个通…

2026/10/10 21:35:52

ASP网上作业提交系统实战:IIS配置、Access数据库与文件上传

简介:基于ASPACCESS的网上作业提交系统设计资料,面向网络教育/K12课程资源开发者、ASP初学者及需要完成课程设计的高校学生,重点解决网络课程学习中的作业提交与知识自适应导航问题。资料围绕自适应网络课程学习导航系统展开,完整…

2026/10/11 1:47:28

信创系统自带的NAS网盘你玩过吗?

背景 NFS(Network File System)协议在Linux世界被广泛使用,如果你想用信创操作系统原生搭建NAS(Network Attached Storage)网盘,那么NFS无疑是一种稳定便宜的方案。下面就给大家讲讲在信创操作系统下,如何玩转NFS协议。 麒麟系统下搭建NFS服…

2026/10/11 1:47:28

Windows 下用 Hyper-V 安装 Windows 10 虚拟机(带桌面)保姆级教程

Windows 下用 Hyper-V 安装 Windows 10 虚拟机(带桌面)保姆级教程想在一台电脑上同时跑多个系统?装双系统怕折腾坏引导?虚拟机就是最优雅的解决方案。本文基于实测全流程,手把手教你用 Windows 自带的 Hyper-V 免费安装…

2026/10/11 1:47:28

仪表 232/485 数据采集网关技术分享

1. 引言在工业自动化与物联网场景中,大量现场仪表(如电表、水表、温控器、PLC 等)仍以 RS-232 或 RS-485 串口作为主要通信接口。如何将这些分散的串口设备统一接入以太网或无线网络,实现远程数据采集与监控,是工程实践…

2026/10/11 1:47:28

Ubuntu 22.04 搭建 PX4 无人机开发环境(保姆级教程)

Ubuntu 22.04 搭建 PX4 无人机开发环境(保姆级教程)PX4 是目前最流行的开源无人机飞控软件,支持多旋翼、固定翼、VTOL 等多种机型。想入门无人机开发,第一步就是把 PX4 开发环境搭起来。本文基于官方推荐流程 实测踩坑经验&#…

2026/10/11 1:42:28

利用继电器感应交流电流

对比几款继电器线圈感应信号AD\Test\2026\September\RelayACSensorMEGA8.SchDoc 使用继电器线圈来检测电流热水器工作报警器 01 【继电器作为电流传感器】 一、设计背景 在之前使用过继电器的它的线圈作为传感器 来检测电线中的电流信号, 利用这种方式可以比较方便…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑