How to create Pipeline in RedisCluster

Today I am going to share my experience with Spring-data-redis + Redis 3.2 with cluster. In one of the project we are using spring-data-redis with Redis 3.2 cluster and facing slow performance issue on production after deployment of our changes.

After Analysis, I have find out that in one of the functionality we are sending HMGET redis command for multiple keys at a time and also found that Jedis library does not supports the pipeline for Redis 3.2 cluster. So we analyzed lots of things, like implement pipeline by our self or use Multi Threading or use Async IO Redis Clinet e.g. Redisson.

I am going to explain implementation of pipeline for Redis 3.2 using Jedis library.

Following example is just assumption for Redis Cluster with Slots and Keys associated with slots.

In the above example, I have redis cluster with three Nodes like Node 1, Node 2 and Node 3

Each Node having following Slot range
Node 1: 0-115
Node 2: 116-315
Node 3: 316-415

Now You can also see Keys stored in each Node respective to slot like
Slot No.     à   Keys
111            à K1, K2, K5
215            à K6, K8, K10
333            à K11, K7, K9

Now we require to call Redis Command HMGET operation with all keys to get fields value in single request. If we use spring-data-redis + Jedis then we can not able to call pipeline to get better performance. So for that we tried to implement pipeline by our way. But for that we require Jedis Native connection from Jedis pool, because JedisClusterConnection doesn’t provides the pipeline. So we planned by following way.

1.     First, we grouped each slots respective to Keys by following code.
Map<Integer, String> slotKeysMap = new HashMap<>();
for (String key : keys) {
   String hKey = RedisCollections.generateKey(locale, collectionName, key);
   int slot = JedisClusterCRC16.getSlot(hKey);
   if (!slotKeysMap.containsKey(slot)) {
      slotKeysMap.put(slot, key);
   } else {
      key = slotKeysMap.get(slot).concat("|").concat(key);
      slotKeysMap.put(slot, key);
   }
}

2.     Second, we took the JedisClusterConnection object reference.
3.     Third, if we want to call pipeline on JedisCluster then it is not Possible. So what we did we tried to take Jedis Native Connection from JedisPool. But JedisCluster also not providing feature to get Jedis connection from JedisPool for each slot. So to get JedisSlotConnectionHandler/ JedisConnectionHandler we have copied BinaryJedisCluster class with same package name in our application and this class is part of Jedis library with pakage name redis.clients.jedis .

// Please find following code which is implemented by me:
JedisClusterConnection jedisClusterConnection = (JedisClusterConnection) stringRedisTemplate.getConnectionFactory().getClusterConnection();
JedisCluster jedisCluster = jedisClusterConnection.getNativeConnection();
JedisSlotBasedConnectionHandler jedisClusterConnectionHandler =  jedisCluster.getConnectionHandler(); // This method is not part of actual Jedis library but it is part of copied BinaryJedisCluste.java class in our project

  
 // Method we have included into copied class is:
public JedisSlotBasedConnectionHandler getConnectionHandler() {
   return (JedisSlotBasedConnectionHandler) this.connectionHandler;
}

Now we can able to get connectionHandler to get the Jedis Native Connection from JedisPool.

You may face Issue at runtime:
By this way we can implement pipeline but the actual problem is this solution is not generic, in future if jedis library changed then again we have to copy that class changes into our project and we have to repackage and deploy our application. 

Another problem is sometime application server class loader loads the Jedis Library class so we will get the Runtime exception of NoSuchMethodError.

à So what I did, I copied source code into our local environment and added the method to get connection handler and tested library in our local environment. It is working fine.

I also raised the PR to include this method in Jedis Library. So every one can use Pipeline by getting Jedis connection from Jedis Pool. Please check from following URL: https://github.com/xetorthio/jedis/pull/1532




Comments