年底了,也差不多两个多月没有更新过这个blog了,是没什么内容好写,也是因为自己懒了。这一晃,一年过去了,对于已过而立之年的人来说,日子过得总是那么快。回首看看自己这一年,没什么收获,工资没变、本事没涨,虚度了这365天,多多少少有些失落。人生就是一张单程车票,过去了也就过去了,好好珍惜接下来的每一天吧。
好了,言归正传,说说这个主题的内容吧。客户碰到这么个问题,他把他们的连接池的初始、最大连接数(initial/max capacity)均设定为某一值,但运行一段时间后,他时常发现max capacity不起作用了,也就是说,从监控来看,当前活动连接数(current active connections)经常大于max capacity。开始怀疑这可能是个console的bug,后来跟客户确认netstat的结果,结果是网络连接数和active connections一致。好了,这说明跟console没有关系,连接池的问题,为什么连接池的max capacity不起作用呢?之前没有听说过类似的bug啊,要了客户的jdbc config,发现连接池配置中有如下信息:
1 <jdbc-connection-pool-params>
2 <initial-capacity>5</initial-capacity>
3 <max-capacity>5</max-capacity>
4 <connection-reserve-timeout-seconds>25</connection-reserve-timeout-seconds>
5 <test-connections-on-reserve>true</test-connections-on-reserve>
6 <test-table-name>dual</test-table-name>
7 <pinned-to-thread>true</pinned-to-thread>
8 </jdbc-connection-pool-params>
怀疑和pinned-to-thread的设置有关系,做了个测试,尝试重现这个问题,不出所料,问题真的重现出来了。至于pinned-to-thread有什么左右,问什么它会导致max-capacity不起作用,我们后面再说。先看看我们问题的重现过程。
我也配置了一个connection pool,初始、最大连接数均设定成5,连接池启动后,连接数监控如下:
写一个jsp, jsp中从datasource获取一个连接,然后关闭该连接,通过apache的ab执行一个压力测试,60个请求(每次并发15个), 然后监控连接使用情况如下:
从netstat的结果来看,WLS到Oracle的连接数的确也是15个,如下:
好了,现在我们再来看看pinned-to-thread是干什么的,为什么它会导致max capacity不起作用。pinned-to-thread在WLS中是用于提高connection reserver性能的选项,当我们选中这个选项后,WLS中执行线程在处理应用请求的使用,如果应用通过datasource.getConnection()申请连接,WLS首先从当前线程的thread local变量中检查时候有连接已经绑定,如果有,使用这个连接,如果没用,则从连接池中申请连接。thread local中storage[7]存储的就是连接信息,从debug信息来看,conns为空,即当前线程还没有获得绑定连接,所以连接最终会从connection pool中获取。
连接申请成功,客户使用完连接后,客户端调用connection.close()来释放这个连接,即我们通常意义上的还池。对于普通的connection pool,WLS的确是这么做的,连接被清理,然后还池并等待其他线程申请,但对于pinned-to-thread的连接池来说,虽然你调用connection.close(),实际连接并不会还池,为了性能嘛,还池的话,还得去重新申请,那就不存在性能调优的说法了。WLS不让这个连接还池,那不就泄露了吗?不会,WLS会将这个不还池的连接绑定到我们前面所说的当前线程的thread local中,这样下次这个线程处理其他请求需要使用连接的时候,连接就不用申请了,直接拿这个绑定连接即可。下面我们再来看看连接colse(),
看到了吧,连接关闭的时候,WLS只是把连接放到ConnectionPool$ConnectionStore中去了。
下面我们再看看为什么pinned-to-thread会导致max capacity不起作用。pinned-to-thread被选中后,如果连接池中有5个连接,这五个连接分别被5个执行线程取走并绑定给自己的话,如果此时某一个应用请求被分配到这5个线程以外的线程,如果max-capacity生效,那么这个线程将永远不能获取到连接(除非拿到连接的线程被destory掉,我们最终用户可干不了这事儿,这事得WLS的work manager自己处理),这对于用户而言是不可以接受的。因为我已有的5个连接可能根本就没有被使用(连接被绑定到执行线程后,对于连接池而言它就是active的,对于其他的用户而言是unavailable的),为什么其他线程拿不到连接,导致请求无法处理,所以WLS为了防止这种情况出现,在连接池被激活的时候,解除了max-capacity的限制,如下:
1 if (pinnedToThread) {
2 props.setProperty(ResourcePool.RP_PROP_MAX_CAPACITY, Integer.toString(Integer.MAX_VALUE));
3 }
好了,pinned-to-thread是干什么的你该清楚了吧,至于要不要选中它,需要你自己去把握。它是把双刃剑,好坏需要你去权衡。好坏大概如下:
1:好处是,可以一定程度上提高connection reserve的性能,少了reserve时候和其他线程的同步。
2:坏处是:可能会导致连接数不受管理,从而导致database端的session数达到上限。这跟应用线程并发量有一定关系,如果预估好最大并发请求,还是可控的。
posted on 2009-12-22 15:52
走走停停又三年 阅读(2231)
评论(2) 编辑 收藏 所属分类:
Weblogic