在宿主机的springboot项目访问docker中的redis集群出错

本文介绍了一种在Docker环境中部署三节点Redis集群的方法,并解决了客户端连接超时的问题。通过自定义entrypoint脚本,实现了所有节点在一个容器内的配置,确保了集群节点信息的正确获取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述:在docker中部署了3个节点的cluster,使用java客户端连接,测试java客户端连接超时。

    @Bean
    public JedisCluster JedisClusterFactory() {
        Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
        jedisClusterNodes.add(new HostAndPort("localhost", 6380));
        jedisClusterNodes.add(new HostAndPort("localhost", 6381));
        jedisClusterNodes.add(new HostAndPort("localhost", 6382));
        JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes);
        return jedisCluster;
    }

docker环境如下:

KumasMBA:~ kumas$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
f3a8ac6612a6        redis:3.2-alpine    "docker-entrypoint..."   2 days ago          Up 3 hours          0.0.0.0:6382->6382/tcp   redis03
f43c6d1ae35e        redis:3.2-alpine    "docker-entrypoint..."   2 days ago          Up 3 hours          0.0.0.0:6381->6381/tcp   redis02
836c324c3dc1        redis:3.2-alpine    "docker-entrypoint..."   2 days ago          Up 3 hours          0.0.0.0:6380->6380/tcp   redis01

分析:debug后发现,客户端配置的localhost信息,JedisCluster客户端通过cluster nodes获取集群节点信息

127.0.0.1:6380> cluster nodes
2ed694f1727c992e82e83d81ab9c20771d5a4bd0 192.168.0.11:6381 master - 0 1534163329853 2 connected 6001-12000
45ee887bee3e9ef256a05cbc8e4c69ca84d5837a 192.168.0.15:6385 slave,fail 4eff07974aae139af1432d33a23c25b598334cbe 1534162704450 1534162704450 5 connected
3e8c33f7e3c46bc56cdd8342589fa1e55668be14 192.168.0.14:6384 slave,fail 2ed694f1727c992e82e83d81ab9c20771d5a4bd0 1534162704449 1534162704449 4 connected
66c1333eaec58a43e17702970906c3c2d94ca91a 192.168.0.13:6383 slave,fail 2527f88935b78ae2d26a7187bc35473db876a241 1534162704449 1534162704449 1 connected
2527f88935b78ae2d26a7187bc35473db876a241 192.168.0.10:6380 myself,master - 0 0 1 connected 0-6000
4eff07974aae139af1432d33a23c25b598334cbe 192.168.0.12:6382 master - 0 1534163329338 3 connected 12001-16383

解析节点信息后将节点存入map,也就是最初配置的set被替换了(具体代码看源码):

public static final int SLOT_INFORMATIONS_START_INDEX = 8;
  public static final int HOST_AND_PORT_INDEX = 1;

  public ClusterNodeInformation parse(String nodeInfo, HostAndPort current) {
    String[] nodeInfoPartArray = nodeInfo.split(" ");

    HostAndPort node = getHostAndPortFromNodeLine(nodeInfoPartArray, current);
    ClusterNodeInformation info = new ClusterNodeInformation(node);

    if (nodeInfoPartArray.length >= SLOT_INFORMATIONS_START_INDEX) {
      String[] slotInfoPartArray = extractSlotParts(nodeInfoPartArray);
      fillSlotInformation(slotInfoPartArray, info);
    }

    return info;
  }

关键信息:String[] slotInfoPartArray = extractSlotParts(nodeInfoPartArray); 
获取slot槽分配的区间值,比如0-5460。
parse函数中另一个关键信息:fillSlotInformation(slotInfoPartArray, info); 

fillSlotInformation函数调用了fillSlotInformationFromSlotRange函数,fillSlotInformationFromSlotRange函数作用是把所有的slot槽的index值存放到addAvailableSlot集合中。
初始化核心工作:把当前节点存放入nodes集合中,key为节点host:port,value为JedisPool实例;把slot槽index索引值与当前节点的JedisPool进行映射,存入Map
关键信息:slots.put(slot, targetPool);实现slot槽index索引值与当前节点的JedisPool进行映射

 

解决思路:网上有pipework的解决方案是最符合预期的,由于脚本针对mac系统需要做较大的调整,等有精力再研究了。先留作备忘,待解决。

如果只是测试,有一个思路(尚未验证,理论上应该可行)主从节点都在一个容器内配置,这样cluster nodes返回的ip都是127.0.0.1。这样即使返回客户端的ip为127.0.0.1再次连接时也不会连不上了。

2ed694f1727c992e82e83d81ab9c20771d5a4bd0 127.0.0.1:6381 master - 0 1530144760135 2 connected 6001-12000
2527f88935b78ae2d26a7187bc35473db876a241 127.0.0.1:6380 master - 0 1530144760014 1 connected 0-6000
4eff07974aae139af1432d33a23c25b598334cbe 127.0.0.1:6382 master - 0 1530144760135 3 connected 12001-16383
45ee887bee3e9ef256a05cbc8e4c69ca84d5837a 127.0.0.1:6385 myself,slave 4eff07974aae139af1432d33a23c25b598334cbe 0 0 5 connected
3e8c33f7e3c46bc56cdd8342589fa1e55668be14 127.0.0.1:6384 slave 2ed694f1727c992e82e83d81ab9c20771d5a4bd0 0 1530144760135 4 connected
66c1333eaec58a43e17702970906c3c2d94ca91a 127.0.0.1:6383 slave 2527f88935b78ae2d26a7187bc35473db876a241 0 1530144760136 1 connected

