单服务器Docker Redis缓存集群搭建及Spring Boot适配实践

单服务器Docker Redis缓存集群搭建及Spring Boot适配实践

缓存是微服务架构中提升性能、减轻数据库压力的核心,Redis凭借高性能成为主流方案。单节点Redis存在单点故障风险,主从+哨兵集群可实现读写分离与故障自动转移,保障高可用。

本文针对中小型项目单服务器场景,详细介绍Docker容器化搭建Redis主从+哨兵集群(统一目录运维)、Spring Boot用户缓存适配,补充缓存三大异常解决方案及故障排查,助力快速落地生产级缓存架构。

摘要:针对单服务器部署场景,提出Docker容器化Redis主从+哨兵集群方案,解决单点故障、IP动态变化、配置兼容等问题;实现Spring Boot缓存服务适配,提供缓存穿透、击穿、雪崩解决方案,通过验证确保集群高可用。方案部署简单、运维便捷,适用于中小型项目生产落地。

关键词:Docker;Redis主从集群;Redis哨兵;Spring Boot;缓存适配


一、单服务器Docker搭建Redis主从+哨兵集群(目录统一管理)

1. 集群设计思路

单服务器采用"不同端口模拟多节点",结合Docker Compose一键编排,所有集群目录统一至/docker/redis-ha-docker,简化运维。节点规划贴合生产端口规范,具体如下:

  • 主节点(master):6379端口(核心写节点,同步数据至从节点,负责数据持久化)
  • 从节点1(slave1):6380端口;从节点2(slave2):6381端口(均为读节点,分担并发、冗余备份)
  • 哨兵1-3:端口26379、26380、26381(监控节点,协同判断故障、执行故障转移,满足quorum=2)

核心优势:哨兵冗余避免监控失效;主从读写分离提升并发;Docker环境隔离;目录统一便于运维;适配主节点IP动态变化,解决容器重启失联问题。

2. 环境准备

确保服务器满足以下要求,避免部署失败:

  • 系统:CentOS 7/8或Ubuntu 20.04+,内存≥2GB;
  • 组件:Docker≥20.10、Docker Compose≥2.10,启动并设置开机自启;
  • 端口:放行6379、6380、6381、26379、26380、26381(防火墙、安全组同步配置);
  • 目录:执行命令创建统一结构,路径可调整但需保持后续配置一致:
bash 复制代码
mkdir -p /docker/redis-ha-docker/{master,slave1,slave2,sentinel1,sentinel2,sentinel3}
cd /docker/redis-ha-docker

3. 编写Docker Compose文件(核心编排)

在集群根目录创建docker-compose.yml,适配Redis 7.0.15,核心解决主节点IP动态变化问题,内容如下:

yaml 复制代码
version: '3.8'

services:
  # 主节点
  redis-master:
    image: redis:7.0-alpine
    container_name: redis-master
    ports:
      - "6379:6379"
    volumes:
      - ./master/redis.conf:/etc/redis/redis.conf  # 路径对应redis-ha-docker下的master目录
      - ./master/data:/data
    command: redis-server /etc/redis/redis.conf
    restart: always
    networks:
      redis-network:
        aliases:
          - redis-master  

  # 从节点1
  redis-slave1:
    image: redis:7.0-alpine
    container_name: redis-slave1
    ports:
      - "6380:6379"
    volumes:
      - ./slave1/redis.conf:/etc/redis/redis.conf  # 路径对应redis-ha-docker下的slave1目录
      - ./slave1/data:/data
    command: redis-server /etc/redis/redis.conf
    restart: always
    depends_on:
      - redis-master
    networks:
      - redis-network

  # 从节点2
  redis-slave2:
    image: redis:7.0-alpine
    container_name: redis-slave2
    ports:
      - "6381:6379"
    volumes:
      - ./slave2/redis.conf:/etc/redis/redis.conf  # 路径对应redis-ha-docker下的slave2目录
      - ./slave2/data:/data
    command: redis-server /etc/redis/redis.conf
    restart: always
    depends_on:
      - redis-master
    networks:
      - redis-network

  # 哨兵1 核心逻辑:1个哨兵检测到主节点故障→标记主观下线→询问其他哨兵→≥2个哨兵确认→标记客观下线→选举1个主导哨兵执行故障转移
  redis-sentinel1:
    image: redis:7.0-alpine
    container_name: redis-sentinel1
    ports:
      - "26379:26379"
    volumes:
      - ./sentinel1/sentinel.conf:/etc/redis/sentinel.conf  # 路径对应redis-ha-docker下的sentinel1目录
    command: redis-sentinel /etc/redis/sentinel.conf
    restart: always
    depends_on:
      - redis-master
      - redis-slave1
      - redis-slave2
    networks:
      - redis-network

  # 哨兵2(与哨兵1、3配置一致,参与投票协商,不单独触发故障转移)
  redis-sentinel2:
    image: redis:7.0-alpine
    container_name: redis-sentinel2
    ports:
      - "26380:26379"
    volumes:
      - ./sentinel2/sentinel.conf:/etc/redis/sentinel.conf  # 路径对应redis-ha-docker下的sentinel2目录
    command: redis-sentinel /etc/redis/sentinel.conf
    restart: always
    depends_on:
      - redis-master
      - redis-slave1
      - redis-slave2
    networks:
      - redis-network

  # 哨兵3(与哨兵1、2配置一致,quorum=2,需至少2个哨兵确认主节点故障才触发转移)
  redis-sentinel3:
    image: redis:7.0-alpine
    container_name: redis-sentinel3
    ports:
      - "26381:26379"
    volumes:
      - ./sentinel3/sentinel.conf:/etc/redis/sentinel.conf  # 路径对应redis-ha-docker下的sentinel3目录
    command: redis-sentinel /etc/redis/sentinel.conf
    restart: always
    depends_on:
      - redis-master
      - redis-slave1
      - redis-slave2
    networks:
      - redis-network

