多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

SpringBoot连接服务器Redis实战:从配置到部署的完整避坑指南

SpringBoot连接服务器Redis实战:从配置到部署的完整避坑指南 1. 项目概述从本地到服务器的Redis连接实战搞后端开发尤其是用SpringBoot的Redis基本是绕不开的一个组件。它速度快、数据结构丰富拿来当缓存、做会话存储、搞消息队列都挺顺手。但很多新手甚至一些工作一两年的朋友在配置连接时还是会踩坑。最常见的就是本地开发环境连不上服务器上的Redis或者配置写了一大堆结果项目启动就报错什么Connection refused、Timeout、NOAUTH Authentication required看着就头疼。这篇文章我就以一个老码农的身份跟你从头到尾捋一遍这个事。核心就两件事第一怎么在服务器上把Redis配置好让外部能安全地连进来第二在SpringBoot的application.yml里怎么写配置才能稳稳地连上它。我会把每一步背后的“为什么”讲清楚比如为什么要改bind为什么要设密码timeout设多少合适让你不仅能把环境配通更能理解其中的门道。无论你是刚接触SpringBoot和Redis还是在部署时遇到了连接问题这篇都能给你一份清晰的“避坑指南”。2. 服务器端Redis配置详解想让SpringBoot应用连上服务器的Redis服务器端的配置是地基。这一步没做对后面怎么写YML都是白搭。很多人图省事直接apt-get install redis-server装完就以为万事大吉结果本地一连接立马吃闭门羹。2.1 安装与基础安全加固在Ubuntu/CentOS这类Linux服务器上安装Redis通常很简单。以Ubuntu为例sudo apt update sudo apt install redis-server -y安装完成后Redis服务会自动启动。但此时的配置是默认的只监听本地回环地址127.0.0.1且没有密码。这意味着除了服务器本机任何外部网络请求都无法连接这是一种安全策略但也正是我们连接失败的根源。首先我们需要找到配置文件。通常位置在/etc/redis/redis.conf。在修改之前强烈建议先备份sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.backup接下来是几个关键的配置项直接关系到能否远程连接bind配置放开网络枷锁默认配置是bind 127.0.0.1 ::1。这行配置绑定了Redis服务监听的网络接口。127.0.0.1是IPv4的本机地址::1是IPv6的本机地址。只绑定它们Redis就成了一座只对内部开放的城堡。修改方案方案A允许特定IP连接如果你知道你的应用服务器IP比如192.168.1.100可以改为bind 127.0.0.1 192.168.1.100。这样既保留了本地连接也允许了指定IP。方案B允许所有IP连接 - 慎用直接注释掉bind这一行或者改为bind 0.0.0.0。这意味着Redis监听所有网络接口任何能访问到服务器IP的机器都能尝试连接。这是极不安全的仅在完全信任的内网环境或配合下面提到的密码和防火墙使用时才考虑。注意很多教程让你直接注释bind但在生产环境我强烈建议采用方案A或者至少设置强密码和防火墙规则。安全无小事。protected-mode配置关闭保护模式这是一个重要的安全特性。当Redis未显式绑定到所有接口即bind没设成0.0.0.0且未设置密码时保护模式会生效拒绝外部连接。在我们修改了bind但还没设密码的过渡阶段或者在内网测试时可能需要暂时关闭它。 找到protected-mode yes将其改为protected-mode no。记住这只是临时测试手段长期运行必须设置密码。requirepass配置设置访问密码这是保障Redis安全的核心。找到# requirepass foobared这一行去掉注释#并把foobared替换成一个高强度密码。例如requirepass YourStrongPassword123!。这个密码之后在SpringBoot配置里要用到。daemonize配置守护进程模式确保daemonize yes这样Redis会在后台以守护进程运行。修改完配置后需要重启Redis服务使配置生效sudo systemctl restart redis-server检查服务状态和监听端口sudo systemctl status redis-server sudo netstat -tlnp | grep 6379你应该能看到Redis进程正在监听0.0.0.0:6379或你指定的IP地址。2.2 防火墙与云平台安全组配置即使Redis配置好了还有两道墙可能挡着你服务器本身的防火墙和云服务商的安全组。服务器防火墙如UFW/iptables如果服务器开启了防火墙需要放行Redis的默认端口6379。# 对于UFWUbuntu常见 sudo ufw allow 6379/tcp sudo ufw reload云平台安全组阿里云、腾讯云等这是最容易忽略的一点。你需要在云服务器的控制台找到该实例所属的安全组添加入站规则允许来源例如0.0.0.0/0表示所有IP或你的办公网络IP段访问TCP 6379端口。实操心得我遇到过无数次本地telnet服务器IP 6379端口不通排查了半天Redis配置最后发现是云平台安全组没开。所以连接不上时请按这个顺序排查1. Redis服务是否运行(status)。2. Redis配置(bind,protected-mode)。3. 服务器防火墙。4. 云平台安全组。2.3 连接测试与故障排查在服务器上配置完后强烈建议先在服务器本地用redis-cli测试一下基础功能然后再从远程测试。本地连接测试带密码redis-cli 127.0.0.1:6379 auth YourStrongPassword123! OK 127.0.0.1:6379 set test hello OK 127.0.0.1:6379 get test hello远程连接测试 在你的开发机上可以使用telnet或nc命令测试网络连通性telnet 你的服务器IP 6379如果连接成功会看到一个空白屏幕此时可以尝试输入Redis命令注意因为设置了密码直接操作会报错但这步只是为了测通网络。更专业的测试可以用redis-cli指定主机和密码连接redis-cli -h 你的服务器IP -p 6379 -a YourStrongPassword123!或者更安全的方式避免密码出现在历史命令中redis-cli -h 你的服务器IP -p 6379 输入 auth YourStrongPassword123!常见问题速查表问题现象可能原因排查命令/步骤Connection refused1. Redis服务未启动。2.bind配置错误未绑定到目标IP。3. 防火墙/安全组拦截。1.sudo systemctl status redis2. 检查redis.conf中bind行。3.sudo ufw status; 检查云控制台安全组。Connection timeout网络不通或者防火墙在“静默丢弃”包。telnet 服务器IP 6379traceroute查看路径。NOAUTH Authentication required未提供密码或密码错误。确认requirepass配置并在客户端连接时提供正确密码。DENIED Redis is running in protected modeprotected-mode为yes且未满足其解除条件绑定所有接口或设置密码。1. 设置强密码。2. 或仅测试bind 0.0.0.0并protected-mode no。3. SpringBoot中Redis的YML配置解析服务器端搞定后接下来就是客户端的活了。SpringBoot通过spring-boot-starter-data-redis这个starter极大地简化了Redis的集成。但“简化”不代表可以乱配YML里的每一个属性都值得琢磨。3.1 基础连接配置lettuce与Jedis的选择首先在pom.xml中引入依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency !-- 如果需要连接池额外引入commons-pool2 -- dependency groupIdorg.apache.commons/groupId artifactIdcommons-pool2/artifactId /dependencySpring Boot 2.x以后默认的Redis客户端是Lettuce它基于Netty支持异步和响应式编程连接实例是线程安全的可以在多线程环境中共享。而Jedis是更老牌、更直接的客户端每个连接实例不是线程安全的通常需要配合连接池使用。如何选择默认用Lettuce就好对于绝大多数普通应用Lettuce的性能和线程安全特性更省心。考虑Jedis的情况如果你的项目非常传统或者有历史包袱旧代码基于Jedis或者你需要对连接行为进行非常底层的、Lettuce不支持的精细控制。在application.yml中基础的配置骨架是这样的spring: redis: host: 你的服务器IP地址 # 例如: 192.168.1.100 或 redis.yourdomain.com port: 6379 password: YourStrongPassword123! # 与redis.conf中的requirepass一致 database: 0 # Redis默认有16个库(0-15)通常用0 timeout: 2000ms # 连接超时时间单位毫秒(ms) # 客户端类型默认就是lettuce通常不用显式指定 # client-type: lettuce参数解读与避坑password如果Redis没设密码这里可以不配或者留空。但生产环境强烈建议设置。databaseRedis的“逻辑数据库”。微服务架构下建议不同服务使用不同的database或者直接用不同的Redis实例避免key冲突和相互影响。timeout这个值很重要。它表示连接建立的超时时间不是读写超时。设得太短在网络波动时容易连接失败设得太长应用卡死等待的时间也长。2000ms2秒是个比较折中的起点可以根据网络状况调整。3.2 连接池深度配置性能的关键无论是Lettuce还是Jedis在生产环境下强烈建议配置连接池。数据库连接包括Redis连接的创建和销毁是昂贵的操作。连接池通过复用已创建的连接能显著提升性能尤其是在高并发场景下。在YML中连接池的配置通常在lettuce.pool或jedis.pool下spring: redis: host: 192.168.1.100 port: 6379 password: YourStrongPassword123! lettuce: # 如果使用默认的Lettuce就配置这个 pool: enabled: true # 启用连接池默认就是true但显式写出更清晰 max-active: 8 # 连接池最大连接数负值表示无限制。根据应用负载调整不是越大越好 max-idle: 8 # 连接池最大空闲连接数 min-idle: 0 # 连接池最小空闲连接数 max-wait: -1ms # 连接池最大阻塞等待时间负值表示无限等待 # 如果非要使用Jedis配置如下 # jedis: # pool: # enabled: true # max-active: 8 # max-idle: 8 # min-idle: 0 # max-wait: -1ms连接池参数调优经验max-active这是最重要的参数。设置太小高并发时请求需要等待或创建新连接导致延迟设置太大会浪费服务器和Redis资源。一个常见的起始估算公式是应用实例数 * (max-active) Redis的maxclients配置。Redis默认maxclients是10000但也要留有余地。对于单个普通应用实例8-20是个常见范围。一定要通过监控观察连接数使用情况来调整。max-idle和min-idlemax-idle通常设置成和max-active一样或略小保证空闲连接能被复用。min-idle可以设置一个较小值如2确保始终有“热”连接可用避免突发请求时临时建连的开销。max-wait当连接池耗尽新请求获取连接的等待时间。设为-1ms无限等待可能导致请求线程长时间挂起通常建议设一个合理值如1000ms超时后抛出异常便于降级处理。一个我踩过的坑曾经有个项目max-active设了50但max-idle是默认的8。在流量高峰时瞬间创建了大量连接接近50高峰过后这些连接逐渐释放但只保留了8个空闲连接其余的都被关闭了。下一个高峰来临又需要大量创建连接导致Redis侧看到大量的CONNECT和CLOSE命令增加了CPU开销。后来把max-idle也调到20连接复用率明显提升Redis负载也更平稳。3.3 高级配置与序列化定制基础连接和连接池配好了应用能跑了但想要用得顺手、不出错还得关注序列化和一些高级特性。序列化配置关键Spring Data Redis默认使用JdkSerializationRedisSerializer。它有个大问题序列化后的key和value包含类信息在Redis里看起来是一堆乱码不具可读性而且不同Java版本可能不兼容。我们通常需要自定义序列化方式。常见的做法是配置一个RedisTemplate的Bean使用StringRedisSerializer来序列化key用Jackson2JsonRedisSerializer或GenericJackson2JsonRedisSerializer来序列化value存储为JSON字符串。Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(connectionFactory); // 设置key的序列化器 StringRedisSerializer stringSerializer new StringRedisSerializer(); template.setKeySerializer(stringSerializer); template.setHashKeySerializer(stringSerializer); // 设置value的序列化器 (使用Jackson将对象序列化为JSON字符串) Jackson2JsonRedisSerializerObject jsonSerializer new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); jsonSerializer.setObjectMapper(objectMapper); template.setValueSerializer(jsonSerializer); template.setHashValueSerializer(jsonSerializer); template.afterPropertiesSet(); return template; } }注意使用GenericJackson2JsonRedisSerializer会在JSON中写入类类型信息class这有助于反序列化时还原到具体类型但也会使存储的字符串稍长且存在一定的安全风险反序列化漏洞。对于类型明确、安全的场景也可以使用Jackson2JsonRedisSerializerYourClass指定具体类型。SSL/TLS与哨兵/集群配置SSL如果Redis服务器启用了SSL例如云服务商的托管Redis需要在YML中配置spring: redis: ssl: true # 可能还需要配置信任证书等视服务器要求而定哨兵模式用于高可用。配置方式如下重点是sentinel节点。spring: redis: sentinel: master: mymaster # 主节点名称 nodes: sentinel1:26379,sentinel2:26379,sentinel3:26379 # 哨兵节点列表 password: yourpassword # 如果主从有密码 database: 0集群模式用于分布式和数据分片。配置方式如下cluster节点指定集群节点和重定向设置。spring: redis: cluster: nodes: 192.168.1.101:6379,192.168.1.102:6379,192.168.1.103:6379 # 集群节点列表至少一个 max-redirects: 3 # 最大重定向次数 password: yourpassword # 集群密码 timeout: 2000ms4. 完整配置示例与验证把上面的配置组合起来一个面向生产环境、相对完整的application.yml配置示例如下以单节点Lettuce连接池为例spring: application: name: demo-app redis: host: prod-redis.yourcompany.com # 生产环境建议用域名 port: 6379 password: ${REDIS_PASSWORD:defaultWeakPassword} # 强烈建议从环境变量读取密码 database: 0 timeout: 2000ms connect-timeout: 1000ms # 连接超时Spring Boot 2.3 lettuce: pool: enabled: true max-active: 16 # 根据压测调整 max-idle: 16 min-idle: 2 max-wait: 1000ms # 获取连接最大等待时间 time-between-eviction-runs: 30000ms # 空闲连接逐出检查间隔 shutdown-timeout: 100ms # 关闭超时时间 # 如果使用SSL # ssl: true logging: level: org.springframework.data.redis: DEBUG # 调试时可开启查看连接详情配置验证 写一个简单的测试类或单元测试注入RedisTemplate或StringRedisTemplate执行一个简单的set和get操作确保一切正常。import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate; import static org.assertj.core.api.Assertions.assertThat; SpringBootTest public class RedisConnectionTest { Autowired private StringRedisTemplate stringRedisTemplate; Test void testRedisConnection() { String key test:config; String value Hello from Spring Boot; stringRedisTemplate.opsForValue().set(key, value); String fetchedValue stringRedisTemplate.opsForValue().get(key); assertThat(fetchedValue).isEqualTo(value); System.out.println(Redis连接与操作测试成功); } }运行测试如果看到成功输出恭喜你从本地SpringBoot到服务器Redis的完整链路就打通了。5. 部署与运维中的注意事项配置写对了本地测试也通过了但一到部署环节尤其是用Jenkins、Docker、K8s部署时又可能冒出新的问题。配置分离与密码管理把数据库密码、Redis密码等敏感信息直接写在application.yml里提交到代码库是大忌。正确的做法是使用环境变量或配置中心。环境变量如上例所示使用${REDIS_PASSWORD:}语法。在服务器上通过export REDIS_PASSWORDxxx或在Dockerfile、K8s Deployment的env中设置。配置中心如Spring Cloud Config, Apollo, Nacos等将配置集中管理。多环境配置开发、测试、生产环境的Redis地址、密码肯定不同。利用Spring Boot的Profile特性# application-dev.yml spring: redis: host: localhost password: devPassword # application-prod.yml spring: redis: host: prod-redis.yourcompany.com password: ${REDIS_PASSWORD}通过启动参数--spring.profiles.activeprod来激活生产环境配置。连接泄漏监控即使配置了连接池代码中没有正确释放连接例如在使用RedisConnection时未关闭也会导致连接泄漏。建议统一使用RedisTemplate它帮我们管理了连接的获取和释放。如果必须使用底层RedisConnection务必在try-with-resources或finally块中确保close()被调用。在Redis服务器上定期使用CLIENT LIST命令查看连接数和空闲时间监控异常的长连接。网络延迟与超时重试跨机房或公网访问Redis网络延迟和抖动是常态。除了设置合理的timeout还可以考虑在客户端增加重试机制。Lettuce本身支持一些重试但对于业务逻辑可能需要更灵活的策略比如使用Spring Retry注解或 Resilience4j等熔断器框架。最后一个小技巧在Spring Boot Actuator中有一个/actuator/redis端点需要引入spring-boot-starter-actuator并暴露该端点可以查看Redis连接工厂的详细信息包括客户端类型、连接数等在运维排查问题时非常有用。整个配置过程从服务器端的网络绑定、安全加固到客户端的连接池调优、序列化定制再到部署时的配置管理环环相扣。理解每一步背后的原理才能在各种环境下游刃有余快速定位和解决问题。希望这份结合了原理和实战经验的梳理能让你下次配置Redis时更加从容。
返回列表