Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ioredis client should not attempt to connect to IP addresses from cluster configuration #365

Closed
bsnote opened this issue Sep 8, 2016 · 3 comments

Comments

@bsnote
Copy link

bsnote commented Sep 8, 2016

I configured Redis cluster consisting of 2 nodes running on the same machine:

redis.conf for 1st node:

bind 0.0.0.0
port 6379
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000

redis.conf for 2nd node:

bind 0.0.0.0
port 6380
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
redis-cli -p 6379 cluster addslots $(seq 0 8191)
redis-cli -p 6380 cluster addslots $(seq 8192 16383)
redis-cli -p 6380 cluster meet 127.0.0.1 6379

redis-cli -p 6379 cluster slots returns the following result:

1) 1) (integer) 8192
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 6380
      3) "c8e9a312411cefdd8ee4f74c923e5b7099db5edd"
2) 1) (integer) 0
   2) (integer) 8191
   3) 1) "127.0.0.1"
      2) (integer) 6379
      3) "e44691fe2b1adb2772fd5114d577dab105482f32"

Now running DEBUG=ioredis:* node 1 on a different machine where

// 1.js
var Redis = require('ioredis');

var cluster = new Redis.Cluster([{
  port: 6379,
  host: '10.2.19.39'
}]);

shows the following:

  ioredis:cluster status: [empty] -> connecting +0ms
  ioredis:redis status[10.2.19.39:6379]: [empty] -> wait +6ms
  ioredis:cluster getting slot cache from 10.2.19.39:6379 +3ms
  ioredis:redis status[10.2.19.39:6379]: wait -> connecting +3ms
  ioredis:redis queue command[0] -> cluster(slots) +1ms
  ioredis:redis status[10.2.19.39:6379]: connecting -> connect +7ms
  ioredis:redis write command[0] -> info() +1ms
  ioredis:redis status[10.2.19.39:6379]: connect -> ready +7ms
  ioredis:connection send 1 commands in offline queue +0ms
  ioredis:redis write command[0] -> cluster(slots) +1ms
  ioredis:redis status[127.0.0.1:6380]: [empty] -> wait +4ms
  ioredis:redis status[127.0.0.1:6379]: [empty] -> wait +0ms
  ioredis:cluster status: connecting -> connect +1ms
  ioredis:redis status[127.0.0.1:6380]: wait -> connecting +1ms
  ioredis:redis queue command[0] -> cluster(info) +0ms
  ioredis:connection error: Error: connect ECONNREFUSED 127.0.0.1:6380 +2ms
  ioredis:redis status[127.0.0.1:6380]: connecting -> close +1ms
  ioredis:connection skip reconnecting because `retryStrategy` is not a function +0ms
  ioredis:redis status[127.0.0.1:6380]: close -> end +0ms
  ioredis:redis status[10.2.19.39:6379]: ready -> close +6ms
  ioredis:connection skip reconnecting since the connection is manually closed. +0ms
  ioredis:redis status[10.2.19.39:6379]: close -> end +0ms
  ioredis:redis status[127.0.0.1:6379]: wait -> connecting +0ms
  ioredis:redis status[127.0.0.1:6379]: connecting -> connect +1ms
  ioredis:redis write command[0] -> info() +0ms
  ioredis:redis status[127.0.0.1:6379]: connect -> ready +1ms
  ioredis:cluster getting slot cache from 127.0.0.1:6379 +97ms
  ioredis:redis write command[0] -> cluster(slots) +0ms
  ioredis:delayqueue send 1 commands in failover queue +2ms
  ioredis:redis queue command[0] -> cluster(info) +1ms
  ioredis:redis status[127.0.0.1:6379]: ready -> close +0ms
  ioredis:connection skip reconnecting since the connection is manually closed. +0ms
  ioredis:redis status[127.0.0.1:6379]: close -> end +0ms
  ...

As it can be seen it's trying to connect to 127.0.0.1 which is wrong as this address is used for inter-node communication and is not necessarily the one that clients use. I can make it work by running this command:

redis-cli -p 6380 cluster meet 10.2.19.39 6379

After that redis-cli -p 6379 cluster slots returns the following result:

1) 1) (integer) 8192
   2) (integer) 16383
   3) 1) "10.2.19.39"
      2) (integer) 6380
      3) "c8e9a312411cefdd8ee4f74c923e5b7099db5edd"