networks:
  redis-network:
    driver: bridge

4. 编写各节点配置文件

所有配置文件对应挂载目录创建,适配Redis 7.0.15,删除无效配置,确保集群稳定运行。

(1)主节点配置(./master/redis.conf)
bash 复制代码
bind 0.0.0.0
protected-mode no
port 6379
daemonize no  # Docker环境必须设为no,避免容器退出
pidfile /var/run/redis_6379.pid
logfile "redis_6379.log"
dir /data

# 双重持久化,兼顾安全与性能
rdbcompression yes
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec
replica-read-only yes  # 从节点只读,保证数据一致
(2)从节点配置(./slave1/redis.conf、./slave2/redis.conf)

两者配置一致,仅目录不同,核心添加主节点指向:

bash 复制代码
bind 0.0.0.0
protected-mode no
port 6379
daemonize no
pidfile /var/run/redis_6379.pid
logfile "redis_6379.log"
dir /data

replicaof redis-master 6379  # 指向主节点别名,适配IP动态变化
replica-read-only yes

# 持久化配置与主节点一致
rdbcompression yes
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec
(3)哨兵配置(3个哨兵一致,以./sentinel1/sentinel.conf为例)
bash 复制代码
port 26379
daemonize no
pidfile /var/run/redis-sentinel_26379.pid
logfile "sentinel_26379.log"
dir /data

# 监控主节点,quorum=2(至少2个哨兵确认故障)
sentinel monitor mymaster redis-master 6379 2

# 核心兼容配置(适配Redis 7.0.15,解决解析报错)
protected-mode no
sentinel resolve-hostnames yes  # 开启主机名解析

# 超时与故障转移配置
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel down-after-milliseconds mymaster 30000  # 30秒无响应标记主观下线
sentinel failover-timeout mymaster 180000  # 故障转移超时3分钟
sentinel parallel-syncs mymaster 1  # 每次同步1个从节点,避免集群压力

说明:3个哨兵配置分别放入对应目录,无需修改IP,均沿用主节点别名,彻底规避配置兼容及解析报错。

5. 集群启动与验证

/docker/redis-ha-docker目录执行以下命令,完成启动与验证,确保集群正常运行:

bash 复制代码
# 一键启动所有节点
docker-compose up -d

# 查看容器状态(确保所有容器Up)
docker-compose ps

# 验证主从关系(主节点应显示2个从节点)
docker exec -it redis-master redis-cli info replication

# 验证哨兵状态(应显示监控1个主节点、2个从节点、3个哨兵)
docker exec -it redis-sentinel1 redis-cli -p 26379 info sentinel

# 验证主节点IP动态变化适配(重启主节点后重新验证哨兵状态)
docker restart redis-master
sleep 10
docker exec -it redis-sentinel1 redis-cli -p 26379 info sentinel

6. 故障转移测试

测试故障转移功能,确保集群高可用:

bash 复制代码
# 停止主节点,模拟故障
docker stop redis-master

# 30秒后查询新主节点(应为slave1或slave2)
docker exec -it redis-sentinel1 redis-cli -p 26379 sentinel get-master-addr-by-name mymaster

# 重启原主节点,验证其作为从节点重新加入集群
docker start redis-master
docker exec -it redis-master redis-cli info replication

二、Spring Boot用户缓存服务适配

1. 配置文件修改(application.yml)

核心配置哨兵节点地址,与Redis集群端口对应,确保服务正常连接集群:

yaml 复制代码
spring:
  redis:
    sentinel:
      master: mymaster  # 与哨兵配置中主节点名称一致
      nodes: 192.168.1.10:26379,192.168.1.10:26380,192.168.1.10:26381  # 替换为服务器IP
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
    timeout: 2000ms

user:
  cache:
    expire: 3600  # 缓存默认过期时间1小时
    hot-user-ids: 1,2,3  # 热点用户ID,用于缓存优化

