对Redis连接池的深入理解与解析

原创 Cadet  2018-04-30 22:20  阅读 628 次 评论 0 条
摘要:

Redis是一种C/S的模式,但是频繁的链接会导致花费在底层链接上的时间大大增加(因为Redis是基于内存的,读取效率高,假设一次数据交互总共用时30ms,超高性能的Redis数据库处理数据所花的时间可能不到1ms,也即是说前期的连接占用了29ms)。

最近换了项目中,突然碰到redis了,对他的理解很有限,这里做个分享。

1.Redis的连接池(JedisPool)

说到连接池,我的第一反应是这可能跟数据源的C3P0类似。结果一查,恩,差不多。

Redis是一种C/S的模式,但是频繁的链接会导致花费在底层链接上的时间大大增加(因为Redis是基于内存的,读取效率高,假设一次数据交互总共用时30ms,超高性能的Redis数据库处理数据所花的时间可能不到1ms,也即是说前期的连接占用了29ms)。显然很不合理,怎么办呢。于是JedisPool就开始出现了。

连接池可以使在客户端建立多个连接并且不释放,想链接即可通过某算法建立连接,用完了,归还即可。这就免去了数据库链接所需要的时间。

但是如果超过连接池的上限以后,会怎么样呢:采用IO的多路复用来解决。

 

2.Redis的连接池的配置

package com.jedis;  

import java.util.concurrent.locks.ReentrantLock;    
import org.apache.commons.lang.StringUtils;    
import org.apache.log4j.Logger;  
import org.junit.Test;  

import redis.clients.jedis.Jedis;    
import redis.clients.jedis.JedisPool;    
import redis.clients.jedis.JedisPoolConfig;    

/**  
 * Reids的工具类    
 * @author EdwardShen  
 *  
 * 2018年4月30日  
 */  
public class JedisUtil {    

    protected static ReentrantLock lockPool = new ReentrantLock();    
    protected static ReentrantLock lockJedis = new ReentrantLock();    

    protected static Logger logger = Logger.getLogger(JedisUtil.class);    

    //Redis服务器IP    
    private static String ADDR_ARRAY = "127.0.0.1,127.0.0.2";    

    //Redis的端口号    
    private static int PORT = 6379;    

    //访问密码    
    private static String AUTH = "http://blog.csdn.net/sx1119183530";    
    //可用连接实例的最大数目,默认值为8;    
    //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。    
    private static int MAX_ACTIVE = 8;    

    //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。    
    private static int MAX_IDLE = 8;    

    //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;    
    private static int MAX_WAIT = 3000;    

    //超时时间    
    private static int TIMEOUT = 10000;    

    //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;    
    private static boolean TEST_ON_BORROW = false;    

    private static JedisPool jedisPool = null;    

    /**   
     * redis过期时间,以秒为单位   
     */    
    public final static int EXRP_HOUR = 60 * 60;            //一小时    
    public final static int EXRP_DAY = 60 * 60 * 24;        //一天    
    public final static int EXRP_MONTH = 60 * 60 * 24 * 30; //一个月    

    /**   
     * 初始化Redis连接池   
     */    
    @Test  
    private static void initialPool() {    
        try {    
            JedisPoolConfig config = new JedisPoolConfig();    
            config.setMaxTotal(MAX_ACTIVE);    
            config.setMaxIdle(MAX_IDLE);    
            config.setMaxWaitMillis(MAX_WAIT);    
            config.setTestOnBorrow(TEST_ON_BORROW);    
            System.out.println(ADDR_ARRAY.split(",")[0]+":"+ADDR_ARRAY.split(",")[1]);  
            jedisPool = new JedisPool(config, ADDR_ARRAY.split(",")[0], PORT, TIMEOUT, AUTH);    
        } catch (Exception e) {    
            logger.error("First create JedisPool error : " + e);    
            try {    
                //如果第一个IP异常,则访问第二个IP    
                JedisPoolConfig config = new JedisPoolConfig();    
                config.setMaxTotal(MAX_ACTIVE);    
                config.setMaxIdle(MAX_IDLE);    
                config.setMaxWaitMillis(MAX_WAIT);    
                config.setTestOnBorrow(TEST_ON_BORROW);    
                jedisPool = new JedisPool(config, ADDR_ARRAY.split(",")[1], PORT, TIMEOUT, AUTH);    
            } catch (Exception e2) {    
                logger.error("Second create JedisPool error : " + e2);    
            }    
        }    
    }    