2) 1) (integer) 0
   2) (integer) 8191
   3) 1) "10.2.19.39"
      2) (integer) 6379
      3) "e44691fe2b1adb2772fd5114d577dab105482f32"

and DEBUG=ioredis:* node 1 works properly:

  ioredis:cluster status: [empty] -> connecting +0ms
  ioredis:redis status[10.2.19.39:6379]: [empty] -> wait +5ms
  ioredis:cluster getting slot cache from 10.2.19.39:6379 +4ms
  ioredis:redis status[10.2.19.39:6379]: wait -> connecting +3ms
  ioredis:redis queue command[0] -> cluster(slots) +1ms
  ioredis:redis status[10.2.19.39:6379]: connecting -> connect +6ms
  ioredis:redis write command[0] -> info() +1ms
  ioredis:redis status[10.2.19.39:6379]: connect -> ready +7ms
  ioredis:connection send 1 commands in offline queue +0ms
  ioredis:redis write command[0] -> cluster(slots) +0ms
  ioredis:redis status[10.2.19.39:6380]: [empty] -> wait +4ms
  ioredis:cluster status: connecting -> connect +1ms
  ioredis:redis write command[0] -> cluster(info) +1ms
  ioredis:cluster status: connect -> ready +1ms

I've checked the code of ioredis and indeed, it's using cluster slots command to get IP address to connect to:

  redis.cluster('slots', utils.timeout(function (err, result) {
    if (err) {
      redis.disconnect();
      return callback(err);
    }
    var nodes = [];

    for (var i = 0; i < result.length; ++i) {
      var items = result[i];
      var slotRangeStart = items[0];
      var slotRangeEnd = items[1];

      var keys = [];
      for (var j = 2; j < items.length; j++) {
        items[j] = { host: items[j][0]/* || redis.options.host*/, port: items[j][1] };
        items[j].readOnly = j !== 2;
        nodes.push(items[j]);
        keys.push(items[j].host + ':' + items[j].port);
      }

      for (var slot = slotRangeStart; slot <= slotRangeEnd; slot++) {
        _this.slots[slot] = keys;
      }
    }

    _this.connectionPool.reset(nodes);
    callback();
  }, 1000));

I think this is inherently wrong as IP addresses used for inter-node communication do not necessarily coincide with IP addresses used by clients. For example if a client for whatever reason is forced to use public IP address then the only way to make it work is to specify public IP for inter-node communication:

redis-cli -p 6380 cluster meet 52.17.215.146 6379

@luin
Copy link
Collaborator

luin commented Sep 8, 2016

You should bind the redis to the correct interface instead of 0.0.0.0. 10.2.1.1 for example.

@bsnote
Copy link
Author

bsnote commented Sep 9, 2016

This just forces to use internal IP and doesn't allow to connect to Redis using localhost or public IP address. I think it's better to still bind to 0.0.0.0 but use cluster meet 10.2.x.x 6379 command, which makes Redis save 10.2.x.x in nodes.conf. BTW in order to use single-node cluster, the node should cluster meet itself using internal IP address. For example redis-cli -p 6379 cluster meet 10.2.19.39 6379

In both cases it's not possible to connect to Redis using public IP address or use localhost address for inter-node communication. It's not a big deal as it's probably not a good idea to expose Redis to outside world anyway. It's just that the overall concept of using the same IP address for inter-node communication and user client communication looks not perfect. Perhaps it's more of a general problem in Redis.

@stale
Copy link

stale bot commented Oct 23, 2017

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 7 days if no further activity occurs, but feel free to re-open a closed issue if needed.

@stale stale bot added the wontfix label Oct 23, 2017
@stale stale bot closed this as completed Oct 30, 2017
luin added a commit that referenced this issue Dec 9, 2018
ioredis-robot pushed a commit that referenced this issue Dec 9, 2018
# [4.3.0](v4.2.3...v4.3.0) (2018-12-09)

### Features

* **cluster:** add NAT support ([#758](#758)) ([3702d67](3702d67)), closes [#693](#693) [#365](#365)
janus-dev87 added a commit to janus-dev87/ioredis-work that referenced this issue Mar 1, 2024
# [4.3.0](redis/ioredis@v4.2.3...v4.3.0) (2018-12-09)

### Features

* **cluster:** add NAT support ([#758](redis/ioredis#758)) ([3702d67](redis/ioredis@3702d67)), closes [#693](redis/ioredis#693) [#365](redis/ioredis#365)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants