Apache Torque的关键配置参数 (DBCP)

来源:互联网 发布:直线裁剪算法代码 编辑:程序博客网 时间:2024/05/16 11:13

起因

频繁的connection close/open.

DBA点名:有个component从3个礼拜前突然开始频率的打开/关闭db的connection,大大抵消了使用connection pool的好处



调查

经探索发现,该component使用Torque来进行db connection pool的管理。而Torque又使用DBCP来管理connection pool。

而DBCP实际上又使用Object Pooling来。


在DBCP 的configuration中有这样的提示

 If maxIdle is set too low on heavily loaded systems it is possible you will see connections being closed and almost immediately new connections being opened. This is a result of the active threads momentarily closing connections faster than they are opening them, causing the number of idle connections to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good starting point.


这个现象和我们遇到的问题完全一致。然后重新check下产品上Torque的配置:

torque.dsfactory.XXX.pool.maxIdle=6torque.dsfactory.XXX.pool.maxActive=30


毫无疑问,maxIdle配置有误。DBCP的默认配置maxIdle和maxActive大小相同。

转到GenericKeyedObjectPool的javadoc

DBCP ParamparamDescritpionUsagemaxActive最大活动对象数目active是指被client正在使用的对象;可被认为是对象(资源)数目的峰值maxIdle最大空闲对象数目      对象返回到Pool时,Pool的最大size;可被认为是对象(资源)数目的平均值          timeBetweenEvictionRunsMillis回收任务的运行间隔默认是每5分钟检查一个Pool是否有对象Idle > minEvictableIdleTimeMillisminEvictableIdleTimeMillis空闲对象的存活时间默认如果该对象1小时内没有被使用,则认为可以被回收,比如真正的释放数据库连接minIdle最小空闲对象数目对象返回到Pool时/Pool初始化时,Pool的最小size


Common Pool 1.3 源码解析

borrowObject //仅抽取其主要分支,另外忽略key的存在,看作仅仅有单个pool
long starttime = System.currentTimeMillis();boolean newlyCreated = false;for(;;){   LinkedList pool = (LinkedList)(_poolMap.get(key)); //Pool为链接结构   pair = (ObjectTimestampPair)(pool.removeFirst()); //取pool中队头元素   if(null == pair)    {     int active = getActiveCount(key); //当前active数目,被client正在使用的对象数目     if ((_maxActive < 0 || active < _maxActive) //小于最大active,创建新的对象      {         Object obj = _factory.makeObject(key);         pair = new ObjectTimestampPair(obj);         newlyCreated = true;     }     else     {         switch(_whenExhaustedAction) //根据exhaust策略来创建,抛异常,或等待         {              case WHEN_EXHAUSTED_GROW:                           Object obj = _factory.makeObject(key);                           pair = new ObjectTimestampPair(obj);                           break;              case WHEN_EXHAUSTED_FAIL:                          throw new NoSuchElementException();              case WHEN_EXHAUSTED_BLOCK:                          if(_maxWait <= 0)                           {                               wait();  //不限时等待                          }                          else                          {                             final long elapsed = (System.currentTimeMillis() - starttime);                             final long waitTime = _maxWait - elapsed;                             if (waitTime > 0)                             {                               wait(waitTime); //限时等待                             }                          }                         //被唤醒或者限时已到                         if(_maxWait > 0 && ((System.currentTimeMillis() - starttime) >= _maxWait))                          {                               throw new NoSuchElementException("Timeout waiting for idle object");//timeout异常                         }                         else                          {                                 continue; // 重新尝试获取对象                         }                         }     }     incrementActiveCount(key); //active count++   }}

returnObject
LinkedList pool = (LinkedList) (_poolMap.get(key));decrementActiveCount(key); // active count--if(_maxIdle >= 0 && (pool.size() >= _maxIdle))  //pool中已有足够闲置对象{   shouldDestroy = true; //直接销毁}else{   pool.addLast(new ObjectTimestampPair(obj)); //放入队尾,更新对象访问时间戳}notifyAll(); //唤醒borrowObject中等待的线程if(shouldDestroy){  _factory.destroyObject(key, obj); //销毁对象}

看完上面两个方法,真相已经大白。
  • common pool采用链接队列(LinkedList)存放Idle 对象,其pool命名为idlePool更为合适;borrowObject从队列移除对象,returnObject(或者初始化)放对象到队列中。
  • 队列采用先前先出模式(队头取,队尾放),更老的对象先取出。
  • 采用acitve count进行计数,统计client正在使用的对象数目;Idle不需要另外计数, pool size即为idle数目
所以maxIdle一旦设置小于系统的资源负载,common pool会频繁的创建/销毁对象。比如maxIdle设置为6,而系统负载为14。
  • 假定初始为空,borrowObject创建14个对象;
  • 一半的资源(7)释放被同时释放,多余的1个对象会被销毁。
  • borrow 8个对象;pool中有6个idle,2个新的对象被创建。
  • 9个对象同时被释放,这时多余的3个对象被销毁。
  • 。。。
在系统实际运行中,只要系统的平均负载大于maxIdle,而且client使用释放资源都很短暂,则极有可能出现对象不断创建和销毁的情况。

清除任务,每次运行默认检查3个对象
evict
final LinkedList list = (LinkedList)_poolMap.get(key);if (_evictLastIndex < 0 || _evictLastIndex > list.size()) {      _evictLastIndex = list.size(); //不同的pool共用_evictLastIndex}objIter = list.listIterator(_evictLastIndex); // 从队尾开始  ObjectTimestampPair pair = (ObjectTimestampPair)(objIter.previous()); //使用list iteratorboolean removeObject=falseif(_minEvictableIdleTimeMillis > 0 &&    System.currentTimeMillis() - pair.tstamp > _minEvictableIdleTimeMillis) //闲置过长{     removeObject=true;}



原创粉丝点击