PS:上述测试思路已经验证可行。

先自定义entrypoint脚本,如下:保存为cluster_in_one.sh。

#!/bin/sh
#注意配置文件daemonized要设为true。
redis-server /data/conf/redis6380.conf && redis-server /data/conf/redis6381.conf && redis-server /data/conf/redis6382.conf  && redis-server /data/conf/redis6383.conf && redis-server /data/conf/redis6384.conf  && redis-server /data/conf/redis6385.conf 

将上述脚本映射为docker-entrypoint.sh

docker run -d --name rediscls --hostname rediscls --expose 6380-6385 -p 6380-6385:6380-6385 -v /Users/kumas/Applications/Docker/etc/localtime:/etc/localtime:ro  -v /Users/kumas/Applications/Docker/redis/cluster_in_one:/data -v /Users/kumas/Applications/Docker/redis/cluster_in_one/cluster_in_one.sh:/usr/local/bin/docker-entrypoint.sh redis:3.2-alpine

 

望遇到此问题的同志们能给出更好的解决方案。

------------PS:20180819------------------

借鉴kafkaclient访问docker中kafka集群的经验,redis的内网网使用hostname方式分别配置不同的ip而且不要使用回路ip(即127.0.0.1)比如:

内网:

192.168.0.10 redis01

192.168.0.11 redis02

192.168.0.12 redis03

外网宿主机:

10.10.10.10 redis01

10.10.10.10 redis02

10.10.10.10 redis03

注:10.10.10.10为宿主机真实网卡配的ip。

只是一个思路,未经验证。有时间再去验证。

 

 

 

 

### 在两台宿主机上使用 Docker 部署 Redis 集群 要在两台宿主机上使用 Docker 部署 Redis 集群,可以按照以下方法实现完整的分布式架构。以下是详细的说明: #### 1. 准备工作 确保每台宿主机都已安装并运行 DockerDocker Compose。此外,在两台宿主机之间建立网络连通性是非常重要的。 - 使用 `ping` 测试两台宿主机之间的通信能力[^1]。 - 确保防火墙允许 Redis 默认端口(默认为 6379 或自定义的其他端口)以及集群间用于节点发现的高范围端口(通常为指定端口号加 10,000 的偏移量)[^2]。 #### 2. 创建 Docker 网络 为了使不同宿主机上的容器能够相互通信,建议创建一个覆盖型 Docker 网络 (overlay network),这可以通过 Docker Swarm 实现。 ```bash docker swarm init docker network create --driver overlay redis-cluster-net ``` 此命令将在整个 Swarm 中创建名为 `redis-cluster-net` 的覆盖网络,以便跨多个宿主机共享同一网络环境[^3]。 #### 3. 构建 Redis 节点镜像 基于官方 Redis 镜像构建适合集群模式的定制化版本。编写一份简单的 `Dockerfile` 文件如下所示: ```Dockerfile FROM redis:6.0.8 COPY redis.conf /usr/local/etc/redis/redis.conf CMD ["redis-server", "/usr/local/etc/redis/redis.conf"] ``` 其中 `redis.conf` 是经过调整后的配置文件,启用集群支持功能,并设置持久化选项等参数[^2]。 #### 4. 启动 Redis 容器实例 在每一台宿主机上启动若干个 Redis 容器作为独立节点加入到即将形成的集群当中去。这里假设我们希望最终形成六个节点组成的三主三从结构,则可以在第一台机器上执行下面这些指令来初始化前三个节点;而在第二台服务器重复类似操作以完成剩余部分。 对于第一个宿主机: ```bash for i in {1..3}; do \ docker run -d --net redis-cluster-net \ --name redis-node$i \ -e REDIS_PORT=$((6379+i)) \ -p $((6379+i)):$(($REDIS_PORT)) \ -v $(pwd)/node-$i/data:/data \ custom_redis_image; done; ``` 第二个宿主机同样适用以上脚本逻辑只是改变起始编号即可。 #### 5. 组建实际的 Redis Cluster 当所有的单体服务都已经正常上线之后就可以着手把它们组合成真正的分布式的键值存储系统了——即所谓的“Redis Cluster”。 利用 `redis-cli --cluster` 工具来进行手动干预是最常见也是最可靠的方式之一。具体做法是从任意一台已经成功部署好的成员那里获取其内部地址列表信息,再据此调用相应的 API 接口发起请求从而正式宣告新组建成功的组员身份关系确立完毕。 例如如果知道所有参与者的 IP 地址及其监听的服务端口的话那么可以直接这样写入命令行界面之中尝试提交给程序处理: ```bash yes | redis-cli --cluster create \ <host1-ip>:<port1> <host1-ip>:<port2> ... <hostN-ip>:<portM> --cluster-replicas 1 ``` 这条语句里的 `<hostX-ip>` 应替换成为真实的物理机或者虚拟机公网可达之处的实际数值表示形式而 `<portY>` 则对应于各自所绑定使用的 TCP 连接通道号码[^1]。 --- ### 注意事项 - **数据一致性**:由于存在多副本机制因此需要特别关注同步策略的选择问题以免造成不必要的麻烦甚至灾难性的后果发生。 - **性能优化**:针对生产环境中可能遇到的各种瓶颈现象提前做好预案措施比如合理规划硬件资源配置比例等等都是很有必要的举措[^2]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值