Jedis和Jedis连接池的基本使用和配置

(一)获取Jedis

Jedis是基于java语言的redis_cli

maven依赖:

<!-- Redis的redis客户端
https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>3.0.1</version>
</dependency>

(二)Jedis基本使用

1、Jedis直连:

 

 

 

Jedis直连相当于一个TCP连接,数据传输完成后关闭连接

//1.生成一个Jedis对象,这个对象负责和指定的Redis节点进行通信
Jedis jedis = new Jedis("127.0.0.1",6379);
//2.jedis执行set操作
jedis.set("hello","world");
//3.jedis执行get操作,value=“world”
String value =jedis.get("hello");

2、Jedis构造函数参数的意义:

Jedis(String host, int port, int connectionTimeout, int soTimeout)

host:Redis节点所在的机器的IP

port:Redis节点的端口

connectionTimeout:客户端连接超时

soTimeout:客户端读写超时

3、简单使用:

//Jedis数据类型:
//1.string
jedis.set("hello","world");
//输出结果: world
System.out.println(jedis.get("hello"));
//对counter自增,输出结果:1
System.out.println(jedis.incr("counter"));

//2.jash
jedis.hset("myhash","f1","v1");
jedis.hset("myhash","f2","v2");
//输出结果:{f2=v2, f1=v1}
System.out.println(jedis.hgetAll("myhash"));

//3.list
jedis.rpush("mylist","1");
jedis.rpush("mylist","2");
jedis.rpush("mylist","3");
//输出结果:[1, 2, 3]
System.out.println(jedis.lrange("mylist",0,-1));

//4.set
jedis.sadd("myset","a");
jedis.sadd("myset","b");
jedis.sadd("myset","a");
//输出结果:[a, b]
System.out.println(jedis.smembers("myset"));
//5.zset
jedis.zadd("myzset",22,"a");
jedis.zadd("myzset",33,"b");
jedis.zadd("myzset",35,"c");
//输出结果:[[a,22.0], [b,33.0], [c,35.0]]
System.out.println(jedis.zrangeWithScores("myzset",0,-1));

(三)Jedis连接池基本使用

1、Jedis Pool的简单介绍

 

 

使用Jedis线程池可以不需要创建新的Jedis对象连接Redis,可以大大减少对于创建和回收Redis连接的开销

2、对使用线程池和使用Jedis直连两方案的对比

 

 

 

3、Jedis Pool的简单使用

通常来讲JedisPool是单例的

GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);
Jedis jedis = null;
try {
    //从连接池获取jedis对象
    jedis = jedisPool.getResource();
    //执行操作
    jedis.set("java", "good");
    System.out.println(jedis.get("java"));
} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (jedis != null) {
        //这里使用的close不代表关闭连接,指的是归还资源
        jedisPool.close();
    }

}

4、Jedis配置优化思路

规划出连接池最大连接数,最大空闲数,最小空闲数,如果在借用池中连接没有资源时,是等待还是超时,如何控制连接池中的空闲对象。

 

 

 

 

1)如何确定maxTotal?

首先举个例子:

1.命令平均执行时间0.1ms = 0.001s。

2.业务需要50000QPS

3.maxTotal理论值 = 0.001*50000=50个。但是实际设计时可能会偏大一些。

由以上可以得出,需要考虑:业务希望的Redis并发量、客户执行命令的时间、Redis资源:例如nodes(应用个数)+maxTotal是不能超过redis的最大连接数的(config get maxclients)

2)如何确定合适的maxIdle和minIdle?

建议maxIdle=maxTotal,为什么这么说呢?假如现在maxTotal是100,maxIdle是50,那么允许的最大空闲数是50,那么在一个高峰期,如果连接池中的50个已经通过连接池的getResource获取到了,这个时候第51个连接是要通过newJedis以及TCP三次握手建立一个新的连接,实际上这本身是有一定开销的。这样可以减少新的开销。建议预热minIdle,第一次getResource时是newJedis并建立TCP三次握手的,对于并发量较大的情况是无法容忍第一次开销的,那么可以在应用初始化的时候提前使用getResource做一些操作。

5、常见问题:

获取连接超时,主要原因在maxWaitMills这个参数:

#获取连接超时,主要原因在maxWaitMills这个参数:
redis.clients.jedis.exceptions.JedisConnectionException:Could not get a resource from the pool
...
Caused By:java.util.NoSuchElementException:Timeout waiting for idle object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449)

#连接池资源耗尽,可能原因:maxIdle!=maxTotal
redis.clients.jedis.exceptions.JedisConnectionException:Could not get a resource from the pool
...
Caused By:java.util.NoSuchElementException:Pool exhausted
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449)

 

解决这一类问题的思路:

1.慢查询阻塞:连接池连接都被hang住。比如多个连接都在执行keys *,或者这redis本身的单线程被阻塞,当这两种情况发生时,都会出现上面两个问题,这就需要对每个操作设置超时时间,对maxWaitMills进行合理配置去观察是否合理,最重要的就是去解决这些慢查询。

2.资源池参数不合理:比如QPS高,连接池小。

3.连接泄露(没有close()):这类问题比较难定位,比如使用client list、netstat等,最重要的是写合理的代码,比如不使用try catch finally,如果中间发生了异常,close就无法执行了。

4.DNS异常也会导致这种问题。

举个例子(只要将注释内的内容取消就可以解决bug了):

public static void main(String[] args) {
    JedisPoolConfig poolConfig = new JedisPoolConfig();
    poolConfig.setMaxTotal(10);
    poolConfig.setMaxWaitMillis(1000);
    JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);
    for (int i = 0; i < 10; i++) {
        Jedis jedis = null;
        try {

            jedis = jedisPool.getResource();
            jedis.ping();
        } catch (Exception e) {
            e.printStackTrace();
        /*} finally {
            if (jedis != null) {
                jedisPool.close();
            }*/

        }
    }
    jedisPool.getResource().ping();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值