欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Jedis 学习笔记

程序员文章站 2022-05-18 09:27:56
...

最近使用jedis的时候碰到一些问题,记录下。

Jedis的官方地址: https://github.com/xetorthio/jedis

 

问题1: Jedis提供了很多pool(JedisPool, JedisSentinelPool,ShardedJedisPool,JedisCluster),它们分别什么时候用?

Jedis/JedisPool

针对单个redis服务器,进行多线程并发连接时,提高效率使用;

 

Jedis/JedisSentinelPool

针对master/slave模式,并启用了sentinel方式时使用,并发连接池,多线程共享连接池;

 

ShardedJedis/ShardedJedisPool

针对多个redis服务器是分离的(横向扩展),相互之间不进行备份通信的情况。

 

JedisCluster

针对redis的cluster模式时使用。

 

示例图:

Jedis 学习笔记

参考:https://greatestrabit.github.io/2016/04/17/firstjedis/

 

问题2: JedisPool是多线程安全吗?getResource需要归还吗?

using Jedis in a multithreaded environment

You shouldn't use the same instance from different threads because you'll have strange errors. And sometimes creating lots of Jedis instances is not good enough because it means lots of sockets and connections, which leads to strange errors as well. A single Jedis instance is not threadsafe! To avoid these problems, you should use JedisPool, which is a threadsafe pool of network connections. You can use the pool to reliably create several Jedis instances, given you return the Jedis instance to the pool when done. This way you can overcome those strange errors and achieve great performance.

To use it, init a pool:

JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");

You can store the pool somewhere statically, it is thread-safe.

JedisPoolConfig includes a number of helpful Redis-specific connection pooling defaults. JedisPool is based on Commons Pool 2, so you may want to have a look at Commons Pool's configuration. Please see http://commons.apache.org/proper/commons-pool/apidocs/org/apache/commons/pool2/impl/GenericObjectPoolConfig.html for more details.

You use it by:

/// Jedis implements Closeable. Hence, the jedis instance will be auto-closed after the last statement.
try (Jedis jedis = pool.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);
}
/// ... when closing your application:
pool.close();

If you can't use try-with-resource, you can still enjoy with Jedis.close().

Jedis jedis = null;
try {
  jedis = pool.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);
} finally {
  // You have to close jedis object. If you don't close then
  // it doesn't release back to pool and you can't get a new
  // resource from pool.
  if (jedis != null) {
    jedis.close();
  }
}
/// ... when closing your application:
pool.close();

If Jedis was borrowed from pool, it will be returned to pool with proper method since it already determines there was JedisConnectionException occurred. If Jedis wasn't borrowed from pool, it will be disconnected and closed.

参考:https://github.com/xetorthio/jedis/wiki/Getting-started

 

JedisUtil的代码例子:

import com.alibaba.fastjson.JSON;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Description: To do
 * <p>
 * Author : Adore Chen
 * Created: 2018-08-22
 */
public class JedisUtil {

    private static JedisPool jedisPool;

    private JedisUtil(){

    }

    public static void configure(String host, int poolSize) {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(poolSize);
        jedisPoolConfig.setMaxIdle(15);
        jedisPoolConfig.setMinIdle(1);
        jedisPoolConfig.setMaxWaitMillis(10000);
        jedisPoolConfig.setTestOnBorrow(true);
        jedisPool = new JedisPool(jedisPoolConfig, host);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> jedisPool.close()));
    }

    public static Jedis getResource(){
        return jedisPool.getResource();
    }

    /**
     * use case.
     * @param item
     */
    public static void put(Item item){
        try(Jedis jedis = jedisPool.getResource()){
            String json = JSON.toJSONString(item);
            System.out.println(json);
            jedis.set(item.getId(), json);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

 

问题3: 一次性查询多个key的数据的处理方式?

Jedis、Redis提供了Pipeline方式来处理批量提交命令,可以很好的提高性能。主要减少了RTT(Round Trip Time)和进程切换(数据从网卡到达后,先保存在系统空间。从系统态到用户态切换的时间) 。

It's not just a matter of RTT

Pipelining is not just a way in order to reduce the latency cost due to the round trip time, it actually improves by a huge amount the total operations you can perform per second in a given Redis server. This is the result of the fact that, without using pipelining, serving each command is very cheap from the point of view of accessing the data structures and producing the reply, but it is very costly from the point of view of doing the socket I/O. This involves calling the read() and write() syscall, that means going from user land to kernel land. The context switch is a huge speed penalty.

参考:https://redis.io/topics/pipelining

pipeline的使用代码:

/**
 * Pipelining
 * 测试时间:0.287 seconds
 */
@Test
@Ignore
public void testPipelining(){
	Jedis jedis = new Jedis("localhost");
	Pipeline pipeline = jedis.pipelined();
	long start = System.currentTimeMillis();
	for(int i = 0; i< COUNTER; i++){
		pipeline.set("p" + i, "p" + i);
		if(i == 100){
			System.out.println(jedis.get("p1"));
		}
	}
        // no return results
        // pipeline.sync();
	List<Object> results = pipeline.syncAndReturnAll();
	long end = System.currentTimeMillis();
	logger.info("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
	jedis.close();
	System.out.println("result: " + results.get(0));
	System.out.println(jedis.get("p1"));
}
相关标签: jedis redis