Druid缓存

连接Oracle数据库,打开PSCache,在其他的数据库连接池都会存在内存占用过多的问题,Druid是唯一解决这个问题的连接池。

oracle数据库下PreparedStatementCache内存问题解决方案:

Oracle支持游标,一个PreparedStatement对应服务器一个游标,如果PreparedStatement被缓存起来重复执行,PreparedStatement没有被关闭,服务器端的游标就不会被关闭,性能提高非常显著。在类似SELECT * FROM T WHERE ID = ?这样的场景,性能可能是一个数量级的提升。

由于PreparedStatementCache性能提升明显,DruidDataSource、DBCP、JBossDataSource、WeblogicDataSource都实现了PreparedStatementCache。

PreparedStatementCache带来的问题

阿里巴巴在使用jboss连接池做PreparedStatementCache时,遇到了full gc频繁的问题。通过mat来分析jmap dump的结果,发现T4CPreparedStatement占内存很多,出问题的几个项目,有的300M,有的500M,最夸张的900M。这些应用都是用jboss连接池访问Oracle数据库,T4CPreparedStatement是Oracle JDBC Driver的PreparedStatement一种实现。 oracle driver不是开源,通过逆向工程以及mat分析,发现其中占内存的是字段char[] defineChars,defineChars大小的计算公式是这样的:

defineChars大小 = rowSize * rowPrefetchCount

rowPrefetchCount在Oracle中,缺省值为10。

其中rowSize是执行查询设计的每一列的大小的和。计算公式是:

rowSize = col_1_size + col_2_size + ... + col_n_size

很悲剧,有些列数据类型是varchar2(4000),于是rowSize巨大,很多个表关联的SQL,rowSize可能高达数十K,再乘以rowPrefetchCount,defineChars大小接近1M。可以想想,maxPoolSize设置为30,PreparedStatementCacheSize设置为50的场景下,是可能导致PreparedStatementCache占据上G的内存。 实际测试得到的结果如下:

varchar2(4000)     col_size 4000 chars    clob -> col_size   col_size 4000 bytes

实际占据内存的公式:

占据内存大小峰值 = defineChars大小 * PreparedStatementCacheSize * MaxPoolSize

我们实际分析,一个应用运行的SQL大约数百条,PreparedStatementCacheSize为50,PreparedStatementCache的算法为LRU,很多的SQL执行之后,在Cache中HitCount为0就被淘汰了,淘汰的过程,其位置从第1移到第50,这个漫长的过程导致了defineChars不能够被young gc回收。

Druid的解决方案

使用OracleDriver提供的PreparedStatementCache支持方法,清理PreparedStatement所持有的buffer。 Oracle在10.x和11.x的Driver中,都提供了如下管理PreparedStatementCache的接口,如下:

package oracle.jdbc.internal;  import Java.sql.SQLException; public interface OraclePreparedStatement extends oracle.jdbc.OraclePreparedStatement, OracleStatement {     public void enterImplicitCache() throws SQLException;     public void exitImplicitCacheToActive() throws SQLException;     public void exitImplicitCacheToClose() throws SQLException; }

DruidDataSource在管理Oracle PreparedStatement Cache时,调用了上述方法。当调用了enterImplicitCache之后,T4CPreparedStatement中的defineChars和defineBytes都会被清空。

测试表明,通过上述处理,能够有效降低内存。

根据PreparedStatement执行的结果,计算RowPrefetch大小 DrudDataSource对在PreparedStatement.executeQuery和execute方法返回的ResultSet做监控统计执行SQL返回的行数,然后根据统计的结果来设置rowPrefetchSize。例如SQL

SELECT * FROM ORDER WHERE ID = ?

这样的SQL每次返回的纪录数量都是0或者1,根据这个统计的最大值来设置rowPrefetchSize。如果最大值为1,则需要设置rowPrefetchSize为2。

计算公式如下:

int maxRowFetchCount = max(resultSet.size) + 1; if (maxRowFetchCount > defaultRowPrefetch) {        maxRowFetchCount = defaultRowPreftech; } prearedStatement.rowPrefetch = maxRowFetchCount;

根据生产环境的监控统计,大多数的SQL返回的行数都是比较小的,通常是1。通过这种算法,能够减少PreparedStatementCache的内存占用。

添加PreparedStatementCache计数器 包括:

PreparedStatementCacheCurrentSize PreparedStatementCacheDeleteCount 缓存删除次数 PreparedStatementCacheHitCount 缓存命中次数 PreparedStatementCacheMissCount 缓存不命中次数 PreparedStatementCacheAccessCount 缓存访问次数

通过这五个计数器,我们清晰了解PreparedStatementCache的工作情况,然后根据实际情况调整。

12. Druid对比

各种数据库连接池对比

主要功能对比


Druid


BoneCP


DBCP


C3P0


