You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用go-redis连接Docker Redis集群持续出现i/o timeout错误

问题

我通过Docker部署了一个包含6个节点(端口7000-7005)的Redis集群,每个节点使用的redis.conf配置如下:

bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
protected-mode no

对应的docker-compose.yaml配置为:

version: "3.9"
services:
  redis-node-1:
    container_name: redis-node-1
    image: redis/redis-stack-server:latest
    volumes:
      - ./build/redis/redis.conf:/usr/local/etc/redis/redis.conf
      - ./data/redis-node-1:/data
    ports:
      - "7000:7000"
      - "17000:17000"
    entrypoint: [ "redis-server", "/usr/local/etc/redis/redis.conf", --port,"7000" ]
    networks:
      redis_cluster_network:
        ipv4_address: 173.18.0.5

  redis-node-2:
    container_name: redis-node-2
    image: redis/redis-stack-server:latest
    volumes:
      - ./build/redis/redis.conf:/usr/local/etc/redis/redis.conf
      - ./data/redis-node-2:/data
    ports:
      - "7001:7001"
      - "17001:17001"
    entrypoint: [ "redis-server", "/usr/local/etc/redis/redis.conf", --port,"7001" ]
    networks:
      redis_cluster_network:
        ipv4_address: 173.18.0.6

  redis-node-3:
    container_name: redis-node-3
    image: redis/redis-stack-server:latest
    volumes:
      - ./build/redis/redis.conf:/usr/local/etc/redis/redis.conf
      - ./data/redis-node-3:/data
    ports:
      - "7002:7002"
      - "17002:17002"
    entrypoint: [ "redis-server", "/usr/local/etc/redis/redis.conf", --port,"7002" ]
    networks:
      redis_cluster_network:
        ipv4_address: 173.18.0.7

  redis-node-4:
    container_name: redis-node-4
    image: redis/redis-stack-server:latest
    volumes:
      - ./build/redis/redis.conf:/usr/local/etc/redis/redis.conf
      - ./data/redis-node-4:/data
    ports:
      - "7003:7003"
      - "17003:17003"
    entrypoint: [ "redis-server", "/usr/local/etc/redis/redis.conf", --port,"7003" ]
    depends_on:
      - redis-node-1
      - redis-node-2
      - redis-node-3
    networks:
      redis_cluster_network:
        ipv4_address: 173.18.0.8

  redis-node-5:
    container_name: redis-node-5
    image: redis/redis-stack-server:latest
    volumes:
      - ./build/redis/redis.conf:/usr/local/etc/redis/redis.conf
      - ./data/redis-node-5:/data
    ports:
      - "7004:7004"
      - "17004:17004"
    entrypoint: [ "redis-server", "/usr/local/etc/redis/redis.conf", --port,"7004" ]
    depends_on:
      - redis-node-1
      - redis-node-2
      - redis-node-3
    networks:
      redis_cluster_network:
        ipv4_address: 173.18.0.9

  redis-node-6:
    container_name: redis-node-6
    image: redis/redis-stack-server:latest
    volumes:
      - ./build/redis/redis.conf:/usr/local/etc/redis/redis.conf
      - ./data/redis-node-6:/data
    ports:
      - "7005:7005"
      - "17005:17005"
    entrypoint: [ "redis-server", "/usr/local/etc/redis/redis.conf", --port,"7005" ]
    depends_on:
      - redis-node-1
      - redis-node-2
      - redis-node-3
    networks:
      redis_cluster_network:
        ipv4_address: 173.18.0.10

  redis-cluster-creator:
    container_name: redis-cluster-creator
    image: redis/redis-stack-server:latest
    command: 'redis-cli -p 7002 --cluster create 173.18.0.5:7000 173.18.0.6:7001 173.18.0.7:7002 173.18.0.8:7003 173.18.0.9:7004 173.18.0.10:7005 --cluster-replicas 1 --cluster-yes'
    depends_on:
      - redis-node-1
      - redis-node-2
      - redis-node-3
      - redis-node-4
      - redis-node-5
      - redis-node-6
    networks:
      redis_cluster_network:
        ipv4_address: 173.18.0.11
