Ioredis: Read from slaves with replication

Created on 25 Oct 2016  路  15Comments  路  Source: luin/ioredis

Hi,

I'm planning to use ioredis with redis-connect for a distributed express application with consistent sessions.

My doubt, after reading the docs, I've assumed the following:

  • Clustering is not needed for session storage, the data won't be enough big.
  • The majority of the operations will be reads in order to transform cookies into a req.session.

having the following nodes:

  • Node A master (with a known ip).
  • Node B slave (replica) of A (localhost).
  • Node C slave (replica) of A (other node, unknown ip).

I can not perform write operations to B, even if I set slave-read-only to no, the updates won't propagate, I need to write to A, so...

var Redis = require('ioredis');
var redis = new Redis('a-ip', port);

redis.set('foo', 'bar');
redis.get('foo', function (err, result) {
  console.log(result);
});

The ideal behavior would be, I am node B, I open a session, so I go A and set it, then the client comes in again, and I have to identify the cookie, so I read from B (localhost). Is this possible?

wontfix

Most helpful comment

@toredash It depends on what you think is read-write splitting. The discussions above consider "read-write splitting" as an automatic way to send different commands to different nodes via ONE Redis instance. Your example works, while developers have to do the splitting themselves.

All 15 comments

What you want is read-write splitting, which is already supported by Redis Cluster (new Redis.Cluster()). However, given your setup, I think you even don't need it since the dataset is relatively small (that the whole dataset can be held by one node) and the performance of Redis is very good when all your commands are simply GET & SET.

which is already supported by Redis Cluster

Isn't a Redis cluster only for sharded data?

I too, have this use case of non-sharded data that's replicated where I want writes to the master and reads to the closest instance. I'm not quite sure how to do that (mongodb does this natively and that's what I'm looking into doing).

Read-write splitting is only implemented in Cluster mode currently. The support of it for standalone Redis or Sentinel is not here yet but pr is welcome.

It shouldn't be hard to do the same thing for Sentinel. You can refer to https://github.com/luin/ioredis/blob/master/lib/cluster/index.js#L427-L433 for how to detecting whether a command is readonly (that can be sent to slaves) or not. Then override Redis#sendCommand or just write a wrapper for it to send every command to different Redis instances.

There is no pipeline implemented in cluster setup in many redis clients. We decided to use sentinels and replications with sharding and scaling reads with this setup would be really awesome.

@luin I have a doubt regarding the override of Redis#sendCommand. Should it pick a random node? But how to know the available nodes? Wouldn't this have a performance impact.

@nodo Refresh available nodes periodically with INFO command and pick a slave randomly or via a config function.

Thanks @luin. Probably I am missing something, but with INFO I can get only private IP of the replicas which is not always useful. Also, INFO should be called periodically to keep the information up-to-date. What do you think?

@nodo The information about slave addresses from INFO is related with your setup, the IP will not be private if your bind the slaves to the current interface.

Yes, INFO may be called every second or so.

Thanks for your comment @luin.

I am not sure if this could be a general solution. For instance, when using Elasticache it is not possible to bind the slaves to the interface. I believe this is the case with docker as well.

Do you think this is a good enough solution anyway?

@luni,

Isn't read write splitting supported now ? If I'm reading the docs correct( link ), I can use two redis connection with sentinels and do r/w splitting.

var redis_ro = new Redis({
  sentinels: [{ host: '127.0.0.1', port: 26379 }, { host: '127.0.0.1', port: 26380 }],
  name: 'mymaster',
  role: 'slave'
});
var redis = new Redis({
  sentinels: [{ host: '127.0.0.1', port: 26379 }, { host: '127.0.0.1', port: 26380 }],
  name: 'mymaster'
});

Then I'm able to do different calls like this:

redis.set('foo', 'bar');
redis_ro.get('foo');

Or am I missing something?

@toredash It depends on what you think is read-write splitting. The discussions above consider "read-write splitting" as an automatic way to send different commands to different nodes via ONE Redis instance. Your example works, while developers have to do the splitting themselves.

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.

@luin is read-write splitting supported currently ?

@dev-drprasad That's supported in the cluster mode. Otherwise, you may refer to @toredash 's approach.

Any update for read-write splitting with sentinel?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

luckyscript picture luckyscript  路  5Comments

PhillipWinder picture PhillipWinder  路  3Comments

snig-b picture snig-b  路  5Comments

ORESoftware picture ORESoftware  路  5Comments

lakano picture lakano  路  3Comments