Proxool


JBoss


LRU








PSCache








PSCache-Oracle-Optimized








ExceptionSorter







LRU

LRU是一个性能关键指标,特别Oracle,每个Connection对应数据库端的一个进程,如果数据库连接池遵从LRU,有助于数据库服务器优化,这是重要的指标。在测试中,Druid、DBCP、Proxool是遵守LRU的。BoneCP、C3P0则不是。BoneCP在mock环境下性能可能好,但在真实环境中则就不好了。

PSCache

PSCache是数据库连接池的关键指标。在Oracle中,类似SELECT NAME FROM USER WHERE ID = ?这样的SQL,启用PSCache和不启用PSCache的性能可能是相差一个数量级的。Proxool是不支持PSCache的数据库连接池,如果你使用Oracle、SQL Server、DB2、Sybase这样支持游标的数据库,那你就完全不用考虑Proxool。

PSCache-Oracle-Optimized

Oracle 10系列的Driver,如果开启PSCache,会占用大量的内存,必须做特别的处理,启用内部的EnterImplicitCache等方法优化才能够减少内存的占用。这个功能只有DruidDataSource有。如果你使用的是Oracle Jdbc,你应该毫不犹豫采用DruidDataSource。

ExceptionSorter

ExceptionSorter是一个很重要的容错特性,如果一个连接产生了一个不可恢复的错误,必须立刻从连接池中去掉,否则会连续产生大量错误。这个特性,目前只有JBossDataSource和Druid实现。Druid的实现参考自JBossDataSource。

13. Druid迁移

dbcp迁移:

DruidDataSource的配置是兼容DBCP的。从DBCP迁移到DruidDataSource,只需要修改数据源的实现类就可以了。

DBCP的数据库连接池的实现是:

org.apache.commons.dbcp.BasicDataSource

替换为:

com.alibaba.druid.pool.DruidDataSource

如果需要使用Druid的其他配置,可以参考https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_DruidDataSource%E5%8F%82%E8%80%83%E9%85%8D%E7%BD%AE

例子

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">     <property name="url" value="${jdbc_url}" />    <property name="username" value="${jdbc_user}" />    <property name="password" value="${jdbc_password}" />     <property name="filters" value="stat" />     <property name="maxActive" value="20" />    <property name="initialSize" value="1" />    <property name="maxWait" value="60000" />    <property name="minIdle" value="1" />     <property name="timeBetweenEvictionRunsMillis" value="60000" />    <property name="minEvictableIdleTimeMillis" value="300000" />     <property name="validationQuery" value="SELECT ‘x‘" />    <property name="testWhileIdle" value="true" />    <property name="testOnBorrow" value="false" />    <property name="testOnReturn" value="false" />    <property name="poolPreparedStatements" value="true" />    <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /></bean>

14. Druid特性

ExceptionSorter是JBoss DataSource中的优秀特性,Druid也有一样功能的ExceptionSorter,但不用手动配置,自动识别生效的。

maxIdle是Druid为了方便DBCP用户迁移而增加的,maxIdle是一个混乱的概念。连接池只应该有maxPoolSize和minPoolSize,druid只保留了maxActive和minIdle,分别相当于maxPoolSize和minPoolSize。

DruidDataSource支持JNDI配置,具体实现的类是这个:

com.alibaba.druid.pool.DruidDataSourceFactory,你可以阅读代码加深理解。

com.alibaba.druid.pool.DruidDataSourceFactory实现了javax.naming.spi.ObjectFactory,可以作为JNDI数据源来配置。

Tomcat JNDI配置

在Tomcat使用JNDI配置DruidDataSource,在/conf/context.xml中,在中加入如下配置:

<Resource      name="jdbc/druid-test"      factory="com.alibaba.druid.pool.DruidDataSourceFactory"      auth="Container"      type="javax.sql.DataSource"       maxActive="100"      maxIdle="30"      maxWait="10000"      url="jdbc:derby:memory:tomcat-jndi;create=true"      />

前半部分是基本信息,不能少的,后半部分是连接池的参数,具体参数看这里,大多数情况driverClassName可以自动识别的

添加Filter

<Resource      name="jdbc/druid-test"      factory="com.alibaba.druid.pool.DruidDataSourceFactory"      auth="Container"      type="javax.sql.DataSource"       maxActive="100"      maxIdle="30"      maxWait="10000"      url="jdbc:derby:memory:tomcat-jndi;create=true"      filters="stat"      />

15. Druid更换

Druid提供了一个中完全平滑迁移DBCP的办法。

1) 从http://repo1.maven.org/maven2/com/alibaba/druid/druid-wrapper/ 下载druid-wrapper-xxx.jar

2) 加入druid-xxx.jar

3) 从你的WEB-INF/lib/中删除dbcp-xxx.jar

