读jedis学对象池

来源:互联网 发布:网络机体盒 编辑:程序博客网 时间:2024/05/12 20:59

读jedis学对象池

本文只是为了交流学习,不保证正确性,有问题可及时提出

Apache Commons pool用于提供对象池或者连接池的编写工具,本文简要介绍一下commons pool的主要功能,并以jedis中如何使用commons pool作为例子,加深理解。

根据GenericObjectPool api描述,池的配置如下:

(1)maxActive :表示能够分配的最大对象数目(包括正在被使用的和空闲等待的对象)。为负数时表示对象数目没有上限,默认值为8,当pool维护的对象数目超过maxActive配置的数目,pool的资源被耗尽。

(2)maxIdle:在同一时刻内最多可以维护的空闲对象的数目,默认为8.

(3)whenExhaustedAction:当调用borrow,pool维护的对象超过maxActive时,通过配置将会出现如下动作:

       1)WHEN_EXHAUSTED_FAIL borrowObject()将会抛出NoSuchElementException;

       2) WHEN_EXHAUSTED_GROW borrowObject()将会继续创建新的对象,并返回,因此,pool维护的对像数将超出maxActive;

       3)WHEN_EXHAUSTED_BLOCK,borrowObject()将会阻塞,直到有可用新的或者空闲的object为止,或者如果配置了maxWait,如果请求阻塞超时,将抛出NoSuchElementException. 如果maxWait为负数,请求将会无限制的阻塞下去,默认配置。

(4)testOnBorrow 如果设置,在调用borrowObject方法时,测试对象的可用性(使用PoolableObjectFactory.validateObject(T)方法),如果测试失败,此Object将会从池中删除,取得下一个Object进行测试。默认设置为false(对于链接池,测试对象往往会增加一次网络访问)。

(5)testOnReturn,在returnObject(T)时,会测试对象可用性,与testOnBorrow相似。

 

对于idle的object,可以设置一定的驱逐策略,让池中尽量保证少的维护对象。需要注意的是,过于频繁的测试驱逐很可能会引发性能问题。配置方法如下:

(1)timeBetweenEvictionRunsMillis定义驱逐扫描的时间间隔。配置为负值,不需要执行驱逐线程,默认为-1;

(2)minEvictableIdleTimeMillis确认某个Object空闲超时时间,负值为永远不超时,在驱逐线程清理超时对象时,只有空闲时间超过minEvictableIdleTimeMillis的对象才会被清除,默认为30分钟;

(3)testWhileIdle对idle的Object进行验证,无效的Object将会从池中删除;

(4)softMinEvictableIdleTimeMillis在驱逐时,可以预留一定数量的idle 对象,是minEvictableIdleTimeMillis的一个附加条件,如果为负值,表示如果驱逐,则所有idle对象都被驱逐;

(5)numTestsPerEvictionRun一次驱逐过程中,最多驱逐对象的个数;

 

对象队列有两种,一种是LIFO(last in first out)和FIFO(Firstin first out),可以选择两种之一。(注:对象在pool中实际是以队列的形式存在的,按照一定策略,在对象借出或者归还时插入队列的不同位置)

Lifo用于设置策略,默认为true。

下面,我们从jedis中拿出池代码,来看看池是如何使用的。

1.    池factory(JedisPool.java)

 

   /**

     * PoolableObjectFactory custom impl.

     */

    private static class JedisFactory extends BasePoolableObjectFactory {

        private final String host;

        private final int port;

        private final int timeout;

        private final String password;

        private final int database;

 

        public JedisFactory(final String host,final int port,

                final int timeout, final String password,final int database) {

            super();

            this.host = host;

            this.port = port;

            this.timeout = timeout;

            this.password = password;

            this.database = database;

        }

 

        public ObjectmakeObject() throws Exception {

            final Jedis jedis =new Jedis(this.host,this.port,this.timeout);

 

            jedis.connect();

            if (null !=this.password) {

                jedis.auth(this.password);

            }

            if(database != 0 ) {

                jedis.select(database);

            }

           

            return jedis;

        }

 

        public void destroyObject(final Object obj)throws Exception {

            if (objinstanceof Jedis) {

                final Jedis jedis = (Jedis) obj;

                if (jedis.isConnected()) {

                    try {

                        try {

                            jedis.quit();

                        } catch (Exception e) {

                        }

                        jedis.disconnect();

                    } catch (Exception e) {

 

                    }

                }

            }

        }

 

        public boolean validateObject(final Object obj) {

            if (objinstanceof Jedis) {

                final Jedis jedis = (Jedis) obj;

                try {

                    return jedis.isConnected() &&jedis.ping().equals("PONG");

                } catch (final Exception e) {

                    returnfalse;

                }

            } else {

                returnfalse;

            }

        }

    }

}

对象池工厂,继承与BasePoolableObjectFactory,并重写相应方法。

2.    池的实现

在jedis的Pool.java中,有如下代码:

  public Pool(finalGenericObjectPool.Config poolConfig,

            PoolableObjectFactory factory) {

        this.internalPool =new GenericObjectPool(factory, poolConfig);

    }

 

    @SuppressWarnings("unchecked")

    public T getResource() {

        try {

            return (T)internalPool.borrowObject();

        } catch (Exception e) {

            throw new JedisConnectionException(

                    "Could not get a resource from the pool", e);

        }

    }

       

    public void returnResourceObject(final Object resource) {

        try {

            internalPool.returnObject(resource);

        } catch (Exception e) {

            throw new JedisException(

                    "Couldnot return the resource to the pool", e);

        }

    }

3.    我们使用如下方法,创建池,获取池资源,返回池资源

 

       Config config = new Config();

       config.maxActive = 20;

       JedisPool pooles = new JedisPool(config,"10.4.21.51", 6379);

       Jedis jedis = pooles.getResource();

       List<String> rets = jedis.lrange("999",1000000000000999990L, 1000);

       pooles.returnResource(jedis);

4.    小结

GenericObjectPool的构造函数有两个参数,一个是Config,一个是PoolableObjectFactory,其中Config用于配置我们前面提到的参数选项,而PoolableObjectFactory则是实际创建对象,验证对象,销毁对象等的实际操作。

在我们的例子中,config仅设置了maxActive,即最大的可用Object数目,每创建一个Object,jedis就会创建一个与redis的链接,因此控制maxActive是必要的;当调用borrowObject()资源耗尽时,请求会排队并且maxwait值为-1,表示永远等待下去;timeBetweenEvictionRunsMillis默认为-1,因此,没有驱逐策略;lifo默认为true,因此使用last in first out 策略。

 

参考:

http://commons.apache.org/proper/commons-pool/api-1.6/org/apache/commons/pool/impl/GenericObjectPool.html

commons-pool-1.5.5.jar

jedis-2.1.0.jar