2. Docker部署Spring Boot服务(可选)

容器化部署服务,与Redis集群协同工作,步骤如下:

(1)编写Dockerfile
sql 复制代码
FROM openjdk:8-jre-alpine
WORKDIR /app
COPY target/redis-user-cache-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
(2)打包与启动
perl 复制代码
# 打包Spring Boot项目
mvn clean package -DskipTests

# 构建镜像
docker build -t user-cache-service:1.0 .

# 启动容器,加入Redis集群网络
docker run -d --name user-cache -p 8080:8080 &#xA  --network redis-network &#xA  -e SPRING_REDIS_SENTINEL_NODES=192.168.1.10:26379,192.168.1.10:26380,192.168.1.10:26381 &#xA  user-cache-service:1.0

3. 服务验证

访问接口验证缓存功能正常,确保适配无误:

  • 缓存命中/未命中:访问http://服务器IP:8080/user/1
  • 空值缓存:访问http://服务器IP:8080/user/999
  • 缓存更新:调用更新接口,验证缓存同步更新。

4. 缓存三大异常解决方案(适配当前集群)

针对缓存穿透、击穿、雪崩,结合Redis集群特性,提供可落地、无侵入解决方案,与业务逻辑兼容。

(1)缓存穿透

问题:请求不存在的用户ID,穿透缓存直击数据库,导致数据库压力激增。

解决方案:空值缓存+布隆过滤器双兜底:

  1. 空值缓存:查询数据库无结果时,缓存"null"标记(过期30秒),避免重复穿透;
  2. 布隆过滤器:项目启动时加载所有有效用户ID至Redis Set,请求先校验ID是否存在,不存在直接返回404。
(2)缓存击穿

问题:热点用户缓存过期瞬间,大量并发请求穿透至数据库。

解决方案:互斥锁+热点数据永不过期:

  1. 互斥锁:缓存未命中时,通过Redis SetNx获取分布式锁,获取成功查询数据库更新缓存,失败则重试;
  2. 热点数据永不过期:针对配置中热点用户,后台定时(每1小时)刷新缓存,确保缓存始终有效。
(3)缓存雪崩

问题:大量缓存同时过期,或Redis集群故障,导致所有请求穿透至数据库,引发数据库雪崩。

解决方案:过期时间随机化+集群高可用+降级熔断:

  1. 过期时间随机化:缓存设置基础过期时间+随机偏移量(10-60秒),避免缓存集中过期;
  2. 集群高可用:依托Redis主从+哨兵集群,主节点故障时哨兵自动切换新主节点,避免缓存服务中断;
  3. 降级熔断:通过Sentinel等组件监控数据库压力,压力过高时熔断缓存穿透请求,返回默认数据。

三、常见故障排查与注意事项

1. 常见故障排查

  • 哨兵启动报错:检查配置文件,确保无Redis 7.0.15不支持的配置(如resolve-ip、known-master);
  • 主从同步失败:确认从节点配置中replicaof指向主节点别名,主从节点网络连通;
  • 容器启动失败:查看容器日志(docker logs 容器名),排查配置挂载路径错误、端口冲突;
  • 缓存适配失败:检查Spring Boot配置中哨兵节点地址、主节点名称,确保与集群一致。

2. 注意事项

  • 所有哨兵配置需完全一致,同步更新,避免哨兵协同异常;
  • 目录路径、端口、网络别名需保持统一,避免配置混乱;
  • 生产环境需定期备份Redis数据(挂载目录备份),避免数据丢失;
  • 根据业务压力调整Redis连接池、过期时间等参数,优化性能。

相关推荐
学到头秃的suhian1 天前
Redis缓存
数据库·redis·缓存
苏渡苇1 天前
Java + Redis + MySQL:工业时序数据缓存与持久化实战(适配高频采集场景)
java·spring boot·redis·后端·spring·缓存·架构
mqffc1 天前
spring session、spring security和redis整合的简单使用
redis·spring·bootstrap
indexsunny1 天前
互联网大厂Java面试实战:Spring Boot到Kafka的技术问答解析
java·spring boot·redis·junit·kafka·spring security·microservices
流氓也是种气质 _Cookie1 天前
Linux上安装Docker
linux·redis·docker
茶杯梦轩1 天前
从零起步学习Redis || 第十章:主从复制的实现流程与常见问题处理方案深层解析
服务器·redis
Wzx1980121 天前
高并发秒杀下,如何避免 Redis 分布式锁的坑?
数据库·redis·分布式
小毅&Nora1 天前
【后端】【Redis】④ Redis 7/8 TopK 新特性:从“热搜榜”到“实时风控”,一文彻底掌握高频元素统计神器
redis·缓存·bloom
brucelee1861 天前
创建AWS ElastiCache Redis
redis·云计算·aws
独自破碎E1 天前
怎么知道本地的Redis有没有设置密码
数据库·redis·缓存