在应用系统开发过程中,经常会使用到池化技术,如对象池,连接池,线程池等,通过复用技术来减少一些消耗,以提升性能。
1.对象池通过复用对象减少创建对象,垃圾回收的开销;
注,池不能太大,太大会影响GC时的扫描时间
2.连接池,如数据库连接池/Redis连接池/HTTP连接池,通过复用TCP连接来减少创建和释放连接的时间来提升性能
3.线程池,通过复用线程来提升性能
池化技术可以使用Apache-commons-pool2来实现,例如DBCP,Jedis连接池都是使用commons-pool2技术实现,不建议使用commons-pool1。
*****************************数据库连接池*****************************
数据库连接池有很多实现,如C3P0,DBCP,Druid等等,KT用的最多的是Durid和DBCP。
示例:commons-dbcp2 2.1.1
1.DBCP连接池配置
<!-- dbcp2配置文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driver}" />
<!-- 数据库连接相关配置(URL 用户名 密码 测试Query 默认超时时间) -->
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- Statement默认超时时间,单位:秒 -->
<property name="defaultQueryTimeout" value="3"/>
<!-- 默认是否自动提交事务 -->
<property name="defaultAutoCommit" value="false"/>
<!-- 数据库连接属性:不同数据库配置不一样 -->
<property name="connectionProperties" value="connectionTimeout=2000;socketTimeout=2000"/>
<!-- 连接池队列类型默认LIFO,false表示FIFO -->
<property name="lifo" value="false"/>
<!-- 建议以下值尽量一样,没必要频繁地过期空闲连接(除非出现连接池资源短缺等情况,才考虑) -->
<property name="initialSize" value="${initialSize}"/> <!-- 初始化连接大小 -->
<property name="minIdle" value="${minIdle}"/> <!-- 连接池最小空闲 -->
<property name="maxIdle" value="${maxIdle}"/> <!-- 连接池最大空闲 -->
<property name="maxTotal" value="${maxTotal}"/> <!-- 连接池最大数量 -->
<!-- 等待获取连接最大等待时间,不需要太大,比如设置在500毫秒 -->
<property name="maxWaitMillis" value="${maxWaitMillis}"/>
<!-- 验证数据库连接是否有效/可用 -->
<property name="testOnBorrow" value="true"/><!-- 从池中获取连接时进行 validateConnection,默认为true -->
<property name="testOnCreate" value="false"/><!-- 新建连接时进行 validateConnection,默认为false -->
<property name="testOnReturn" value="false"/><!-- 将连接释放回池时进行validateConnection,默认为false -->
<property name="validationQuery" value=""/><!-- 若不设置则调用Connection#isValid(int timeout)验证数据库是否有效 -->
<property name="maxConnLifetimeMillis" value="0"/><!-- 连接存活的最长时间,<=0表示禁用 -->
<property name="timeBetweenEvictionRunsMillis" value="0"/><!-- 驱除定时器执行周期,<=0表示禁用 -->
<property name="softMinEvictableIdleTimeMillis" value="0"/><!-- 连接空闲多久从池中驱除,<=0表示不做判断,当mindle<当前空闲连接数量时,开始这个判断 -->
<property name="minEvictableIdleTimeMillis" value="0"/> <!-- 连接空闲多久从池中驱除,与 softMinEvictableIdleTimeMillis是或的关系-->
<property name="numTestsPerEvictionRun" value="0"/><!-- 每次测试多少空闲对象,<=0相当于禁用 -->
<property name="testWhileIdle" value="false"/> <!-- 当连接空闲时是否测试,即保持连接一直存货,配合驱动定时器使用 -->
<property name="evictionPolicyClassName" value="org.apache.commons.pool2.impl.DefaultEvictionPolicy"/> <!-- 判断连接是否需要驱除的策略,默认为DefaultEvictionPolicy -->
<!-- 移除无引用连接(那些没有close的连接,此处设置为false,需要保证连接一定要释放) -->
<property name="removeAbandonedOnBorrow" value="false"/>
<property name="removeAbandonedOnMaintenance" value="false"/>
<!-- 超时后将关闭无引用连接,单位:秒 -->
<property name="removeAbandonedTimeout" value="10"/>
</bean>
说明:
【数据库连接配置】
备注一点,也可以在JDBC URL ?proName=prop Value配置这些属性
【池配置】
【验证数据库连接有效性】
三种方法:主动测试,定时测试,关闭孤儿连接
【关闭孤儿连接】
2.DBCP配置建议
2.1在并发量大的情况下:
(1)几个池大小设置为一样
(2)禁用关闭孤儿连接
(3)禁用定时器
如下:
<!-- dbcp2配置文件 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<!-- 省略url username password -->
<!-- Statement默认超时时间,单位:秒 -->
<property name="defaultQueryTimeout" value="3"/>
<!-- 默认是否自动提交事务 -->
<property name="defaultAutoCommit" value="false"/>
<!-- 数据库连接属性:不同数据库配置不一样 -->
<property name="connectionProperties" value="connectionTimeout=2000;socketTimeout=2000"/>
<property name="testOnBorrow" value="true"/><!-- 从池中获取连接时进行 validateConnection,默认为true -->
<!-- 连接池队列类型默认LIFO,false表示FIFO -->
<property name="lifo" value="false"/>
<!--省略池配置(池大小设置为一样)-->
<!-- 等待获取连接最大等待时间,不需要太大,比如设置在500毫秒 -->
<property name="maxWaitMillis" value="500"/>
<property name="timeBetweenEvictionRunsMillis" value="0"/><!-- 驱除定时器执行周期,<=0表示禁用 -->
<property name="numTestsPerEvictionRun" value="80"/><!-- 每次测试多少空闲对象,<=0相当于禁用 -->
<property name="testWhileIdle" value="true"/> <!-- 当连接空闲时是否测试,即保持连接一直存货,配合驱动定时器使用 -->
</bean>
2.2并发量不大时建议:
(1)按需设置池大小
(2)禁用关闭孤儿连接
(3)启用定时器(注意MYSQL空闲8小时自动断开)
如下:
<!-- dbcp2配置文件 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<!-- 省略url username password -->
<!-- Statement默认超时时间,单位:秒 -->
<property name="defaultQueryTimeout" value="3"/>
<!-- 默认是否自动提交事务 -->
<property name="defaultAutoCommit" value="false"/>
<!-- 数据库连接属性:不同数据库配置不一样 -->
<property name="connectionProperties" value="connectionTimeout=2000;socketTimeout=2000"/>
<property name="testOnBorrow" value="false"/><!-- 从池中获取连接时进行 validateConnection,默认为true -->
<!-- 连接池队列类型默认LIFO,false表示FIFO -->
<property name="lifo" value="false"/>
<!--省略池配置(池大小设置为一样)-->
<!-- 等待获取连接最大等待时间,不需要太大,比如设置在500毫秒 -->
<property name="maxWaitMillis" value="500"/>
<property name="timeBetweenEvictionRunsMillis" value="3600000"/><!-- 驱除定时器执行周期,<=0表示禁用 -->
</bean>
总结:
(1)无论何种方式,都必须设置超时时间
(2)在JVM关闭/重启时一定要销毁连接池(bean设置为destory-method="close")
3.数据库驱动超时 的 实现
4.连接池使用的一些建议
(1)注意网络阻塞/不稳定时出现的级联效应,还有当前等待连接池的人数过多,比如1000,那么接下来的等到就没有意义了,还会造成滚需求效应。
建议:
使用熔断和快速失败机制,即在连接池内部应该根据当前网络状态(例如超时次数过多),将一定时间内(比如100ms)的请求全部timeout,根本不进行await(maxAwait)
(2)DBCP比较容易出现的问题是:设置超时时间过长,造成大量TIMED_WAIT和线程阻塞,而且像滚雪球,一旦出现问题很难理解恢复,可以通过上下文方案解决。
等待超时时间应尽可能小些,即使返回错误页,也比等待并阻塞强
1. 数据库连接池应用中数据库服务器断开超时连接的问题
要点:应用中数据库连接池中会保存指定数量的数据库连接实例,而这些连接实例并没有定时地检测其到数据库服务器连接是否正常;
与此同时,数据库服务器存在数据库连接实例的超时时间,超过时间后它会自动断开连接。
也就是,被断开的那个连接此时仍然保存在应用的数据库连接池内,下次被使用的时候就会发生数据库连接断开而导致一次访问失败。
推荐解决方案:
1)如果能够提供这样一种检测机制,在应用的连接池管理中定时地检测连接池中连接的有效性,就完全可以避免上面描述的问题。
2)在应用代码中通过异常处理机制,来实现该次业务的重新处理,也可以很好地避免。
3)C3P0,Proxool,BoneCP,Druid等连接池的断开自动重联功能
参考:https://www.oschina.net/question/59889_44927
参考:http://blog.csdn.net/shirdrn/article/details/8248814
<property name="driverClass" value="${jdbc.driver}" /> com.mysql.jdbc.Driver
<property name="driverClass" value="oracle.jdbc.driver.OracleDriver" />
http://blog.sina.com.cn/s/blog_85d71fb70101ab99.html
Spring配C3P0
http://blog.csdn.net/vebasan/article/details/5059000
Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource卡住
解决方案:肯定是网络,用户名密码的错误导致
*****************************HttpClient连接池**********************************
见 《HttpClient使用详解》
*****************************Java线程池****************************************
总的:线程池,通过复用线程来提升性能;
背景:
线程是一个操作系统概念。操作系统负责这个线程的创建、挂起、运行、阻塞和终结操作。而操作系统创建线程、切换线程状态、终结线程都要进行CPU调度,这是一个耗费时间和系统资源的事情。
在如下场景下:
处理某一次请求的时间是非常短暂的,但是请求数量是巨大的。如果为每个请求都单独创建一个线程,那么物理机的所有资源基本上都被操作系统创建线程、切换线程状态、销毁线程这些操作所占用,用于业务请求处理的资源反而减少了。
另外,一些操作系统是有最大线程数量限制的。当运行的线程数量逼近这个值的时候,操作系统会变得不稳定。这也是我们要限制线程数量的原因。每个线程都需要一个内存栈,用于存储局部变量,操作栈等信息,通过-Xss参数来调整每个线程栈大小(64位系统默认1024kb,可根据实际需要调小,比如256KB)
通过调整该参数可以创建更多的线程,不过JVM不能无限制地创建线程
最理想的处理方式:将处理请求的线程数量控制在一个范围,既保证后续的请求不会等待太长时间,又保证物理机将足够的资源用于请求处理本身。
使用线程池:线程池会限制创建的线程数,从而保护系统;线程池配合队列工作,限制并发处理的任务数量,当任务超限时,通过一定的策略来处理,可避免系统因为大流量
而导致崩溃-只是部分拒绝服务,还是有一部分是正常服务的。
线程池分为:核心线程池和最大数量线程池,线程池中线程空闲一段时间会被回收,核心线程是不会被回收的。
合适的线程数:
(1)建议根据实际业务情况来压测决定
(2)利特尔法则:在一个稳定系统内,长时间观察到的平均用户数量L = 长时间观察到的有效达到率 * 平均每个用户在系统花费的时间。
针对(2)实际情况更复杂,如:在处理超时,网络抖动会导致线程花费时间不一样。
鉴于在处理超时,网络抖动会导致线程花费时间不一样,可能造成的线程数不合理,需要考虑:超时机制,线程隔离机制,快速失败机制等来保护系统
Java语言为我们提供了两种基础线程池的选择:ScheduledThreadPoolExecutor和ThreadPoolExecutor。它们都实现了ExecutorService接口
(注意,ExecutorService接口本身和“线程池”并没有直接关系,它的定义更接近“执行器”,而“使用线程管理的方式进行实现”只是其中的一种实现方式)。
这篇文章中,我们主要围绕ThreadPoolExecutor类进行讲解。
Java提供了ExecutorService三种实现
(1)ThreadPoolExecutor:标准线程池
(2)ScheduledThreadPoolExecutor:支持延迟任务的线程池
(3)ForkJoinPool:
类似于ThreadPoolExecutor,但是使用work-stealing模式,其会为线程池中的每个线程创建一个队列,从而用work-stealing(任务窃取)算法使得线程可以从其他
线程队列里窃取任务来执行。即如果自己的任务处理完成了,可以去忙碌的工作线程哪里窃取任务执行。
*****************************Tomcat线程池**************************************
见<<Tomcat实践>> 【2.1.5 连接池配置】
- 浏览: 65829 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (69)
- 系统评估,设计与规划 (4)
- 性能测试与诊断 (3)
- 硬件,网络与操作系统 (1)
- &&&&性能层面&&&& (0)
- 负载均衡与反向代理 (4)
- 应用扩容-RPC,SOA和微服务 (11)
- 数据扩容-应用层面&中间件 (6)
- 网络协议框架 (0)
- OpenResty (5)
- 缓存 (7)
- 应用服务器:基础及优化 (2)
- JVM:基础及优化 (1)
- Java及开发框架相关技术 (2)
- 关系型数据库:基础优化及读写分离 (9)
- NOSQL数据库 (0)
- 开发工具 (1)
- 收藏 (1)
- 实践项目总结 (0)
- 搜索引擎 (1)
- Zookeeper (1)
- &&&&可用性层面&&&& (1)
- 池化技术 (2)
- 学习 (1)
- 分布式系统链路追踪 (1)
- 开发效率 (1)
- jdk使用及源码解析 (1)
- 高级架构设计师考试 (0)
- JAVA设计模式 (1)
- JAVA虚拟机 (1)
- 数据结构与算法 (1)
- 网络 (1)
- 多线程 (0)
- 源码解析 (1)
- 业务场景及解决方案 (0)
- 石杉架构 (1)
相关推荐
### Apache Commons Pool:Java对象池化技术详解 #### 一、引言 在现代软件开发过程中,尤其是在基于Java的企业级应用开发中,资源管理和优化变得尤为重要。创建和销毁对象的成本通常较高,特别是在高并发场景下,...
Tomcat与java web 开发技术详解-
《Linux设备驱动开发详解-基于最新的Linux4.0内核》是一本深入探讨Linux设备驱动程序开发的专业书籍,其源码提供了丰富的实践示例,帮助读者理解如何在Linux操作系统下编写和调试驱动程序。该书涵盖了从基础概念到...
《Tomcat与Java Web开发技术详解》是孙卫琴老师撰写的一本深入解析Java Web开发和Tomcat服务器的著作,其第二版进一步更新了内容,提供了更为详尽的指导。这本书针对初学者和有一定经验的开发者,旨在帮助读者掌握...
嵌入式Linux系统开发技术详解--基于ARM(完整版) 嵌入式开发资料 更多资源,请登录我的博客:http://blog.csdn.net/hi_Emily 如需real 6410 嵌入式ARM11开发板请登录My_Shop:http://shop62249124.taobao.com/
Tomcat连接器(Connector)是Apache Tomcat服务器的核心组件之一,负责接收客户端的连接请求,创建请求对象,将请求分派给处理请求的Servlet容器,并最终返回响应。在Tomcat的配置和性能优化中,了解如何设置连接数...
FEKO 5.4 电磁场分析技术与实例详解-2009
### WebSphere连接池参数详解 在企业级应用服务器领域中,IBM WebSphere Application Server(简称WebSphere或WAS)是一款非常流行的解决方案。其中,连接池技术是提高数据库访问效率的关键技术之一。本文将深入...
【标题】"(PiggyXP)完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三——源码" 提供了一个深入理解网络编程中关键概念的机会,这次聚焦的是“完成端口”(Completion Port,简称IOCP)。...
一、要实现高效的线程池,可以考虑以下几点 二、实现线程池可以按照以下步骤进行 三、简单的C++线程池代码示例 四、 基于boost编写的源码库 - 线程池 4.1 基于boost编写的源码库地址 4.2 boost线程池的先进先出、...
最好的华为网络技术入门级教材-官方精选版-PPT+详解-HCNA
最好的华为网络技术入门级教材-官方精选版-PPT+详解-HCNA.pdf
TracePro应用实例详解-压缩版(内容不变)
双线性池化(Bilinear pooling)是一种在深度学习领域中用于特征提取的高级技术,尤其在图像识别、细粒度分类和视觉问答等任务中展现出优越性能。它通过引入了矩阵乘法来增强特征之间的交互,从而捕获更丰富的上下文...
《PullToRefresh使用详解--构建下拉刷新的listView》博文对应原源码,博客地址:http://blog.csdn.net/harvic880925/article/details/17680305,讲解了PullToRefresh构建可下拉刷新的listView的过程;
嵌入式Linux应用程序开发详解-第1 章 Linux 快速入门.pdf 嵌入式Linux应用程序开发详解-第10章(嵌入式Linux网络编程).pdf 嵌入式Linux应用程序开发详解-第11章(嵌入式Linux设备驱动开发).pdf 嵌入式Linux应用...
《Linux设备驱动开发详解-基于最新的Linux4.0内核(第三版)》这本书深入探讨了这一领域的核心概念和技术。 首先,Linux设备驱动分为字符设备驱动、块设备驱动和网络设备驱动等几大类。字符设备驱动主要用于传输单个...
### Hibernate 连接池配置详解 #### 一、概述 在使用Hibernate进行数据库操作时,合理配置连接池是非常重要的一步。连接池可以帮助我们更高效地管理数据库连接资源,避免频繁创建与销毁数据库连接带来的性能开销。...