4) 按需要加上配置,比如JVM启动参数加上-Ddruid.filters=stat,动态配置druid的filters

这种用法,使得可以在一些非自己开发的应用中使用Druid,例如在sonar中部署druid,sonar是一个使用jruby开发的web应用,写死了DBCP,只能够通过这种方法来更换。

时间: 2024-10-12 18:50:23

Druid缓存的相关文章

【分享】Java后台开发精选知识图谱

地址 引言: 学习一个新的技术时,其实不在于跟着某个教程敲出了几行.几百行代码,这样你最多只能知其然而不知其所以然,进步缓慢且深度有限,最重要的是一开始就对整个学习路线有宏观.简洁的认识,确定大的学习方向,这样才能事半功倍. 我们经常会遇到这样的情况: 一开始学习一门新技术的时候,面对着很多很多陌生的名词,无从下手,一度想要放弃. 本文首先会给出关于java后台开发和前端适配的一些建议学习路线,接着简单解释一些应用到的高频技术,帮助大家理解和学习,算是一个入门篇. Java后台开发知识一览 1.

BootDo后台管理系统

BootDo是在SpringBoot基础上搭建的一个Java基础开发平台,MyBatis为数据访问层,ApacheShiro为权限授权层,Ehcahe对常用数据进行缓存. BootDo目前包括以下四大模块,系统管理(SYS)模块. 内容管理(CMS)模块.在线办公(OA)模块.代码生成(GEN)模块. 系统管理模块 ,包括企业组织架构(用户管理.机构管理.区域管理). 菜单管理.角色权限管理.字典管理等功能: 内容管理模块 ,包括内容管理(文章.链接),栏目管理.站点管理. 公共留言.文件管理.

java 整合redis缓存 SSM 后台框架 rest接口 shiro druid maven bootstrap html5

获取[下载地址]   QQ: 313596790A 调用摄像头拍照,自定义裁剪编辑头像 [新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统]B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单;  技术:313596790 freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块C 集成阿里巴巴数据库连接池druid;  数据库连接池  阿里巴巴的 druid.Druid在监控.可扩

java 整合redis缓存 SSM 后台框架 rest接口 shiro druid

获取[下载地址]   QQ: 313596790   [免费支持更新] 三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体 [新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统] A 集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单; QQ:313596790 freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块 B 集成阿里巴巴数据库连

集成代码生成器 SpringMVC mybatis shiro druid bootstrap HTML5 兼容PC 平板 手机 ehcache二级缓存

获取[下载地址]   QQ: 313596790   [免费支持更新]A 代码生成器(开发利器);全部是源码     增删改查的处理类,service层,mybatis的xml,SQL( mysql   和oracle)脚本,   jsp页面 都生成   就不用写搬砖的代码了,生成的放到项目里,可以直接运行B 阿里巴巴数据库连接池druid;  数据库连接池  阿里巴巴的 druid.Druid在监控.可扩展性.稳定性和性能方面都有明显的优势C 安全权限框架shiro ;  Shiro 是一个用

java 整合redis缓存 SSM 后台框架 rest接口 shiro druid maven b

A代码编辑器,在线模版编辑,仿开发工具编辑器,pdf在线预览,文件转换编码B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,快速开发利器)+快速表单构建器freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块C 集成阿里巴巴数据库连接池druid  数据库连接池  阿里巴巴的 druid.Druid在监控.可扩展性.稳定性和性能方面都有明显的优势D 集成安全权限框架shiro  Shiro 是一个用 Java 语言实

java企业级框架 SpringMVC_mybatis or hibernate+ ehcache +shiro+druid+bootstrap+HTML5

获取[下载地址]   QQ: 313596790   [免费支持更新] 支持三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体 [新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统] A 代码生成器(开发利器);       增删改查的处理类,service层,mybatis的xml,SQL( mysql   和oracle)脚本,   jsp页面 都生成    就不用写搬砖的代码了,生成的放到项目里,可以直接运行 B 阿里巴巴数据库连接

SpringMVC mybatis or hibernate ehcache二级缓存maven非和maven版本

获取[下载地址]   QQ: 313596790   [免费支持更新] 支持三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体 [新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统] A 代码生成器(开发利器);       增删改查的处理类,service层,mybatis的xml,SQL( mysql   和oracle)脚本,   jsp页面 都生成    就不用写搬砖的代码了,生成的放到项目里,可以直接运行 B 阿里巴巴数据库连接

【企业框架源码】 SpringMVC mybatis or hibernate ehcache二级缓存maven非和maven版本【websocket即时通讯】

获取[下载地址]   [免费支持更新]三大数据库 mysql  oracle  sqlsever   更专业.更强悍.适合不同用户群体[新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统] A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单;freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块B 集成阿里巴巴数据库连接池druid;  数据库连接池  阿里巴巴的 druid.Drui