使用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。核心原因有两点:
- Redis集群节点默认会在
nodes.conf中记录容器内网IP和端口,而外部应用无法直接访问容器内网地址,导致路由混乱; depends_on仅保证容器启动顺序,无法确保Redis服务完全就绪,集群创建可能在节点未初始化完成时执行,导致节点地址记录错误。
具体修复步骤
修改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添加健康检查,确保节点就绪后再创建集群
在每个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调整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, })清理旧集群配置缓存
删除./data/redis-node-*目录下的nodes.conf文件,避免旧的错误地址缓存影响新集群启动,然后重新执行docker-compose up -d。
内容的提问来源于stack exchange,提问作者scul0405
相关产品推荐
相关产品推荐

