You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Java中用TestContainers搭建Redis集群遇JedisCluster超时问题求助

核心问题分析

你遇到的Cluster retry deadline exceeded和redis-cli重定向卡住问题,本质是Redis集群节点向客户端通告的是容器内部的IP与端口,而运行在宿主机的Jedis/redis-cli只能访问宿主机映射后的端口,无法直接连接容器内部地址,导致重定向指令无法执行,最终触发超时或卡住。


一、单节点集群修复方案

1. 调整容器启动命令,添加集群通告配置

启动容器后获取宿主机映射端口,重新配置Redis节点的通告地址,让节点向客户端暴露宿主机可访问的端口:

int basePort = 6379;
String redisPassword = "your-password";
Network network = Network.newNetwork();

RedisContainer redisContainer = new RedisContainer(DockerImageName.parse("redis:7.0.5"))
        .withExposedPorts(basePort)
        .withNetwork(network)
        .waitingFor(Wait.forListeningPort());

// 先启动容器获取映射端口
redisContainer.start();
int mappedPort = redisContainer.getMappedPort(basePort);

// 更新启动命令,添加集群通告地址
redisContainer.withCommand(
        "redis-server --port " + basePort +
        " --requirepass " + redisPassword +
        " --masterauth " + redisPassword +
        " --cluster-enabled yes" +
        " --cluster-config-file nodes.conf" +
        " --cluster-node-timeout 5000" +
        " --appendonly yes" +
        " --bind 0.0.0.0" +
        " --cluster-announce-ip 127.0.0.1" +
        " --cluster-announce-port " + mappedPort
);
redisContainer.restart();

// 执行槽位分配
redisContainer.execInContainer(
        "redis-cli", "--no-auth-warning", "-h", "localhost", "-p", String.valueOf(basePort),
        "-a", redisPassword, "cluster", "addslotsrange", "0", "16383"
);

2. JedisCluster连接验证

你的现有Jedis连接代码无需修改,因为已经使用了宿主机映射端口,和节点通告的端口一致,重新运行即可正常读写。


二、多节点集群修复方案

1. 启动并配置所有节点

先启动所有容器获取映射端口,再为每个节点添加集群通告配置,最后执行集群初始化命令:

int nodeCount = 6;
int basePort = 6379;
String redisPassword = "your-password";
Network network = Network.newNetwork();
List<RedisContainer> redisContainers = new ArrayList<>();
Set<HostAndPort> hostAndPorts = new HashSet<>();

// 第一步:启动所有节点(暂不配置集群通告)
for (int i = 0; i < nodeCount; i++) {
    int port = basePort + i;
    RedisContainer container = new RedisContainer(DockerImageName.parse("redis:7.0.5"))
            .withExposedPorts(port)
            .withCommand(
                    "redis-server --port " + port +
                    " --requirepass " + redisPassword +
                    " --masterauth " + redisPassword +
                    " --cluster-enabled yes" +
                    " --cluster-config-file nodes.conf" +
                    " --cluster-node-timeout 5000" +
                    " --appendonly yes" +
                    " --bind 0.0.0.0"
            )
            .withNetwork(network)
            .waitingFor(Wait.forListeningPort());
    container.start();
    redisContainers.add(container);
    int mappedPort = container.getMappedPort(port);
    hostAndPorts.add(new HostAndPort("127.0.0.1", mappedPort));
}

// 第二步:更新每个节点的集群通告配置并重启
for (int i = 0; i < redisContainers.size(); i++) {
    RedisContainer container = redisContainers.get(i);
    int originalPort = basePort + i;
    int mappedPort = container.getMappedPort(originalPort);
    container.withCommand(
            "redis-server --port " + originalPort +
            " --requirepass " + redisPassword +
            " --masterauth " + redisPassword +
            " --cluster-enabled yes" +
            " --cluster-config-file nodes.conf" +
            " --cluster-node-timeout 5000" +
            " --appendonly yes" +
            " --bind 0.0.0.0" +
            " --cluster-announce-ip 127.0.0.1" +
            " --cluster-announce-port " + mappedPort
    );
    container.restart();
}

// 第三步:执行集群初始化命令(在容器内执行,利用容器网络访问内部端口)
StringBuilder clusterCreateCmd = new StringBuilder("redis-cli --no-auth-warning -a " + redisPassword + " --cluster create ");
for (HostAndPort hp : hostAndPorts) {
    clusterCreateCmd.append(hp.getHost()).append(":").append(hp.getPort()).append(" ");
}
clusterCreateCmd.append("--cluster-replicas 1 --cluster-yes");

redisContainers.get(0).execInContainer(
        "/bin/sh", "-c", clusterCreateCmd.toString()
);

2. JedisCluster连接验证

保持你现有Jedis连接代码不变,运行后即可正常进行集群读写操作,redis-cli -c也不会再卡在重定向步骤。


额外注意事项

  • 确保所有节点的--masterauth--requirepass配置完全一致,避免节点间通信认证失败。
  • 单节点集群仅适合测试场景,Redis官方不推荐生产环境使用。
  • 执行集群初始化时添加--cluster-yes参数,可跳过交互确认步骤。

内容的提问来源于stack exchange,提问作者djGowda

火山引擎 最新活动