和处才是木前wwW3344ut.comhr的,相不到3344ut.comhrcOm珍的不管了

基于一致性hash算法的redis连接池_Java_ThinkSAAS
基于一致性hash算法的redis连接池
基于一致性hash算法的redis连接池
内容来源: 网络
超轻(简)量(陋)级分布式的java redis连接池,提供路由及failover功能。仅依赖jedis2.7.2。package me.stone.util.redis.ConsistentRedisP
import java.util.R
import redis.clients.jedis.J
public class Test {
public static String buildRandomStr(int length) {
char[] str = "!@#$%^&*()&:.,/-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i & i++) {
sb.append(str[random.nextInt(str.length)]);
return sb.toString();
public static void testRedisPool() {
String ip1 = "192.168.1.100";
String ip2 = "192.168.1.101";
String ip3 = "192.168.1.102";
RedisPool pool = RedisPool.getInstance();
pool.addServer(ip1);
pool.addServer(ip2);
pool.addServer(ip3);
int keyNumber = 1000;
for (int i = 0; i & keyN i++) {
String str = "consistent:" + buildRandomStr(32);
Jedis jedis = pool.getJedis(str);
jedis.set(str, i + "");
pool.returnResource(jedis, str);
public static void main(String[] args) {
testRedisPool();
PHP开发框架
开发工具/编程工具
服务器环境
ThinkSAAS商业授权:
ThinkSAAS为用户提供有偿个性定制开发服务
ThinkSAAS将为商业授权用户提供二次开发指导和技术支持
让ThinkSAAS更好,把建议拿来。
开发客服微信26086人阅读
关键字:Redis的Java客户端Jedis的八种调用方式(事务、管道、分布式…)介绍&
Tags: redis, jedis, 事务, 管道, 分布式, 连接池&
redis是一个著名的key-value存储系统,而作为其官方推荐的java版客户端jedis也非常强大和稳定,支持事务、管道及有jedis自身实现的分布式。&
在这里对jedis关于事务、管道和分布式的调用方式做一个简单的介绍和对比:&
一、普通同步方式&
最简单和基础的调用方式,&
public void test1Normal() {&
&&& Jedis jedis = new Jedis(&localhost&);&
&&& long start = System.currentTimeMillis();&
&&& for (int i = 0; i & 100000; i++) {&
&&&&&&& String result = jedis.set(&n& + i, &n& + i);&
&&& long end = System.currentTimeMillis();&
&&& System.out.println(&Simple SET: & + ((end - start)/1000.0) + & seconds&);&
&&& jedis.disconnect();&
很简单吧,每次set之后都可以返回结果,标记是否成功。&
二、事务方式(Transactions)&
redis的事务很简单,他主要目的是保障,一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令。&
看下面例子:&
public void test2Trans() {&
&&& Jedis jedis = new Jedis(&localhost&);&
&&& long start = System.currentTimeMillis();&
&&& Transaction tx = jedis.multi();&
&&& for (int i = 0; i & 100000; i++) {&
&&&&&&& tx.set(&t& + i, &t& + i);&
&&& List&Object& results = tx.exec();&
&&& long end = System.currentTimeMillis();&
&&& System.out.println(&Transaction SET: & + ((end - start)/1000.0) + & seconds&);&
&&& jedis.disconnect();&
我们调用jedis.watch(…)方法来监控key,如果调用后key值发生变化,则整个事务会执行失败。另外,事务中某个操作失败,并不会回滚其他操作。这一点需要注意。还有,我们可以使用discard()方法来取消事务。&
三、管道(Pipelining)&
有时,我们需要采用异步方式,一次发送多个指令,不同步等待其返回结果。这样可以取得非常好的执行效率。这就是管道,调用方法如下:&
public void test3Pipelined() {&
&&& Jedis jedis = new Jedis(&localhost&);&
&&& Pipeline pipeline = jedis.pipelined();&
&&& long start = System.currentTimeMillis();&
&&& for (int i = 0; i & 100000; i++) {&
&&&&&&& pipeline.set(&p& + i, &p& + i);&
&&& List&Object& results = pipeline.syncAndReturnAll();&
&&& long end = System.currentTimeMillis();&
&&& System.out.println(&Pipelined SET: & + ((end - start)/1000.0) + & seconds&);&
&&& jedis.disconnect();&
四、管道中调用事务&
就Jedis提供的方法而言,是可以做到在管道中使用事务,其代码如下:&
public void test4combPipelineTrans() {&
&&& jedis = new Jedis(&localhost&);&
&&& long start = System.currentTimeMillis();&
&&& Pipeline pipeline = jedis.pipelined();&
&&& pipeline.multi();&
&&& for (int i = 0; i & 100000; i++) {&
&&&&&&& pipeline.set(&& + i, && + i);&
&&& pipeline.exec();&
&&& List&Object& results = pipeline.syncAndReturnAll();&
&&& long end = System.currentTimeMillis();&
&&& System.out.println(&Pipelined transaction: & + ((end - start)/1000.0) + & seconds&);&
&&& jedis.disconnect();&
但是经测试(见本文后续部分),发现其效率和单独使用事务差不多,甚至还略微差点。&
五、分布式直连同步调用&
public void test5shardNormal() {&
&&& List&JedisShardInfo& shards = Arrays.asList(&
&&&&&&&&&&& new JedisShardInfo(&localhost&,6379),&
&&&&&&&&&&& new JedisShardInfo(&localhost&,6380));&
&&& ShardedJedis sharding = new ShardedJedis(shards);&
&&& long start = System.currentTimeMillis();&
&&& for (int i = 0; i & 100000; i++) {&
&&&&&&& String result = sharding.set(&sn& + i, &n& + i);&
&&& long end = System.currentTimeMillis();&
&&& System.out.println(&Simple@Sharing SET: & + ((end - start)/1000.0) + & seconds&);&
&&& sharding.disconnect();&
这个是分布式直接连接,并且是同步调用,每步执行都返回执行结果。类似地,还有异步管道调用。&
六、分布式直连异步调用&
public void test6shardpipelined() {&
&&& List&JedisShardInfo& shards = Arrays.asList(&
&&&&&&&&&&& new JedisShardInfo(&localhost&,6379),&
&&&&&&&&&&& new JedisShardInfo(&localhost&,6380));&
&&& ShardedJedis sharding = new ShardedJedis(shards);&
&&& ShardedJedisPipeline pipeline = sharding.pipelined();&
&&& long start = System.currentTimeMillis();&
&&& for (int i = 0; i & 100000; i++) {&
&&&&&&& pipeline.set(&sp& + i, &p& + i);&
&&& List&Object& results = pipeline.syncAndReturnAll();&
&&& long end = System.currentTimeMillis();&
&&& System.out.println(&Pipelined@Sharing SET: & + ((end - start)/1000.0) + & seconds&);&
&&& sharding.disconnect();&
七、分布式连接池同步调用&(适用于2.2及以下版本)
如果,你的分布式调用代码是运行在线程中,那么上面两个直连调用方式就不合适了,因为直连方式是非线程安全的,这个时候,你就必须选择连接池调用。&
public void test7shardSimplePool() {&
&&& List&JedisShardInfo& shards = Arrays.asList(&
&&&&&&&&&&& new JedisShardInfo(&localhost&,6379),&
&&&&&&&&&&& new JedisShardInfo(&localhost&,6380));&
&&& ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);&
&&& ShardedJedis one = pool.getResource();&
&&& long start = System.currentTimeMillis();&
&&& for (int i = 0; i & 100000; i++) {&
&&&&&&& String result = one.set(&spn& + i, &n& + i);&
&&& long end = System.currentTimeMillis();&
&&& pool.returnResource(one);&
&&& System.out.println(&Simple@Pool SET: & + ((end - start)/1000.0) + & seconds&);&
&&& pool.destroy();&
上面是同步方式,当然还有异步方式。&
八、分布式连接池异步调用 (适用于2.2及以下版本)
public void test8shardPipelinedPool() {&
&&& List&JedisShardInfo& shards = Arrays.asList(&
&&&&&&&&&&& new JedisShardInfo(&localhost&,6379),&
&&&&&&&&&&& new JedisShardInfo(&localhost&,6380));&
&&& ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);&
&&& ShardedJedis one = pool.getResource();&
&&& ShardedJedisPipeline pipeline = one.pipelined();&
&&& long start = System.currentTimeMillis();&
&&& for (int i = 0; i & 100000; i++) {&
&&&&&&& pipeline.set(&sppn& + i, &n& + i);&
&&& List&Object& results = pipeline.syncAndReturnAll();&
&&& long end = System.currentTimeMillis();&
&&& pool.returnResource(one);&
&&& System.out.println(&Pipelined@Pool SET: & + ((end - start)/1000.0) + & seconds&);&
&&& pool.destroy();&
九、需要注意的地方&
&&& 事务和管道都是异步模式。在事务和管道中不能同步查询结果。比如下面两个调用,都是不允许的:&
&&&& Transaction tx = jedis.multi();&
&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&& tx.set(&t& + i, &t& + i);&
&&&& System.out.println(tx.get(&t1000&).get());& //不允许&
&&&& List&Object& results = tx.exec();&
&&&& Pipeline pipeline = jedis.pipelined();&
&&&& long start = System.currentTimeMillis();&
&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&& pipeline.set(&p& + i, &p& + i);&
&&&& System.out.println(pipeline.get(&p1000&).get()); //不允许&
&&&& List&Object& results = pipeline.syncAndReturnAll();&
&&& 事务和管道都是异步的,个人感觉,在管道中再进行事务调用,没有必要,不如直接进行事务模式。&
&&& 分布式中,连接池的性能比直连的性能略好(见后续测试部分)。&
&&& 分布式调用中不支持事务。&
&&& 因为事务是在服务器端实现,而在分布式中,每批次的调用对象都可能访问不同的机器,所以,没法进行事务。&
运行上面的代码,进行测试,其结果如下:&
Simple SET: 5.227 seconds&
Transaction SET: 0.5 seconds&
Pipelined SET: 0.353 seconds&
Pipelined transaction: 0.509 seconds&
Simple@Sharing SET: 5.289 seconds&
Pipelined@Sharing SET: 0.348 seconds&
Simple@Pool SET: 5.039 seconds&
Pipelined@Pool SET: 0.401 seconds&
另外,经测试分布式中用到的机器越多,调用会越慢。上面是2片,下面是5片:&
Simple@Sharing SET: 5.494 seconds&
Pipelined@Sharing SET: 0.51 seconds&
Simple@Pool SET: 5.223 seconds&
Pipelined@Pool SET: 0.518 seconds&
下面是10片:&
Simple@Sharing SET: 5.9 seconds&
Pipelined@Sharing SET: 0.794 seconds&
Simple@Pool SET: 5.624 seconds&
Pipelined@Pool SET: 0.762 seconds&
下面是100片:&
Simple@Sharing SET: 14.055 seconds&
Pipelined@Sharing SET: 8.185 seconds&
Simple@Pool SET: 13.29 seconds&
Pipelined@Pool SET: 7.767 seconds&
分布式中,连接池方式调用不但线程安全外,根据上面的测试数据,也可以看出连接池比直连的效率更好。&
十一、完整的测试代码&
package com.example.&
import java.util.A&
import java.util.L&
import org.junit.AfterC&
import org.junit.BeforeC&
import org.junit.T&
import redis.clients.jedis.J&
import redis.clients.jedis.JedisPoolC&
import redis.clients.jedis.JedisShardI&
import redis.clients.jedis.P&
import redis.clients.jedis.ShardedJ&
import redis.clients.jedis.ShardedJedisP&
import redis.clients.jedis.ShardedJedisP&
import redis.clients.jedis.T&
import org.junit.FixMethodO&
import org.junit.runners.MethodS&
@FixMethodOrder(MethodSorters.NAME_ASCENDING)&
public class TestJedis {&
&&& private static J&
&&& private static ShardedJ&
&&& private static ShardedJedisP&
&&& @BeforeClass&
&&& public static void setUpBeforeClass() throws Exception {&
&&&&&&& List&JedisShardInfo& shards = Arrays.asList(&
&&&&&&&&&&&&&&& new JedisShardInfo(&localhost&,6379),&
&&&&&&&&&&&&&&& new JedisShardInfo(&localhost&,6379)); //使用相同的ip:port,仅作测试&
&&&&&&& jedis = new Jedis(&localhost&);&
&&&&&&& sharding = new ShardedJedis(shards);&
&&&&&&& pool = new ShardedJedisPool(new JedisPoolConfig(), shards);&
&&& @AfterClass&
&&& public static void tearDownAfterClass() throws Exception {&
&&&&&&& jedis.disconnect();&
&&&&&&& sharding.disconnect();&
&&&&&&& pool.destroy();&
&&& @Test&
&&& public void test1Normal() {&
&&&&&&& long start = System.currentTimeMillis();&
&&&&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&&&&& String result = jedis.set(&n& + i, &n& + i);&
&&&&&&& }&
&&&&&&& long end = System.currentTimeMillis();&
&&&&&&& System.out.println(&Simple SET: & + ((end - start)/1000.0) + & seconds&);&
&&& @Test&
&&& public void test2Trans() {&
&&&&&&& long start = System.currentTimeMillis();&
&&&&&&& Transaction tx = jedis.multi();&
&&&&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&&&&& tx.set(&t& + i, &t& + i);&
&&&&&&& }&
&&&&&&& //System.out.println(tx.get(&t1000&).get());&
&&&&&&& List&Object& results = tx.exec();&
&&&&&&& long end = System.currentTimeMillis();&
&&&&&&& System.out.println(&Transaction SET: & + ((end - start)/1000.0) + & seconds&);&
&&& @Test&
&&& public void test3Pipelined() {&
&&&&&&& Pipeline pipeline = jedis.pipelined();&
&&&&&&& long start = System.currentTimeMillis();&
&&&&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&&&&& pipeline.set(&p& + i, &p& + i);&
&&&&&&& }&
&&&&&&& //System.out.println(pipeline.get(&p1000&).get());&
&&&&&&& List&Object& results = pipeline.syncAndReturnAll();&
&&&&&&& long end = System.currentTimeMillis();&
&&&&&&& System.out.println(&Pipelined SET: & + ((end - start)/1000.0) + & seconds&);&
&&& @Test&
&&& public void test4combPipelineTrans() {&
&&&&&&& long start = System.currentTimeMillis();&
&&&&&&& Pipeline pipeline = jedis.pipelined();&
&&&&&&& pipeline.multi();&
&&&&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&&&&& pipeline.set(&& + i, && + i);&
&&&&&&& }&
&&&&&&& pipeline.exec();&
&&&&&&& List&Object& results = pipeline.syncAndReturnAll();&
&&&&&&& long end = System.currentTimeMillis();&
&&&&&&& System.out.println(&Pipelined transaction: & + ((end - start)/1000.0) + & seconds&);&
&&& @Test&
&&& public void test5shardNormal() {&
&&&&&&& long start = System.currentTimeMillis();&
&&&&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&&&&& String result = sharding.set(&sn& + i, &n& + i);&
&&&&&&& }&
&&&&&&& long end = System.currentTimeMillis();&
&&&&&&& System.out.println(&Simple@Sharing SET: & + ((end - start)/1000.0) + & seconds&);&
&&& @Test&
&&& public void test6shardpipelined() {&
&&&&&&& ShardedJedisPipeline pipeline = sharding.pipelined();&
&&&&&&& long start = System.currentTimeMillis();&
&&&&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&&&&& pipeline.set(&sp& + i, &p& + i);&
&&&&&&& }&
&&&&&&& List&Object& results = pipeline.syncAndReturnAll();&
&&&&&&& long end = System.currentTimeMillis();&
&&&&&&& System.out.println(&Pipelined@Sharing SET: & + ((end - start)/1000.0) + & seconds&);&
&&& @Test&
&&& public void test7shardSimplePool() {&
&&&&&&& ShardedJedis one = pool.getResource();&
&&&&&&& long start = System.currentTimeMillis();&
&&&&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&&&&& String result = one.set(&spn& + i, &n& + i);&
&&&&&&& }&
&&&&&&& long end = System.currentTimeMillis();&
&&&&&&& pool.returnResource(one);&
&&&&&&& System.out.println(&Simple@Pool SET: & + ((end - start)/1000.0) + & seconds&);&
&&& @Test&
&&& public void test8shardPipelinedPool() {&
&&&&&&& ShardedJedis one = pool.getResource();&
&&&&&&& ShardedJedisPipeline pipeline = one.pipelined();&
&&&&&&& long start = System.currentTimeMillis();&
&&&&&&& for (int i = 0; i & 100000; i++) {&
&&&&&&&&&&& pipeline.set(&sppn& + i, &n& + i);&
&&&&&&& }&
&&&&&&& List&Object& results = pipeline.syncAndReturnAll();&
&&&&&&& long end = System.currentTimeMillis();&
&&&&&&& pool.returnResource(one);&
&&&&&&& System.out.println(&Pipelined@Pool SET: & + ((end - start)/1000.0) + & seconds&);&
欢迎访问我的技术群
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1707842次
积分:15003
积分:15003
排名:第689名
原创:175篇
转载:689篇
评论:134条
(98)(21)(30)(19)(1)(7)(71)(38)(24)(25)(19)(19)(11)(7)(1)(2)(10)(18)(21)(22)(80)(26)(28)(13)(16)(14)(42)(21)(7)(4)(18)(9)(12)(5)(12)(38)(4)(30)(28)redis java客户端jedis使用总结 - 为程序员服务
为程序员服务
redis java客户端jedis使用总结
jedis是redis官方推荐的java客户端,总结一下其大概知识点。,
redis最简单的使用:
Jedis jedis = new Jedis(&localhost&);//使用redis默认端口6379
jedis.set(&foo&, &bar&);
String value = jedis.get(&foo&);
但是jedis对象不是线程安全的,在多线程环境下会傻逼,所以官方提供了一个线程安全的连接池:
JedisPool pool = new JedisPool(new JedisPoolConfig(), &localhost&);
可以直接设置成静态的全局变量。
因为一直使用spring,配置一个:
&bean id=&jedisPoolConfig& class=&redis.clients.jedis.JedisPoolConfig&&
&property name=&maxTotal& value=&${redis.maxTotal}&/&
&property name=&maxIdle& value=&${redis.maxIdle}&/&
&property name=&maxWaitMillis& value=&${redis.maxWaitMillis}&/&
&property name=&testOnBorrow& value=&true&/&
&property name=&testOnReturn& value=&true&/&
&bean id=&jedisPool& class=&redis.clients.jedis.JedisPool&&
&constructor-arg index=&0& ref=&jedisPoolConfig&/&
&constructor-arg index=&1& value=&${redis.hostname}& /&
&constructor-arg index=&2& value=&${redis.port}& /&
ok,可以开始干活了:
Jedis jedis = jedisPool.getResource();
/// ... do stuff here ... for example
jedis.set(&foo&, &bar&);
String foobar = jedis.get(&foo&);
jedis.zadd(&sose&, 0, &car&); jedis.zadd(&sose&, 0, &bike&);
Set&String& sose = jedis.zrange(&sose&, 0, -1);
} catch (JedisConnectionException e) {
// returnBrokenResource when the state of the object is unrecoverable
if (null != jedis) {
pool.returnBrokenResource(jedis);
} finally {
/// ... it's important to return the Jedis instance to the pool once you've finished using it
if (null != jedis)
pool.returnResource(jedis);
/// ... when closing your application:
pool.destroy();//如果不destroy的话,连接池中的connection将会一直连着,直到超时为止,所以在spring容器写一个destroy方法还是有必要的
redis事务支持(transactions)。
说白了就是:我要同时干好几件事,期间不能干别的,我就把这几件事放同一个事物里。
Transaction t = jedis.multi();
t.set(&aaa&, &111&);
t.set(&bbb&, &222&);
再举个官方的例子:
Transaction t = jedis.multi();
t.set(&fool&, &bar&);
Response&String& result1 = t.get(&fool&);
t.zadd(&foo&, 1, &barowitch&); t.zadd(&foo&, 0, &barinsky&); t.zadd(&foo&, 0, &barikoviev&);
Response&Set&String&& sose = t.zrange(&foo&, 0, -1);
// get the entire sortedset
// dont forget it
String foolbar = result1.get();
// use Response.get() to retrieve things from a Response
int soseSize = sose.get().size();
// on sose.get() you can directly call Set methods!
// List&Object& allResults = t.exec();
// you could still get all results at once, as before,最后这个方法是以前版本用的,过时了,现在都用上面的方法
返回值有点类似于线程池的submit方法得到Future对象,这个是必须在exec()方法执行完了之后才能得到结果。所以不能在事物里使用方法的返回值。
redis 管道(Pipelining)
异步执行,一次发送多个指令,不同步等待其返回结果。可以在管道中加入事物。
Pipeline p = jedis.pipelined();
p.set(&fool&, &bar&);
p.zadd(&foo&, 1, &barowitch&);
p.zadd(&foo&, 0, &barinsky&); p.zadd(&foo&, 0, &barikoviev&);
Response&String& pipeString = p.get(&fool&);
Response&Set&String&& sose = p.zrange(&foo&, 0, -1);
int soseSize = sose.get().size();
Set&String& setBack = sose.get();
分布式客户端(ShardedJedis)
我个人理解这东西就是个负载均衡,利用xxx哈希算法,均匀的把key存到不同redis服务器上
jedisPoolConfig与上面的一样,第二个参数是redis服务器的列表
&bean id=&shardedJedisPool& class=&redis.clients.jedis.ShardedJedisPool&&
&constructor-arg index=&0& ref=&jedisPoolConfig&/&
&constructor-arg index=&1&&
&bean class=&redis.clients.jedis.JedisShardInfo&&
&constructor-arg index=&0& value=&${redis.hostname}&/&
&constructor-arg index=&1& value=&${redis.port}&/&
&/constructor-arg&
ShardedJedis jedis = pool.getResource();
jedis.set(&a&, &foo&);
.... // do your work here
pool.returnResource(jedis);
.... // a few moments later
ShardedJedis jedis2 = pool.getResource();
jedis.set(&z&, &bar&);
pool.returnResource(jedis);
pool.destroy();
因为事务是在服务器端实现,而在分布式中,每批次的调用对象都可能访问不同的机器,所以,没法进行事务。
您可能的代码
相关聚客文章
荣誉:2086
相关专栏文章

我要回帖

更多关于 www.3344ax.com 的文章

 

随机推荐