    /**   
     * 在多线程环境同步初始化   
     */    
    private static void poolInit() {    
        lockPool.lock();    
        try {    
            if (jedisPool == null) {    
                initialPool();    
            }    
        } catch (Exception e) {    
            e.printStackTrace();    
        } finally {    
            lockPool.unlock();    
        }    
    }    

    public static Jedis getJedis() {    
        lockJedis.lock();    
        if (jedisPool == null) {    
            poolInit();    
        }    
        Jedis jedis = null;    
        try {    
            if (jedisPool != null) {    
                jedis = jedisPool.getResource();    
            }    
        } catch (Exception e) {    
            logger.error("Get jedis error : " + e);    
        } finally {    
            returnResource(jedis);    
            lockJedis.unlock();    
        }    
        return jedis;    
    }    

    /**   
     * 释放jedis资源   
     *   
     * @param jedis   
     */    
    public static void returnResource(final Jedis jedis) {    
        if (jedis != null && jedisPool != null) {    
            jedisPool.returnResource(jedis);    
        }    
    }    

    /**   
     * 设置 String   
     *   
     * @param key   
     * @param value   
     */    
    public synchronized static void setString(String key, String value) {    
        try {    
            value = StringUtils.isEmpty(value) ? "" : value;    
            getJedis().set(key, value);    
        } catch (Exception e) {    
            logger.error("Set key error : " + e);    
        }    
    }    

    /**   
     * 设置 过期时间   
     *   
     * @param key   
     * @param seconds 以秒为单位   
     * @param value   
     */    
    public synchronized static void setString(String key, int seconds, String value) {    
        try {    
            value = StringUtils.isEmpty(value) ? "" : value;    
            getJedis().setex(key, seconds, value);    
        } catch (Exception e) {    
            logger.error("Set keyex error : " + e);    
        }    
    }    

    /**   
     * 获取String值   
     *   
     * @param key   
     * @return value   
     */    
    public synchronized static String getString(String key) {    
        if (getJedis() == null || !getJedis().exists(key)) {    
            return null;    
        }    
        return getJedis().get(key);    
    }    
}

测试类:

    package com.jedis;  

    import java.text.DateFormat;  
    import java.text.SimpleDateFormat;  
    import java.util.Date;  

    import org.junit.Test;  
    /**  
     * 测试类  
     * @author EdwardShen  
     *  
     * 2018年4月30日  
     */  
    public class TestJedis extends Thread {  
        int i = 0;  

        public  TestJedis(int i) {  
            this.i = i;  
        }  

        public void run() {  
            Date date = new Date();  
            DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
            String time = format.format(date);  
            JedisUtil.setString("foo", time);  
            String foo = JedisUtil.getString("foo");  
            System.out.println("【输出>>>>】foo:" + foo + " 第:" + i + "个线程" + "当前时间:" + format.format(new Date()));  
        }  


        @Test  
        public void test()  
        {  
            System.out.println("kaishil  !");  
             for (int i = 0; i < 10000; i++) {              
                 TestJedis t = new TestJedis(i);    
                    t.start();    
                }   
        }  
    }
本文地址:https://www.icheny.cn/archives/948
关注公众号“我的IT小地方”:扫二维码乘月网的公众号 or 搜索公众号:it_place
版权声明:本文为原创文章,版权归 Cadet 所有,欢迎分享本文,转载请保留出处!
PREVIOUS:已经是最后一篇了

发表评论


表情