Jedis的使用及配置优化

Jedis是什么

jedis就是基于java语言的redis客户端,集成了redis的命令操作,提供了连接池管理。
redis-cli是redis官方提供的客户端,可以看作一个shell程序,它可以发送命令对redis进行操作。
对于jedis同理是使用java语言操作redis,双方都遵循redis提供的协议,按照协议开发对应的客户端。

Jedis的使用及配置优化_第1张图片
Maven依赖
    
        redis.clients
        jedis
        2.9.0
        compile
    

Jedis直连

jedis直连,本质是定义一个tcp连接,然后使用socket技术进行通信

    //1.生成一个jedis对象,这个对象负责和指定Redis节点进行通信
    Jedis jedis = new Jedis("119.23.226.29", 6379);
    //带密码需要执行认证方法
    //jedis.auth("123456");
    //2.jedis执行set操作
    jedis.set("hello", "world");
    //3.jedis执行get操作,value="world"
    String value = jedis.get("hello");
构造方法参数介绍
Jedis的使用及配置优化_第2张图片

Jedis简单使用

字符串
// 1.string
//输出结果: OK
jedis.set("hello", "world");
//输出结果: world
jedis.get("hello");
//输出结果:1
jedis.incr("counter");
哈希
// 2.hash
jedis.hset("myhash", "f1", "v1");
jedis.hset("myhash", "f2", "v2");
//输出结果 : {f1=v1, f2=v2}
jedis.hgetAll("myhash");
列表
// 3.list
jedis.rpush("mylist", "1");
jedis.rpush("mylist", "2");
jedis.rpush(" mylist", "3");
//输出结果 : [1, 2, 3]
jedis.lrange("mylist", 0, -1);
集合
// 4.set
jedis.sadd(" myset", "a");
jedis.sadd(" myset", "b");
jedis.sadd(" myset", "a");
//输出结果 : [b, a]
jedis.smembers("myset");
有序集合
// 5.zset
jedis.zadd("myzset", 99, "tom");
jedis.zadd("myzset", 66, "peter");
jedis.zadd("myzset", 33, "james");
//输出结果 : [[["james"],33.0], [["peter"],66.0], [["tom"],99.0]]
jedis.zrangeWithScores("myzset", 0, -1);

Jedis连接池

jedis直连

每次操作创建一个jedis对象,执行完毕后关闭连接,对应的就是一次Tcp连接。

Jedis的使用及配置优化_第3张图片
jedis连接池

预先生成一批jedis连接对象放入连接池中,当需要对redis进行操作时从连接池中借用jedis对象,操作完成后归还。这样jedis对象可以重复使用,避免了频繁创建socket连接,节省了连接开销。

Jedis的使用及配置优化_第4张图片
方案对比
Jedis的使用及配置优化_第5张图片

连接池简单使用

这里只是对连接池进行一个简单使用,实际开发通常会对JedisPool进行封装,进行一些参数配置和方法定义等,在使用Jedis API时,也会对常用API进行封装,方便程序调用

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class Demo {
    
    public static void main(String[] args) {
        //连接池配置对象,包含了很多默认配置
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        //初始化Jedis连接池,通常来讲JedisPool是单例的
        JedisPool jedisPool = new JedisPool(poolConfig, "119.23.226.29", 6379);
        Jedis jedis = null;
        try {
            //1.从连接池获取jedis对象
            jedis = jedisPool.getResource();
            //2.执行操作
            jedis.set("hello", "jedis");
            System.out.println(jedis.get("hello"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            //如果使用JedisPool,那么close操作不是关闭连接,代表归还连接池
            if(jedis != null){
                jedis.close();
            }
        }   
    }
}

Jedis配置优化

对于企业级开发来说,连接池的合理使用是非常重要的,如果设置不当会引起很多不必要的麻烦,容易造成线上的故障。
其实关于配置是一个比较难或者说没有确定答案的部分,这里只能给出一些思路和解决一些异常的方法。

连接池重要配置

为了方便使用,Jedis提供了JedisPoolConfig,它本身继承了GenericObjectPoolConfig设置了一些空闲监测设置

资源数控制
Jedis的使用及配置优化_第6张图片
借还参数
Jedis的使用及配置优化_第7张图片
适合的maxTotal

其实这个参数是比较难确定的,举个例子:

  • 命令平均执行时间0.1ms = 0.001s
  • 业务需要50000 QPS
  • maxTotal理论值 = 0.001 * 50000 = 50个。实际值要偏大一些

对于适合的maxTotal而言,我们需要考虑

  • 业务希望Redis并发量
  • 客户端执行命令时间
  • Redis资源:例如 nodes(例如应用个数) * maxTotal 是不能超过redis的最大连接数
  • 资源开销:例如虽然希望控制空闲连接,但是不希望因为连接池的频繁释放创建连接造成不必靠开销
适合的maxIdle和minIdle
  • 建议maxIdle = maxTotal,减少创建新连接的开销
  • 建议预热minIdle,减少第一次启动后的新连接开销
常见问题

无法从资源池获取到资源,原因是获取空闲连接超时了。

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)

无法从资源池获取到资源,原因是池子中资源已经耗尽了。

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:464)
解决思路
  1. 慢查询阻塞:池子连接都被hang住。
  2. 资源池参数不合理:例如QPS高、池子小。
  3. 连接泄露(没有close()):此类问题比较难定位,例如client list、netstat等,最重要的是写合理的代码。
  4. DNS异常等。
例如连接泄漏
    public static void main(String[] args){

        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(10);
        jedisPoolConfig.setMaxWaitMillis(1000);
    
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, "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();
            }
            //再次获取资源就会出错
            jedisPool.getResource().ping();
        }
    }

你可能感兴趣的:(Jedis的使用及配置优化)