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 staticT 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; } publicT 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 ListjedisShardInfos; 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); } }