最近在链接池上面栽了个跟头(参见这里),引发我对池技术的强烈关注,这几天总结了一下不少场景都会使用的池技术;html
池概念java
pool,中文翻译为水池,可是在英文中,还有一种解释是redis
an organization of people or resources that can be shared;sql
不知道古代中文是否包含共享资源的意思,欧美语言中,池就是有资源共享的意思;数据库
为何要采用池技术apache
精确的说,应该是为何要使用链接池技术;咱们先看看这些使用池技术的组件都有哪些,httpclient HTTP协议组件,dbcp数据库链接池,jedis redis客户端;能够说表明了三种大相径庭的应用场景;可是他们背后,却都有一个共同点,那就是TCP长链接;后端
综上,我我的认为主要是出于如下几方面服务器
一、TCP链接每次创建和释放都比较耗时,特别是对于小的HTTP请求,若是能在业务调用时省去这段时间,则业务代码性能更好,这就须要提早创建TCP链接或者过后释放TCP链接;网络
二、业务代码会存在屡次资源调用,可是不但愿TCP链接对象在屡次调用之间传来传去,这样会让代码变的复杂;运维
三、组件但愿提供更友好的接口,而将底层的TCP技术使用池进行了封装;
有些人可能对长短链接概念不是很清楚,你们能够简单的认为,像HTTP协议请求完就会与服务器的链接断掉是短链接,一般咱们上网都是短链接。像开发过程当中使用的数据库客户端,通常会长时间与数据库维持一个TCP链接,这个能够就认为是长链接。除了DB,还有redis,java中的RMI等协议都是长链接;
长链接比短链接各有优劣:
好处:省去每次TCP3次握手和4次挥手的过程,发送请求和响应耗时更短;
坏处:服务器切换影响比较大,一般只能经过强制手段让客户端从新创建链接才能完成后端服务的切换;单纯从运维角度看,长链接很是不提倡;
池抽象
若是画一张图,我想应该是这样
就是在一个大池子里面,有好多资源。这些资源随时可能被拿出去占用或者随时有新的资源被归还,好借好还,再借不难;正常状况应该是这样
这就是池技术的基本原理,这个模型很重要,httpclient,dbcp,jedis,c3p0,druid,okhttp这些组件都使用到了池技术,你们能够自行去官网查看;下面我再抽几个重点场景给你们几个常见的重要配置参数;
链接池总资源数
既然是池,其容量老是有限制的,而且不一样的组件,其总量限制默认都很低。
组件 |
最大资源数属性 |
默认最大资源数 |
httpclient4 |
MaxTotal |
20 |
jedis2 |
maxTotal |
8 |
druid |
maxActive |
8 |
c3p0 |
maxPoolSize |
15 |
关于httpclient,还要特殊说明一下,这个maxTotal,存在误区,能够参见这里;
那么问题来了,若是TCP链接的另一端响应忽然变慢,致使租户没法及时归还资源,新的用户又要借用,但链接池中没有资源了,组件会如何处理?
答案是等;并且,若是你没有修改默认设置的话,默认是无限的等;你可能会说,我不相等,我想让系统有自我保护功能,当后端依赖出现问题的时候,咱们尽快的反馈给调用方,而不是把本身耗死;OK,你的想法很不错,可是你须要修改配置,让调用方不是无限等,能够设置调用方不等或者等待有限时间
组件 |
属性 |
httpclient4 |
RequestConfig.ConnectionRequestTimeout |
jedis2 |
MaxWaitMillis |
druid |
maxWait |
c3p0 |
breakAfterAcquireFailure |
dbcp |
maxWaitMillis |
TCP链接的问题
由于网络协议太复杂了,当组件采用池技术后,一系列后遗症也逐渐暴露出来;有时发现从池中取出链接使用时,发现链接已经被服务器端关闭了;而且这种状况,各类池组件没法感知(这个提及来又能说一篇),这些链接在英文中称为stale;针对这种状况,各类组件基本上围绕使用流程在使用前,使用后以及定时任务清理三种策略来避免这种状况;
使用前
组件一般采用在用户代码请求时,组件先本身测试TCP链接是否还可用,可是这种手段一般仅对DB链接池组件有效;如dbcp组件,一般会向服务器端发送一个测试sql来测试链接是否还可用;
使用后
同使用前检测同样,这种方法也是一般应用在数据库链接池中;在数据库出现问题时,一般链接已经不可用,这个时候再return给链接池,也会给其余后申请者形成影响,不如直接释放链接,后续再创建新的链接;
按期检测
一般链接池在不一样的时间,池中空闲的链接数量是不一样的,在业务低峰期,长时间维持一些没用的链接也是一种浪费。一般这个时候会有一个定时任务来按期清理长期不活跃的链接。具体的清理策略各式各样,有按照链接时长清理的,有按照长时间没有活动清理的。这个清理又会涉及不少参数设置,你们能够自行阅读参考;
另外,在数据库链接池中针对低峰期空闲链接多的问题(一般会致使系统time_wait多的问题),链接池一般还有一个最大空闲链接数(maxIdle)和最小空闲链接数(minIdle)两个参数,这两个参数的含义以下:
minIdle:保证池中最少要有minIdle个空闲的链接可用。若是少于这个数,则开始预建立链接;
maxIdle:保证池中最多有maxIdle个空闲的链接,当链接池被不断归还时,若是空闲链接数超过maxIdle,则开始对空闲的链接数进行释放。
最后还有一点,druid,dbcp和jedis池技术都是采用或者参考的apache的common-pool,不少参数都跟common-pool同样。okhttp是后起之秀,虽然也使用了池技术,可是在同步调用中,并无对池的大小设置闲置,能够认为,okhttp是一个无限制的链接池;
搜索公众号“猿界汪汪队”,关注更多有深度的文章;
参考资料:
http://hc.apache.org/httpcomponents-client-ga/tutorial/html/index.html
http://commons.apache.org/proper/commons-dbcp/configuration.html
https://www.mchange.com/projects/c3p0/#configuration_properties