原来项目中有用到Redis用做缓存服务,刚开始时只用一台Redis就可以知足服务,随着项目的慢慢进行,发现一台知足不了现有的项目需求,由于Redis操做都是原子性这样的特性,形成有时同时读写缓存形成查询效率的降低。可是因为咱们如今用的仍是2.X版本,仍是没有集群功能的(Redis做者在3.0版本中已经加入了集群功能), 所以只能使用2.x版本中自带的一个叫作ShardedJedis的来实现分布式缓存。redis
ShardedJedis是经过一致性哈希来实现分布式缓存的,经过必定的策略把不一样的key分配到不一样的redis server上,达到横向扩展的目的。那么ShardedJedis内部是怎么实现的呢,文章会慢慢讲解。算法
1.ShardedJedis使用方法
ShardedJedis的使用方法除了配置时有点区别,其余和Jedis基本相似,有一点要注意的是 ShardedJedis不支持多命令操做,像mget、mset、brpop等能够在redis命令后一次性操做多个key的命令,具体包括哪些,你们能够看Jedis下的 MultiKeyCommands 这个类,这里面就包含了全部的多命令操做。很贴心的是,Redis做者已经把这些命令从ShardedJedis过滤掉了,使用时也调用不了这些方法,你们知道下就好了。数据库
好了,如今来看基本的使用缓存
//设置链接池的相关配置 JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(2); poolConfig.setMaxIdle(1); poolConfig.setMaxWaitMillis(2000); poolConfig.setTestOnBorrow(false); poolConfig.setTestOnReturn(false); //设置Redis信息 String host = "127.0.0.1"; JedisShardInfo shardInfo1 = new JedisShardInfo(host, 6379, 500); shardInfo1.setPassword("test123"); JedisShardInfo shardInfo2 = new JedisShardInfo(host, 6380, 500); shardInfo2.setPassword("test123"); JedisShardInfo shardInfo3 = new JedisShardInfo(host, 6381, 500); shardInfo3.setPassword("test123"); //初始化ShardedJedisPool List<JedisShardInfo> infoList = Arrays.asList(shardInfo1, shardInfo2, shardInfo3); ShardedJedisPool jedisPool = new ShardedJedisPool(poolConfig, infoList); //进行查询等其余操做 ShardedJedis jedis = null; try { jedis = jedisPool.getResource(); jedis.set("test", "test"); jedis.set("test1", "test1"); String test = jedis.get("test"); System.out.println(test); ...... } finally { //使用后必定关闭,还给链接池
if(jedis!=null) {
jedis.close();
} }
jedis获取后必定要关闭,这和咱们使用数据库链接池是同样的,放在finally块中保证jedis的关闭.服务器
ps:若是你们使用的jdk是1.7版本或者以上的话,可使用1.7加入的try-with-resources语句 分布式
try(ShardedJedis jedis = jedisPool.getResource()) { jedis.set("test", "test"); jedis.set("test1", "test1"); String test = jedis.get("test"); System.out.println(test); }
try-with-resources的效果和咱们上面写法是同样的,只是jedis.close()语法它会帮咱们调用,它会默认调用咱们在try-with-resources语句中声明的,实现了Closeable 接口的对象的close方法(像上面的ShardedJedis),咱们常常用到的数据库链接Connection和一些输入输出流均可以使用这种方法。测试
从代码上看,除了初始化ShardedJedisPool时须要加入多个Redis服务器信息,其余的和Jedis使用差很少。spa
在初始化ShardedJedisPool 时,咱们还能够传入ShardedJedis采用的hash算法,支持MURMUR_HASH 和MD5两种算法,默认是使用MURMUR_HASH(能够查看redis.clients.util.Hashing 类查看相关的信息)code
另外还能够传入keyTagPattern来指定咱们key的分布策略,全部可以匹配keyTagPattern的key(经过正则匹配)将放在同一个redis里,默认的是直接使用key来进行断定。Redis自带了一个Sharded.keyTagPattern,以下 server
Pattern DEFAULT_KEY_TAG_PATTERN = Pattern.compile("\\{(.+?)\\}");
咱们能够用下面的代码来实际测试下
ShardedJedis jedis = jedisPool.getResource();
jedis.set("cnblog", "cnblog"); jedis.set("redis", "redis"); jedis.set("test", "test"); jedis.set("123456", "1234567"); Client client1 = jedis.getShard("cnblog").getClient(); Client client2 = jedis.getShard("redis").getClient(); Client client3 = jedis.getShard("test").getClient(); Client client4 = jedis.getShard("123456").getClient(); ////打印key在哪一个server中 System.out.println("cnblog in server:" + client1.getHost() + " and port is:" + client1.getPort()); System.out.println("redis in server:" + client2.getHost() + " and port is:" + client2.getPort()); System.out.println("test in server:" + client3.getHost() + " and port is:" + client3.getPort()); System.out.println("123456 in server:" + client4.getHost() + " and port is:" + client4.getPort());
看输出内容: