go-redis 总是得到拨号 tcp i/o 超时

问题描述 投票:0回答:2

我已经使用 docker 构建了一个包含 6 个节点的 Redis 集群,端口来自

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

我错过了一些配置吗?

我已阅读 go-redis 指南。它告诉我,我应该等待所有 Redis 节点运行,然后再在 docker-compose 中运行应用程序。但我只将 docker-compose 用于 redis,不包括我的应用程序。我确信所有redis节点都已完成运行。而且这个错误仍然发生。

go redis go-redis redis-stack-server
2个回答
0
投票

我在尝试运行固定IP时也遇到了类似的问题,所以我发现如下:

这是 docker-compose.yml 的示例

version: '3'

networks:
  redis-cluster-compose:
    driver: bridge

services:
  redis-node-1:
    container_name: node1
    image: redis:latest
    ports:
      - 7000:7000
    networks:
      - redis-cluster-compose
    hostname: redis-node-1
    volumes:
      - ./7000:/redis
    command: redis-server /redis/redis.conf
  
  redis-node-2:
    container_name: node2
    image: redis:latest
    ports:
      - 7001:7001
    networks:
      - redis-cluster-compose
    hostname: redis-node-2
    volumes:
      - ./7001:/redis
    command: redis-server /redis/redis.conf

  redis-node-3:
    container_name: node3
    image: redis:latest
    ports:
      - 7002:7002
    networks:
      - redis-cluster-compose
    hostname: redis-node-3
    volumes:
      - ./7002:/redis
    command: redis-server /redis/redis.conf

  redis-cluster-creator:
    container_name: cluster-creator
    image: redis:latest
    ports:
      - 6999:6999
    networks:
      - redis-cluster-compose
    command: redis-cli -p 7000 --cluster create redis-node-1:7000 redis-node-2:7001 redis-node-3:7002 --cluster-replicas 0 --cluster-yes
    depends_on:
      - redis-node-1
      - redis-node-2
      - redis-node-3

这是

main.go

package main

import (
    "context"
    "fmt"
    "time"

    "github.com/redis/go-redis/v9"
)

func main() {
    rdb := redis.NewClusterClient(&redis.ClusterOptions{
        Addrs: []string{"localhost:7000", "localhost:7001", "localhost:7002"},
    })

    ctx := context.Background()

    // Writing data
    key, message := "test", fmt.Sprintf("[%s] Test", time.Now())
    err := rdb.Set(ctx, key, message, 0).Err()
    if err != nil {
        panic(err)
    }

    // Reading data
    val, err := rdb.Get(ctx, key).Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("key:", val)
}

备注:Go 程序不在 Docker 中运行,如果需要,可能需要对 URL 进行一些调整。


0
投票

活动部件太多。例如,网络部分完全不需要运行:

version: "3.9"

x-vars:
  redis-shared-config: &redis-shared-config
    entrypoint: [ "redis-server", "/usr/local/etc/redis/redis.conf", --port,"6379" ]
    image: redis/redis-stack-server:latest
    healthcheck:
      test: [ "CMD", "redis-cli", "ping" ]
      interval: 5s
      timeout: 5s
      retries: 5
    configs:
      - source: redis-conf
        target: /usr/local/etc/redis/redis.conf

configs:
  redis-conf:
    file: ./build/redis/redis.conf
volumes:
  redis-data-1:
  redis-data-2:
  redis-data-3:
  redis-data-4:
  redis-data-5:
  redis-data-6:

