DB/Redis

[Redis] 샤드를 지원하는 SharedJedisTemplate 만들기

louis.dev 2013. 12. 9. 18:38

spring-data-redis에서 제공해주는 RedisTemplate을 사용하면 @Cacheable 어노테이션을 사용할 수도 있고, Jedis를 이용한 Redis 사용을 쉽게 개발할수 있는 장점이 있습니다.


하지만 현재 spring-data-redis 1.1.0 버전에서 제공해 주는 RedisTemplate은 샤드를 지원해 주지 않고 있기 때문에 시스템 구성이 샤드로 되어 있는 경우 spring-data-redis의 RedisTemplate을 사용할 수가 없습니다.


그래서 샤드를 지원하는 레디스 템플릿을 만들어 보기 위해 구글링을 하던 중 중국 개발자가 만들어 놓은 ShardedJedisTemplate를 찾을수 있었고, 약간의 수정을 하여 Template 클래스를 만들었습니다.



1. RedisException

package net.krespo.redis.exception;

public class RedisException extends RuntimeException{
	private static final long serialVersionUID = 9150947297211556907L;

	public RedisException() {
		super();
	}

	public RedisException(String message, Throwable cause) {
		super(message, cause);
	}

	public RedisException(String message) {
		super(message);
	}

	public RedisException(Throwable cause) {
		super(cause);
	}

}

2. ShardedJedisPoolUtils

package net.krespo.redis.jedis.util;


import net.krespo.redis.jedis.ShardedJedisCallback;
import net.krespo.redis.jedis.ShardedJedisReturnedCallback;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;

/**
 * 레디스의 실행 및 실행결과를 리턴해주는 유틸
 * **/
public class ShardedJedisPoolUtils {
	
	/**
	 * 리턴값이 필요한 Command 실행
	 * */
	public static  T execute(ShardedJedisPool jedisPool, ShardedJedisReturnedCallback shardedJedisReturnedCallback) {
		ShardedJedis shardedJedis = null;
	    try {   
	    	shardedJedis = jedisPool.getResource();
	        T returnValue = shardedJedisReturnedCallback.doInShardedJedis(shardedJedis);
	    	return returnValue;
	    } 
	    //장애로 인해 레디스 커넥션이 맺어지지 않으면 커넥션풀에서 해당 커넥션을 제거한다.
	    catch (JedisConnectionException e) {
	    	if(shardedJedis != null) jedisPool.returnBrokenResource(shardedJedis);
	    	return null;
	    }
	    finally{
	    	if (shardedJedis != null) {
	    		jedisPool.returnResource(shardedJedis);
	    	}
	    }
	}
	
	/**
	 * 리턴값이 필요 없는 Command 실행
	 * */
	public static void execute(ShardedJedisPool jedisPool, ShardedJedisCallback shardedJedisCallback) {
		ShardedJedis shardedJedis = null;
	    try {   
	    	shardedJedis = jedisPool.getResource();
	        shardedJedisCallback.doInShardedJedis(shardedJedis);
	    } 
	    //장애로 인해 레디스 커넥션이 맺어지지 않으면 커넥션풀에서 해당 커넥션을 제거한다.
	    catch (JedisConnectionException e) {
	    	if(shardedJedis != null) jedisPool.returnBrokenResource(shardedJedis);
	    }
	    finally{
	    	if (shardedJedis != null) {
	    		jedisPool.returnResource(shardedJedis);
	    	}
	    }
	}
}

3. ShardedJedisCallback

package net.krespo.redis.jedis;

import redis.clients.jedis.ShardedJedis;
public interface ShardedJedisCallback {
	void doInShardedJedis(ShardedJedis shardedJedis);
}

4. ShardedJedisReturnedCallback

package net.krespo.redis.jedis;

import redis.clients.jedis.ShardedJedis;

public interface ShardedJedisReturnedCallback {
	T doInShardedJedis(ShardedJedis shardedJedis);
}

5. AbstractRedisTemplate

package net.krespo.redis.template;

import net.krespo.redis.exception.RedisException;

public abstract class AbstractRedisTemplate {
	protected void handleException(RedisException e) throws RedisException {
		throw e;
	}
	
	protected RedisException wrapperException(Exception e) {
		return new RedisException(e.getMessage(), e);
	}
}

6. ShardedJedisTemplate

package net.krespo.redis.jedis;

import net.krespo.redis.exception.RedisException;
import net.krespo.redis.jedis.util.ShardedJedisPoolUtils;
import net.krespo.redis.template.AbstractRedisTemplate;
import redis.clients.jedis.ShardedJedisPool;

public class ShardedJedisTemplate extends AbstractRedisTemplate{
	protected ShardedJedisPool shardedJedisPool;
	
	public void setShardedJedisPool(ShardedJedisPool shardedJedisPool) {
		this.shardedJedisPool = shardedJedisPool;
	}
	
	
	public  T execute(ShardedJedisReturnedCallback shardedJedisReturnedCallback) throws RedisException {
		try {
			return ShardedJedisPoolUtils.execute(shardedJedisPool, shardedJedisReturnedCallback);
		} catch (Exception e) {
			handleException(wrapperException(e));
			return null;		
		}
	}
	
	
	public void execute(ShardedJedisCallback shardedJedisCallback) throws RedisException {
		try {
			ShardedJedisPoolUtils.execute(shardedJedisPool, shardedJedisCallback);
		} catch (Exception e) {
			handleException(wrapperException(e));
		}
	}
}

사용법은 아래와 같이 사용하면 됩니다.

package net.krespo.redis.template.jedis;

import java.util.ArrayList;
import java.util.List;

import net.krespo.redis.jedis.ShardedJedisCallback;
import net.krespo.redis.jedis.ShardedJedisReturnedCallback;
import net.krespo.redis.jedis.ShardedJedisTemplate;

import org.junit.Assert;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

public class ShardedJedisTemplateTests {
	private JedisPoolConfig config;
	private List jedisShardInfos;
	private ShardedJedisPool pool;
	private ShardedJedisTemplate template;
	@Before
	public void init() {
		config = new JedisPoolConfig();
		jedisShardInfos = new ArrayList();
		
		JedisShardInfo shard1 = new JedisShardInfo("호스트1", 포트);
		JedisShardInfo shard2 = new JedisShardInfo("호스트2", 포트);
		shard1.setPassword("비밀번호");
		shard2.setPassword("비밀번호");
		
		jedisShardInfos.add(shard1);
		jedisShardInfos.add(shard2);
		
		pool = new ShardedJedisPool(config, jedisShardInfos);
		
		template = new ShardedJedisTemplate();
		template.setShardedJedisPool(pool);
	}
	
	@Test
	public void shardedJedisTemplateCallbackTest() {
		template.execute(new ShardedJedisCallback() {
			public void doInShardedJedis(ShardedJedis shardedJedis) {
				String status = shardedJedis.set("test:key", "testvalue");
				Assert.assertEquals("OK", status);
			}
		});
	}
	@Test
	public void shardedJedisTemplateReturnedCallbackTest() {
		String value = template.execute(new ShardedJedisReturnedCallback() {
					   		public String doInShardedJedis(ShardedJedis shardedJedis) {
								return shardedJedis.get("test:key");
							}
							
						});
		Assert.assertNotNull(value);
		Assert.assertEquals("testvalue", value);
		
	
	}
    
}