八年 Java 开发实战:Redis 3 主 3 从六台集群部署全指南(附测试环境配置解析与避坑手册)
作为一名摸爬滚打八年的 Java 开发,从初期单体项目里的 Redis 单节点,到后来电商秒杀、支付对账等高并发场景,踩过的 Redis 坑两只手都数不完 —— 单节点内存溢出、主从同步延迟导致数据不一致、集群脑裂…… 最近刚在测试环境落地一套 6 台 Redis 主从集群(3 主 3 从),正好结合全新的测试环境node.conf
配置,跟大家聊聊从业务需求到部署落地的全流程,带你避开那些 “一看就会,一配就跪” 的坑。
一、先聊业务:为什么要搞 6 台 Redis 主从集群?
别上来就闷头部署,先想清楚 “业务需要什么”—— 这是八年开发的第一个经验:技术是为业务服务的。
我这次在测试环境复现的是电商订单中台场景,核心诉求有三个:
- 高并发读写:测试环境模拟峰值 QPS 5k+,单节点 Redis(就算开了持久化)扛不住,必须分片分担压力;
- 高可用验证:模拟主节点宕机场景,确保从节点能自动顶上去,避免业务中断;
- 数据安全兜底:订单、库存测试数据不能丢,主从同步 + 持久化必须到位,为生产部署铺路。
基于这三点,6 台机器(3 主 3 从)是测试环境性价比最高的选择:
- 分片:3 个主节点把 Redis 的 16384 个槽位均分(0-5460、5461-10922、10923-16383),每台主节点扛 1/3 读写压力,贴近生产真实负载;
- 高可用:每个主节点挂 1 个从节点,主节点宕机后从节点能自动故障转移,验证集群容错能力;
- 成本平衡:6 台测试机(2 核 4G 配置)足够模拟生产场景,比搞 9 台、12 台更省资源,运维也简单。
二、解析测试环境node.conf
:看清集群拓扑
拿到测试环境的node.conf
关键信息,第一步不是配机器,而是 “拆解集群结构”—— 这是避免部署混乱的核心。先把 6 个节点的角色、IP、端口、槽位对应清楚,后续部署才不会出错:
节点 ID(nodeId) | IP 地址 | 业务端口 | 集群总线端口 | 角色 | 所属主节点 ID(masterId) | 负责槽位范围 |
---|---|---|---|---|---|---|
a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b | 192.168.56.240 | 7001 | 17001 | master(主) | 无(自身是主) | 0-5460 |
b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c | 192.168.56.240 | 7002 | 17002 | master(主) | 无(自身是主) | 10923-16383 |
c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d | 192.168.56.241 | 7003 | 17003 | master(主) | 无(自身是主) | 5461-10922 |
d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e | 192.168.56.241 | 7004 | 17004 | slave(从) | a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b | 无(同步主节点槽位) |
e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f | 192.168.56.242 | 7005 | 17005 | slave(从) | b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c | 无(同步主节点槽位) |
f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a | 192.168.56.242 | 7006 | 17006 | slave(从) | c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d | 无(同步主节点槽位) |
关键信息解读:
- 3 个主节点跨 3 台测试机部署(240 有 2 个主节点、241 有 1 个主节点),避免 “单机器宕机导致多主挂掉”,贴近生产 “跨节点容灾” 逻辑;
- 从节点同样跨机器:241 的 7004 同步 240 的 7001,242 的 7005 同步 240 的 7002,242 的 7006 同步 241 的 7003—— 就算某台测试机宕机,主从也不会同时挂;
- 集群总线端口:都是 “业务端口 + 10000”(7001→17001、7002→17002),这是 Redis Cluster 用于主从通信、故障检测的关键端口,必须开放,否则节点间无法握手。
三、部署全流程:从 0 到 1 搭建 6 台测试集群(附核心配置)
接下来是实战步骤,每一步都带 “八年开发的经验注解”,避免你踩我在测试环境踩过的坑。
1. 环境准备(先做对基础,少走弯路)
-
操作系统:CentOS 7.x(测试环境和生产保持一致,避免兼容性问题);
-
Redis 版本:6.2.6(LTS 版本,稳定且修复了旧版本 bug,测试 / 生产统一版本);
-
机器规划:3 台测试机(192.168.56.240、241、242),每台部署 2 个 Redis 节点;
-
依赖安装:先装 gcc(Redis 编译需要),测试机可能没预装:
yum install -y gcc-c++
-
端口开放:每台测试机开放业务端口(7001-7006)和集群总线端口(17001-17006),命令:
# 开放端口(永久生效,重启防火墙也不会丢) firewall-cmd --add-port=7001-7006/tcp --permanent firewall-cmd --add-port=17001-17006/tcp --permanent # 刷新防火墙配置 firewall-cmd --reload
✅ 经验坑:第一次部署时忘开集群总线端口,导致
cluster create
时 “节点能 ping 通但无法加入集群”,排查了 2 小时才发现是端口没开放 —— 测试环境也要严格按生产标准配置!
2. 单节点 Redis 配置(核心是redis.conf
)
每台测试机上的 2 个节点,需要单独的配置文件和数据目录(避免端口冲突、数据混乱)。以 240 机器的 7001 节点为例,redis-7001.conf
核心配置如下(测试环境和生产配置保持一致,仅 IP / 端口不同):
# 1. 基础网络与运行配置
port 7001 # 业务端口,每节点不同
bind 192.168.56.240 # 绑定测试机IP,不要用127.0.0.1(其他机器连不上)
daemonize yes # 后台运行,测试机不需要前台占用终端
pidfile /var/run/redis-7001.pid # PID文件路径,区分不同节点
logfile "/var/log/redis/redis-7001.log" # 日志文件(排查问题的关键,必须配)
dir /data/redis/7001 # 数据目录(RDB/AOF、node.conf都存在这里)
# 2. 集群核心配置(必须开启,否则是单节点)
cluster-enabled yes # 开启集群模式
cluster-config-file nodes-7001.conf # 集群节点配置文件(Redis自动生成/更新,不用手动改)
cluster-node-timeout 15000 # 节点超时时间(15秒,超过视为宕机,测试环境可适当缩短)
cluster-port 17001 # 集群总线端口(6.2+版本支持显式配置,旧版本隐式+10000)
# 3. 持久化配置(测试环境也要开,模拟数据安全)
appendonly yes # 开启AOF持久化(实时记录写操作,避免测试数据丢失)
appendfsync everysec # 每秒刷盘一次(平衡性能和安全性,生产也用这个)
save 900 1 # 900秒内1次写操作生成RDB快照
save 300 10 # 300秒内10次写操作生成RDB快照
# 4. 性能与安全配置(贴近生产)
maxmemory 2gb # 每节点最大内存(2核4G测试机配2gb,避免内存溢出)
maxmemory-policy allkeys-lru # 内存满了按LRU淘汰键(测试/生产逻辑一致)
requirepass "testRedis@2024" # Redis密码(测试环境也要加,避免未授权访问)
masterauth "testRedis@2024" # 主从同步密码(和requirepass一致,否则同步失败)
配置复制与修改技巧:
- 240 机器的 7002 节点:复制
redis-7001.conf
为redis-7002.conf
,全局替换 “7001” 为 “7002”(port、pidfile、logfile、dir、cluster-config-file、cluster-port),IP 保持 192.168.56.240; - 241 机器的 7003、7004 节点:复制上述配置,替换 IP 为 192.168.56.241,端口分别为 7003/17003、7004/17004;
- 242 机器的 7005、7006 节点:IP 替换为 192.168.56.242,端口分别为 7005/17005、7006/17006;
- 所有节点的
requirepass
和masterauth
必须一致!否则主从同步会报 “NOAUTH Authentication required”,测试环境别图省事省略密码。
3. 启动所有 Redis 节点
在 3 台测试机上分别启动 2 个节点,顺序不影响,确保进程都起来即可:
# 240机器启动7001、7002
redis-server /etc/redis/redis-7001.conf
redis-server /etc/redis/redis-7002.conf
# 241机器启动7003、7004
redis-server /etc/redis/redis-7003.conf
redis-server /etc/redis/redis-7004.conf
# 242机器启动7005、7006
redis-server /etc/redis/redis-7005.conf
redis-server /etc/redis/redis-7006.conf
验证启动结果:在每台机器上执行ps -ef | grep redis
,能看到对应端口的redis-server
进程(比如 240 机器有 7001、7002 两个进程),说明节点启动成功。
4. 初始化 Redis Cluster 集群
这一步是 “把 6 个孤立节点组成集群”,核心命令是redis-cli --cluster create
,在任意一台测试机上执行即可(比如 240 机器):
redis-cli -a testRedis@2024 --cluster create \
192.168.56.240:7001 \
192.168.56.240:7002 \
192.168.56.241:7003 \
192.168.56.241:7004 \
192.168.56.242:7005 \
192.168.56.242:7006 \
--cluster-replicas 1
命令解读:
-
-a testRedis@2024
:指定 Redis 密码(和配置文件中的requirepass
一致,没设密码可去掉); -
--cluster-replicas 1
:每个主节点分配 1 个从节点(6 个节点→3 主 3 从,正好匹配测试环境需求); -
执行后 Redis 会自动计算主从关系和槽位分配,你需要输入
yes
确认配置:Can I set the above configuration? (type 'yes' to accept): yes
✅ 经验技巧:测试环境可以用--cluster-replicas
自动分配主从,省得手动配置;如果想自定义主从关系(比如指定 241 的 7004 为 240 的 7001 从节点),可以先初始化主节点,再手动添加从节点,但没必要 —— 测试环境优先追求效率,模拟生产自动分配逻辑更有意义。
5. 验证集群状态(部署完必须做!)
测试环境部署完,一定要验证集群是否正常,不然后续测试用例跑不通,还得回头排查集群问题。
(1)查看集群节点信息
登录任意一个节点(比如 240 的 7001):
redis-cli -a testRedis@2024 -h 192.168.56.240 -p 7001
执行cluster nodes
,输出应该和前面的拓扑表一致,重点看三点:
- 每个主节点的
role:master
和槽位范围(比如 7001 的 0-5460); - 每个从节点的
role:slave
和master_id
(对应主节点的 nodeId,比如 7004 的 master_id 是 a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b); - 所有节点的状态都是
connected
(表示节点间通信正常)。
(2)检查集群健康状态
执行cluster health
,如果输出OK
,说明集群正常;如果有错误(比如 “slot xxxx not covered”),会提示具体问题(比如槽位未分配、节点断线),按提示修复即可。
(3)测试读写与槽位路由
在 7001 节点执行set order:1001 "paid"
(模拟订单状态存储),然后在 7002 节点执行get order:1001
——Redis 会自动路由到 7001 节点(因为order:1001
的哈希值落在 0-5460 槽位),返回"paid"
,说明分片和路由正常。
测试从节点同步:在 7001 节点执行set user:2001 "test"
,登录 7004 节点(7001 的从节点)执行get user:2001
,能返回"test"
,说明主从同步正常。
四、Java 客户端接入:测试环境实战代码(带最佳实践)
集群搭好后,Java 测试项目怎么接入?以 Spring Boot 项目为例,分享 “八年开发推荐的配置方式”,和生产接入逻辑保持一致。
1. 引入依赖(Spring Data Redis)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!-- 排除默认的lettuce客户端,用jedis(更稳定,测试环境排查问题方便) -->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入jedis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2. 核心配置(application-test.yml)
测试环境配置文件单独放application-test.yml
,和开发 / 生产环境隔离:
spring:
redis:
# Redis密码(和测试集群一致)
password: testRedis@2024
# 连接超时时间(毫秒,测试环境可短点,快速发现问题)
timeout: 2000
jedis:
pool:
max-active: 8 # 连接池最大连接数(测试环境5k QPS配8足够)
max-idle: 8 # 连接池最大空闲连接数
min-idle: 2 # 连接池最小空闲连接数
max-wait: -1 # 连接池最大阻塞等待时间(-1表示无限制)
cluster:
# 集群节点列表(所有主从节点都写上,客户端自动识别主从)
nodes:
- 192.168.56.240:7001
- 192.168.56.240:7002
- 192.168.56.241:7003
- 192.168.56.241:7004
- 192.168.56.242:7005
- 192.168.56.242:7006
# 最大重定向次数(Redis Cluster路由时的重定向,默认5次,测试环境设3次足够)
max-redirects: 3
3. 实战代码(Redis 工具类)
测试环境也要写规范的工具类,避免重复代码,同时方便后续迁移到生产:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Component
public class RedisClusterTestUtil {
private static final Logger log = LoggerFactory.getLogger(RedisClusterTestUtil.class);
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 存值(带过期时间,测试订单数据常用)
* @param key 键(比如order:1001)
* @param value 值(订单JSON或状态)
* @param timeout 过期时间(测试环境可设短点,比如30分钟)
* @param unit 时间单位
* @return 是否成功
*/
public boolean set(String key, Object value, long timeout, TimeUnit unit) {
try {
redisTemplate.opsForValue().set(key, value, timeout, unit);
log.info("Redis Cluster set success, key: {}, value: {}", key, value);
return true;
} catch (Exception e) {
// 八年开发经验:测试环境也要打日志!方便排查集群问题(比如节点断线)
log.error("Redis Cluster set key error, key: {}, value: {}", key, value, e);
return false;
}
}
/**
* 取值(测试用例验证数据常用)
* @param key 键
* @return 值(可能为null)
*/
public Object get(String key) {
try {
Object value = redisTemplate.opsForValue().get(key);
log.info("Redis Cluster get success, key: {}, value: {}", key, value);
return value;
} catch (Exception e) {
log.error("Redis Cluster get key error, key: {}", key, e);
return null;
}
}
// 其他常用方法(delete、hash操作、自增等)省略...
}
关键经验:
- 测试环境不要用
JedisCluster
直接实例化(手动管理连接池麻烦),用 Spring Data Redis 封装,和生产保持一致; - 必须加日志:测试环境模拟故障时(比如 down 掉主节点),日志能帮你快速定位 “是客户端问题还是集群问题”;
- 避免大 key:测试环境也要模拟生产规范,大 key(比如 100MB 以上)会导致单个节点压力过大,还会影响主从同步效率。
五、测试环境运维避坑指南:八年开发总结的 “血泪经验”
测试环境不是 “搭完就不管”,而是要模拟生产运维场景,提前发现问题。分享几个测试环境必须做的运维操作:
1. 监控配置(知道集群在干嘛)
测试环境也要配监控,为生产监控铺路:
-
监控工具:Prometheus + Grafana(装 Redis Exporter,测试机资源足够);
-
必监控指标:
- 节点存活状态(
redis_up
:1 表示存活,0 表示宕机); - 主从同步延迟(
redis_cluster_slave_offset_delay_bytes
:延迟超过 10MB 要告警,测试环境可设 5MB); - 内存使用率(
redis_memory_used_percentage
:超过 80% 要清理测试数据,避免内存溢出); - 槽位分配状态(
redis_cluster_slots_assigned
:确保 16384 个槽位都已分配,否则集群不可用)。
- 节点存活状态(
2. 故障转移测试(模拟生产宕机)
测试环境的核心目的是 “发现问题”,必须手动模拟主节点宕机:
-
步骤 1:登录 240 机器,down 掉 7001 主节点:
redis-cli -a testRedis@2024 -h 192.168.56.240 -p 7001 shutdown
-
步骤 2:登录 7004 节点(7001 的从节点),执行
cluster nodes
:能看到 7004 的角色从slave
变为master
,并接管 0-5460 槽位; -
步骤 3:测试业务可用性:用 Java 工具类执行
set order:1002 "unpaid"
,能正常写入(路由到新主节点 7004),说明故障转移成功; -
步骤 4:重启 7001 节点:
redis-server /etc/redis/redis-7001.conf
,再执行cluster nodes
:7001 会自动变为 7004 的从节点,同步新数据。
3. 数据备份与恢复测试(模拟数据丢失)
测试环境也要验证 “数据丢了能恢复”:
- 备份:在 7001 节点执行
bgsave
,生成 RDB 快照(路径在dir
配置的/data/redis/7001/dump.rdb
),复制到备份目录; - 恢复:删除 7001 节点的
dump.rdb
和appendonly.aof
,把备份的dump.rdb
放回去,重启 7001,执行get order:1001
能拿到之前的值,说明恢复成功。
4. 避免脑裂(测试环境也要防)
测试环境虽然数据不重要,但也要模拟生产配置,避免脑裂:
-
在所有节点的
redis.conf
中添加:cluster-require-full-coverage no
作用:部分槽位不可用时,集群仍能处理其他槽位的请求(默认是 yes,会导致整个集群不可用),贴近生产实际配置。
六、总结:测试环境集群是生产的 “预演”
作为八年 Java 开发,最后想跟大家说:测试环境的 Redis 集群不是 “走过场”,而是生产部署的 “预演”。你在测试环境踩的坑,都是未来生产环境的 “避坑指南”。
6 台 3 主 3 从集群,适合测试 QPS 5k-2w 的场景;如果测试 QPS 更低(1k 以下),单主双从足够;如果 QPS 更高(10w+),再考虑扩容或引入 Redis Cluster Proxy。核心是:测试环境要和生产环境 “同构”,配置、架构、运维逻辑保持一致,这样才能确保生产部署时 “一次成功”。
希望这篇测试环境部署指南能帮你少踩坑,有问题欢迎评论区交流~