services:
  redis-node-1:
    container_name: redis-1
    <<: *redis-shared-config
    volumes:
      - "redis-data-1:/data"
  redis-node-2:
    container_name: redis-2
    <<: *redis-shared-config
    volumes:
      - "redis-data-2:/data"
  redis-node-3:
    container_name: redis-3
    <<: *redis-shared-config
    volumes:
      - "redis-data-3:/data"
  redis-node-4:
    container_name: redis-4
    <<: *redis-shared-config
    volumes:
      - "redis-data-4:/data"
  redis-node-5:
    container_name: redis-5
    <<: *redis-shared-config
    volumes:
      - "redis-data-5:/data"
  redis-node-6:
    container_name: redis-6
    <<: *redis-shared-config
    volumes:
      - "redis-data-6:/data"
  redis-cluster-creator:
    container_name: redis-cluster-creator
    image: redis/redis-stack-server:latest

    # Make the run of redis-cluster-creator service idempotent
    # by checking the cluster health before creating it.
    # We do this so that we can make our app a dependent service
    # of the redis-cluster-creator service.
    #
    # Explanation of the command:
    # If the cluster is already created the part before || will be
    # successful and exit with 0 and the part after || will not be executed.
    #
    # If the cluster is not created the part before || will
    # fail and the part after || will be executed.
    # If successful, the create command will exit with 0.
    command: |
      bash -c "redis-cli --cluster check redis-node-1:6379 || (echo Setting up redis cluster; redis-cli --cluster create redis-node-1:6379 redis-node-2:6379 redis-node-3:6379 redis-node-4:6379 redis-node-5:6379 redis-node-6:6379 --cluster-replicas 1 --cluster-yes)"
    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

  app:
    image: myapp:latest
    platform: linux/amd64
    build:
      context: ./build/app
    environment:
      - MY_APP_REDIS_ADDRESSES=redis-node-1:6379,redis-node-2:6379,redis-node-3:6379,redis-node-4:6379,redis-node-5:6379,redis-node-6:6379
    depends_on:
      redis-cluster-creator:
        condition: service_completed_successfully
      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

我将应用程序放在这里不仅仅是为了方便,而是为了必要:您指示 redis 绑定到

0.0.0.0
,大致翻译为

您可以掌握的每个IP地址。

现在,据我了解,这就是幕后发生的事情:您联系一个集群节点,请求一个密钥(所有内容都在 Redis 中的密钥后面),然后您将被重定向到分片的主节点保持所述值。但集群只知道该主机的内部IP,在您给出的示例中

173.18.0.7
。然而,它的 IP 范围很可能在您的网络上可用(这些是公共 IP),更不用说主机了,除非您碰巧为 MediaCom 工作或成为 MediaCom 的客户:

$ whois 173.18.0.7
% IANA WHOIS server
% for more information on IANA, visit http://www.iana.org
% This query returned 1 object

refer:        whois.arin.net

inetnum:      173.0.0.0 - 173.255.255.255
organisation: ARIN
status:       ALLOCATED

whois:        whois.arin.net

changed:      2008-02
source:       IANA

# whois.arin.net

NetRange:       173.16.0.0 - 173.31.255.255
CIDR:           173.16.0.0/12
NetName:        MEDIACOM-RESIDENTIAL-CUST
NetHandle:      NET-173-16-0-0-1
Parent:         NET173 (NET-173-0-0-0-0)
NetType:        Direct Allocation
OriginAS:       
Organization:   Mediacom Communications Corp (MCC-244)
RegDate:        2008-05-19
Updated:        2012-02-24
Ref:            https://rdap.arin.net/registry/ip/173.16.0.0


OrgName:        Mediacom Communications Corp
OrgId:          MCC-244
Address:        1 Mediacom Way
City:           Mediacom Park
StateProv:      NY
PostalCode:     10918
Country:        US
RegDate:        2008-02-05
Updated:        2018-08-29
Comment:        For abuse issues contact [email protected]
Ref:            https://rdap.arin.net/registry/entity/MCC-244

<skipped for brevity>

因此,最有可能的罪魁祸首是相当奇怪的网络配置。

您可以在

https://github.com/mwmahlberg/redis-78155633
找到 docker compose 以及用于测试的小型 Go 应用程序和随附的 Dockerfile

© www.soinside.com 2019 - 2024. All rights reserved.