networks:
  redis_cluster_network:
    driver: bridge
    ipam:
      driver: default
      config:
          - subnet: 173.18.0.0/16

但使用go-redis代码连接时:

redisClient := redis.NewClusterClient(&redis.ClusterOptions{
    Addrs:         cfg.RedisCache.Address,
    Password:      cfg.RedisCache.Password,
    PoolSize:      cfg.RedisCache.PoolSize,
    MaxRetries:    cfg.RedisCache.MaxRetries,
    ReadOnly:      true,
    RouteRandomly: true,
})
err = redisClient.ForEachShard(ctx, func(ctx context.Context, shard *redis.Client) error {
    return shard.Ping(ctx).Err()
})
if err != nil {
    apiLogger.Fatal(err)
}

总是收到类似dial tcp 173.18.0.7:7000: i/o timeout的错误。我已确认所有Redis节点正常运行,请问是否遗漏了某些配置?


解决思路及方案

问题根源

错误中的173.18.0.7:7000存在明显异常:173.18.0.7是redis-node-3的容器内网IP,对应端口应为7002,却被错误映射为7000。核心原因有两点:

  1. Redis集群节点默认会在nodes.conf中记录容器内网IP和端口,而外部应用无法直接访问容器内网地址,导致路由混乱;
  2. depends_on仅保证容器启动顺序,无法确保Redis服务完全就绪,集群创建可能在节点未初始化完成时执行,导致节点地址记录错误。

具体修复步骤

  1. 修改Redis配置,指定对外暴露的地址和端口
    在每个节点的redis.conf中添加集群公告配置,让节点向集群报告外部可访问的宿主机地址及对应端口:

    # 替换为你的宿主机IP或可被应用访问的地址
    cluster-announce-ip 192.168.xxx.xxx
    # 对应节点的业务端口,如redis-node-1填7000,redis-node-2填7001,以此类推
    cluster-announce-port 7000
    # 对应节点的集群总线端口(业务端口+10000),如redis-node-1填17000
    cluster-announce-bus-port 17000
    
  2. 添加健康检查,确保节点就绪后再创建集群
    在每个redis-node-*服务中添加健康检查,确保Redis服务完全启动:

    healthcheck:
      test: ["CMD", "redis-cli", "-p", "7000", "ping"] # 端口对应节点自身业务端口
      interval: 3s
      timeout: 3s
      retries: 5
    

    然后修改redis-cluster-creator的depends_on,依赖节点的健康状态:

    depends_on:
      redis-node-1:
        condition: service_healthy
      redis-node-2:
        condition: service_healthy
      redis-node-3:
        condition: service_healthy
      redis-node-4:
        condition: service_healthy
      redis-node-5:
        condition: service_healthy
      redis-node-6:
        condition: service_healthy
    
  3. 调整go-redis连接配置
    确保Addrs配置的是宿主机暴露的端口,而非容器内网IP,同时添加超时配置避免连接等待过久:

    import "time"
    
    redisClient := redis.NewClusterClient(&redis.ClusterOptions{
        Addrs:         []string{"192.168.xxx.xxx:7000", "192.168.xxx.xxx:7001", "192.168.xxx.xxx:7002", "192.168.xxx.xxx:7003", "192.168.xxx.xxx:7004", "192.168.xxx.xxx:7005"},
        Password:      cfg.RedisCache.Password,
        PoolSize:      cfg.RedisCache.PoolSize,
        MaxRetries:    cfg.RedisCache.MaxRetries,
        ReadOnly:      true,
        RouteRandomly: true,
        DialTimeout:   5 * time.Second,
        ReadTimeout:   3 * time.Second,
        WriteTimeout:  3 * time.Second,
    })
    
  4. 清理旧集群配置缓存
    删除./data/redis-node-*目录下的nodes.conf文件,避免旧的错误地址缓存影响新集群启动,然后重新执行docker-compose up -d。


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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 06:05:53