redis原生应用

redis原生应用


一、普通同步方式
public void test1Normal() {
    Jedis jedis = new Jedis("localhost");	//生成Jedis,连接到redis服务器
    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(); //断开连接
}



二、事务方式(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();
}


1.WATCH命令可以监控一个或多个键,一旦其中有一个键里的值被修改(或删除),之后的事务就不会执行。监控一直持续到EXEC命令
(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值)
2.我们调用jedis.watch(…)方法来监控key,如果调用后key里的值发生变化,则整个事务会执行失败(被放弃),EXEC将放弃当前事务中
的所有命令(返回NULL-multi-bulk回复)。
3.因为redis的命令是一条条执行的(单进程模式),所以用WATCH命令是可以做到数据并发处理的,不存在回滚,因为还没有执行的机
会就被放弃掉了。
4.事务中某个操作失败,并不会回滚其他操作。这一点需要注意。
5.我们可以使用discard()方法来取消事务。就是取消事务队列中的所有指令。

命令说明
1.MULTI
用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行EXEC时,这些命令才会被原子的执行。

2.EXEC
执行在一个事务内命令队列中的所有命令,同时将当前连接的状态恢复为正常状态,即非事务状态。如果在事务中执行了WATCH命令,
那么只有当WATCH所监控的Keys没有被修改的前提下,EXEC命令才能执行事务队列中的所有命令,否则EXEC将放弃当前事务中的所有命令。
原子性的返回事务中各条命令的返回结果。如果在事务中使用了WATCH,一旦事务被放弃,EXEC将返回NULL-multi-bulk回复。

3.DISCARD
回滚事务队列中的所有命令,同时再将当前连接的状态恢复为正常状态,即非事务状态。如果WATCH命令被使用,该命令将
UNWATCH所有的Keys。

4.WATCH key [key ...]
在MULTI命令执行之前,可以指定待监控的Keys,然而在执行EXEC之前,如果被监控的Keys发生修改,EXEC将放弃执
行该事务队列中的所有命令。

5.UNWATCH
取消当前事务中指定监控的Keys,如果执行了EXEC或DISCARD命令,则无需再手工执行该命令了,因为在此之后,事务中所有被监
控的Keys都将自动取消。


三、管道(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();
}



七、分布式连接池同步调用
如果,你的分布式调用代码是运行在线程中,那么上面两个直连调用方式就不合适了,因为直连方式是非线程安全的,
这个时候,你就必须选择连接池调用。
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();
}



八、分布式连接池异步调用
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();
}




JedisPool应用
1.Jedis使用commons-pool完成池化实现。

先做个配置文件(properties文件):
#最大分配的对象数
redis.pool.maxActive=1024
#最大能够保持idel状态的对象数
redis.pool.maxIdle=200
#当池内没有返回对象时,最大等待时间
redis.pool.maxWait=1000
#当调用borrow Object方法时,是否进行有效性检查
redis.pool.testOnBorrow=true
#当调用return Object方法时,是否进行有效性检查
redis.pool.testOnReturn=true
#IP
redis.ip=172.0.0.1
#Port
redis.port=6379


jedisPool的相关详细配置可参考: http://www.2cto.com/database/201311/254449.html

在静态代码段中完成初始化:
private static JedisPool pool;
static {
	ResourceBundle bundle = ResourceBundle.getBundle("redis");
	if (bundle == null) {
		throw new IllegalArgumentException("[redis.properties] is not found!");
	}
	JedisPoolConfig config = new JedisPoolConfig();
	config.setMaxActive(Integer.valueOf(bundle.getString("redis.pool.maxActive")));
	config.setMaxIdle(Integer.valueOf(bundle.getString("redis.pool.maxIdle")));
	config.setMaxWait(Long.valueOf(bundle.getString("redis.pool.maxWait")));
	config.setTestOnBorrow(Boolean.valueOf(bundle.getString("redis.pool.testOnBorrow")));
	config.setTestOnReturn(Boolean.valueOf(bundle.getString("redis.pool.testOnReturn")));
	pool = new JedisPool(config, bundle.getString("redis.ip"), Integer.valueOf(bundle.getString("redis.port")));
}


修改为Jedis从pool中获得:
// 从池中获取一个Jedis对象
Jedis jedis = pool.getResource();
String keys = "name";
// 删数据
jedis.del(keys);
// 存数据
jedis.set(keys, "snowolf");
// 取数据
String value = jedis.get(keys);
System.out.println(value);
// 释放对象池
pool.returnResource(jedis);



Jedis分布式
Jedis分布式(就是数据按key算出hash后按hash分片方式(就是对数据进行分类,方便后面查找)存到不同的redis服务器)

保留前面的 JedisPoolConfig ,新增两个Redis的IP(redis1.ip,redis2.ip),完成两个
JedisShardInfo 实例 ,并将其丢进List中:
JedisShardInfo jedisShardInfo1 = new JedisShardInfo(
            bundle.getString("redis1.ip"), Integer.valueOf(bundle.getString("redis.port")));
JedisShardInfo jedisShardInfo2 = new JedisShardInfo(
            bundle.getString("redis2.ip"), Integer.valueOf(bundle.getString("redis.port")));
List<JedisShardInfo> list = new LinkedList<JedisShardInfo>();
list.add(jedisShardInfo1);
list.add(jedisShardInfo2);


初始化 ShardedJedisPool 代替 JedisPool:
ShardedJedisPool pool = new ShardedJedisPool(config, list);


改由ShardedJedis,获取Jedis对象:
// 从池中获取一个Jedis对象
ShardedJedis jedis = pool.getResource();
String keys = "name";
String value = "snowolf";
// 删数据
jedis.del(keys);
// 存数据
jedis.set(keys, value);
// 取数据
String v = jedis.get(keys);
System.out.println(v);
// 释放对象池
pool.returnResource(jedis);


通过以上方式,向redis进行set操作的key-value,会通过hash而均匀的分配到pool里的redis机器中。



参考原文: http://www.tuicool.com/articles/jM7RF3Y
参考原文: http://www.open-open.com/lib/view/open1410485827242.html
参考原文: http://www.cnblogs.com/stephen-liu74/archive/2012/03/28/2357783.html

猜你喜欢

转载自huangyongxing310.iteye.com/blog/2324422