• 1. 原理调优篇-周仓(DBA)JBOSS连接池浅析
  • 2. 目标了解JBOSS连接池原理 连接池常见问题的分析调优
  • 3. 原理篇-提纲原理篇为什么要使用连接池?连接池的数据结构连接池操作的启动和关闭从连接池中:获取连接,返还连接,销毁连接
  • 4. JDBC连接数据库JDBC方式连接数据库加载JDBC驱动获得数据库连接执行SQL关闭数据库连接创建连接是很耗资源的过程 连接没有重复利用
  • 5. JDBC连接池方式连接池方式创建连接池和连接应用通过连接池获得连接应用返还连接解决了链接复用的问题
  • 6. 连接池的数据结构核心数据结构是ArrayList 取链接时从链表的尾部取出一个 返还链接是加到链表尾部 连接1连接2连接4连接3HEADTAIL请求获取返还
  • 7. 连接池的启动//连接池MAX连接数 this.maxSize = this.poolParams.maxSize; //连接池数组初始化。 cls = new ArrayList(this.maxSize); /*创建一个对应连接事件监听器的信号集,用于连接的获取。 每次获取连接或者创建连接之前,都需要获取信号量, 当没有可用的信号量时,表示连接已经到达max值。 */ permits = new FIFOSemaphore(this.maxSize); /* jboss配置文件中的prefill,默认为false。 如果设置为true,填充min连接数。 */ if(poolParams.prefill) { PoolFiller.fillPool(this); }Prefill参数在JBOSS4.0.5版本之后才能够被支持。启动代码如下:
  • 8. 连接池的初始化初始化操作:将连接池注册到IdleRemover线程和ConnectionValidator线程中。 IdleRemover默认是15分钟/次,清理空闲超过30分钟的连接。 ConnectionValidator默认是5分钟进行一次连接验证。
  • 9. 清理线程如何工作连接1连接2连接4连接3HEADTAIL请求获取返还从HEAD到TAIL进行销毁越靠近HEAD,空闲的时间越大LRU的链表的清理
  • 10. 如何验证连接有效性这个validate操作如何验证连接? 自定义的SQL来验证: 验证SQL java类验证方式: org.jboss.resource.adapter.jdbc.vendor.OracleValidConnectionChecker(直接调用jdbc的ping database(oracle中执行的是select * from dual) )
  • 11. fillPOoL的场景有一个fillerThread专门负责作连接池的fillPool(fillToMin)。 在以下场景执行fillPool: prefill设置为true。 prefill为false,第一次getconnetion的时候。 在IdleRemoveTimeout后,紧接着执行fillToMin。 在valitionconnection后,紧接着执行fillToMin。
  • 12. 连接池的关闭
  • 13. 连接池的关闭 shutdown是一个很快的操作 设置shutdown=true 从IdleRemover和ConnectionValidator中注销连接池。 销毁空闲的连接( flush完成) 使用中的连接设置为DESTROY状态,returnConnection时清理。(flush完成)
  • 14. 获取连接创建第一个连接时fillPool
  • 15. 获取连接说明blocking-timeout-millis 是一个获取信号量的超时时间,如果不能够获取到信号量(连接),则jboss会抛出异常“No ManagedConnections available within configured blocking timeout”。 信号量一共有MAX值个,只要当前正在使用的连接数没有到达MAX值,这个信号量一定能够被获取到。 业务在使用连接的过程中,会一直占有这个信号量,在returnConnection或者发生异常时释放信号量。
  • 16. 返还连接在连接return时,有可能已经是destory的状态,这时,直接进行remove即可。  释放连接需要释放信号量。
  • 17. 异常连接销毁默认情况下,JBOSS不会对无效的连接进行销毁。 对异常列表中的连接进行销毁需要配置 org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter TDDL中存在DB错误的异常列表,这里的异常列表有什么作用呢? 用于数据源动态管理。 用于实现某些特定的需求(如CIF读写分离,分库分表)。
  • 18. ORACLE异常列表
  • 19. MYSQL异常列表
  • 20. 连接池的默认参数 public static class PoolParams { public int minSize = 0; public int maxSize = 10; public int blockingTimeout = 30000; //milliseconds public long idleTimeout = 1000 * 60 * 30; //milliseconds, 30 minutes. public boolean backgroundValidation; //set to false by default public long backgroundInterval = 1000 * 60 * 10; //milliseconds, 10 minutes; public boolean prefill; public boolean useFastFail; }
  • 21. 连接池的统计信息//获取可用的连接数,判断可用的信号量即可 public long getAvailableConnections() { return permits.permits(); } //获取最大可用的连接数 public int getMaxConnectionsInUseCount() { return maxUsedConnections; } //获取已经被使用的连接数,checkedout是一个hashset. //所有被使用的连接都会首先checkout到这个hashset中,如果只需要获取hashset的大小即可。 public int getConnectionInUseCount() { return checkedOut.size(); }
  • 22. 调优篇-提纲调优篇连接风暴设置连接数的MIN值设置连接数的MAX值调整blocking-timeout-millisPreparedStatementCache的作用PreparedStatementCache与JVM内存交易系统调整案例分享
  • 23. 连接风暴-创建一个连接创建连接方式距离(KM)平均每个连接的创建时间(ms)OCI1584.998THIN(MTS)1519.468THIN(DEDICATED)1520.094MYSQL1519.25THIN(DEDICATED)本地7.248OCI本地46.35MYSQL本地6.964网络15公里,每次创建500个连接进行测试:
  • 24. 连接风暴-应用连接数在项目发布的过程中,我们需要重启应用,当应用启动的时候,经常会碰到各应用服务器的连接数异常飙升。 10点聚划算,数据库连接数飙升。应用有时候可能报“No ManagedConnections available within configured blocking timeout”
  • 25. 连接风暴的危害在多个应用系统同时启动时,系统大量占用数据库连接资源,可能导致数据库连接数耗尽。 数据库创建连接的能力是有限的,并且是非常耗时和消耗CPU等资源的,突然大量请求落到数据库上,极端情况下可能导致数据库异常crash。 对于应用系统来说,连接创建的时候,所有的请求会被阻塞,可能导致瞬间业务请求失败(报错),甚至应用的crash。
  • 26. Why连接风暴?获取连接流程图:第一次获取连接,执行fillpool
  • 27. 连接风暴原理连接数MIN=9,80毫秒内共10个并发请求。每个请求占用连接5ms。需要多少个连接?
  • 28. 连接风暴解决方式一般来说,连接风暴在非常繁忙的核心系统上面会存在比较大的影响,解决方式有如下几种: 设置jboss连接池参数prefill=true。(JBOSS 4.0.5版本以上支持) 在启动完成后,先执行一个SQL(如oracle可以执行:select * from dual),将连接数填充到min值。 如果有必要,选择在业务低峰时重启系统。 连接风暴在应用启动时,对应用的冲击很大。
  • 29. 设置连接数MIN值MIN值设置过小会有连接风暴,但也不宜设置太大。 在销毁空闲的连接(IdleRemover)后,如果连接数小于MIN值,会重新执行一个prefill的操作,重新将连接池中的连接数填充到min值。 如果min设置过大,JBOSS会将连接不断的进行销毁->创建->销毁->创建…(idle线程对空闲连接销毁,销毁后小于min值,然后马上又创建,新创建的连接处于空闲状态,于是又被idle线程销毁…)
  • 30. 设置连接数MAX值MAX值设置过小会对业务造成影响,一般设置要偏大点,但也不宜设置太大。 MAX值的设置,应该尽量满足业务的需要,但不宜设置过大,可以在异常情况下保护应用系统,保护我们的数据库。 连接数MAX值如果不限制,在以某些情况下会异常增长,影响应用稳定性,消耗数据库资源。如:DAO响应变慢(数据库存储波动,SQL执行计划问题,网络瞬断,账务EQ等) 一次故障,预发布环境单台机器连接数达到600个以上,导致连接数不够用。
  • 31. blocking-timeout将blocking-timeout-millis参数设置的尽量小一点 这个参数是应用getconnection时的超时时间,只在连接数达到MAX值时才会起作用,因为连接数没到达MAX值,这个获取连接是一个很快的操作,内部仅仅是执行一个获取信号量的操作。 防止因为数据库异常而导致应用线程池的堵塞 业务繁忙的系统,作水平拆分,读写分离的应用。
  • 32. ORACLE中的SQL缓存不解析:PGA已有打开的游标软软解析:PGA SQL有语句缓存软解析:Share pool(全局共享)有SQL缓存硬解析:没有缓存PGA: Process Global Area,一个进程的专用的内存区
  • 33. 应用如何执行SQL?createStatement: String sql = "select * from table_name where id = "; Statement stmt = conn.createStatement(); rset = stmt.executeQuery(sql+"1"); PreparedStatement: String v_id = 'xxxxx'; String v_sql = 'select name from table_a where id = ? '; //创建con.prepareStatement,并执行SQL预编译。 stmt = con.prepareStatement(v_sql); stmt.setString(1, v_id ); //为绑定变量赋值 stmt.executeQuery();
  • 34. 如何选择?createStatement()方法: 创建一个Statement对象,用于发送SQL语句到数据库。没有使用绑定变量的SQL语句一般使用Statement来执行。如果一个相同的SQL语句被执行多次,则使用PreparedStatement是一个更好的方式。 prepareStatement(String sql)方法: 创建一个PreparedStatement对象,用于发送使用绑定变量的SQL语句到数据库中。 SQL能够被预编译,并且存储到一个PreparedStatement对象中。这个对象,可以在多次执行这个SQL语句的块景中被高效的使用。(在数据库中会存在缓存) 如果驱动程序支持绑定变量,方法prepareStatement将会发送一个SQL语句到数据库,以执行预编译(即数据库中的解析)。也有一些驱动不支持预编译,在这种情况下,在PreparedStatement执行之后,语句才会被发送到数据库,这对于用户没有直接的作用。
  • 35. PreparedStatementCachePreparedStatementCache使用了一个本地缓存的LRU链表来保存prepareStatement对象。在PreparedStatementCache中的SQL,数据库端肯定有open cursor,那样我们就可以绕过解析(不解析)。 不解析(提高PreparedStatementCache 命中率)的好处: 节省一次网络往返。 解析很耗数据库CPU。 提升SQL响应时间,提高应用连接利用率。PreparedStatementCache的设置 JBOSS的配置文件中有个参数,当连接被创建的时候就会初始化PSCACHE的大小: 50
  • 36. MYSQL中的PSCACHE在MYSQL数据库中,因为没有绑定变量这个概念,MYSQL本身在执行所有的SQL之前,都需要进行解析,因此在MYSQL中这个值意义不象ORACLE那么大。
  • 37. PSCACHE性能测试数据库连接方式PSCACHE网络距离每次时间(ms)ORACLEoci支持15KM1.5484ORACLEoci不支持15KM2.0015ORACLEthin支持15KM1.5937ORACLEthin不支持15KM2.9093ORACLEoci支持本地0.1625ORACLEoci不支持本地0.6631ORACLEthin支持本地0.2695ORACLEthin不支持本地0.6555MYSQLjdbc支持15KM1.5124MYSQLjdbc不支持15KM1.5344MYSQLjdbc支持本地0.3195MYSQLjdbc不支持本地0.3792本机到机房的距离约为15KM: 15KM/(200000KM/s)=0.075ms    实际光速为300,000,000米/秒,因为光纤中的传播,有些损耗,所以传播速度计算为: 200,000,000米/秒 0.075ms*2=0.15ms           *2表示网络往返1次。 交换机延时:0.3ms(往返) 所以网络的交互时间在:0.3+0.15=0.45ms左右,即prepareStatement一次需要额外的0.45ms左右。
  • 38. PSCACHE的设置建议如果jvm heap内存足够的话,对于DAO性能响应很高的系统,可以牺牲一部分内存来换取性能。 这个值可以设置的尽量大一点,覆盖到应用所有的SQL版本。 对于INLIST SQL的提升,可以固定IN 的个数,参考,inlist查询优化http://www.dbafree.net/?p=546
  • 39. ORACLE连接池和JVM内存JVM内存占用计算: Connection中内存占用最大的是PreparedStatement,其中除了metadata之外,占用内存最多的就是CURSOR相关的内存区 JVM内存占用大小=(连接池1中的连接数*PSCache大小*平均每个PS的内存占用)+(连接池2中的连接数*PSCache大小*平均每个PS的内存占用)+(连接池3中的连接数*PSCache大小*每个PS的内存占用)+…… 假设一个应用有3个连接池,每个连接池有10个连接,每个PreparedStatement平均大小为200K。 当PSCache为30时:内存大小=3*10*200K*30=175.78MB 当PSCache为100时:内存大小=3*10*200K*100=585.95MB DML SQL由于不需要保存查询结果集,占用的PS大小可以忽略,一般在10KB左右。
  • 40. MYSQL连接池和JVM内存MYSQL的连接池占用内存很小,基本可以忽略,主要原因是preparestament基本上不占用内存。 MYSQL不支持客户端游标,但是客户端API通过把结果取到内存中,可以模拟游标操作。 不什么不支持客户端游标,这个是由MYSQL 客户端/服务器协议决定 的。MYSQL的这个协议是半双工的,即MYSQL只能在给定的时间,发送或接受改写,但不能同时发送和接收。(在接收完之后,才能释放锁等资源)。 这种协议使MYSQL在正常的情况下,查询的效率更高,对于大结果集的查询,MYSQL是客户端的内存占会大大的增加。这也是为什么preparestamentcache中,MYSQL基本不占用内存的原因
  • 41. 决定JVM内存的因素影响JVM内存的因素: 连接池个数:这个和应用架构有关系,不容易调整。 连接池中的连接数:由DAO处理时间及业务量决定。 PSCache大小:这个参数可以由我们来控制,和PS的大小关系很大,需要合理设置这个参数。 PS大小:由具体访问的SQL语句和fetchsize决定 。 JVM内存空间的计算最关键的问题变成了如何计算PreparedStatement的大小。 影响PreparedStatement大小的,只有fetchsize和SQL语句本身。 如何节约JVM内存?
  • 42. PS大小的计算Test10000表结构: col_a varchar2(4000) , col_b varchar2(4000), col_c varchar2(2000) SQL: Select * from test10000 where col_a=:1fetchsize设置为10(jdbc默认值),占用空间为: select字长总长度(字节)*fetchsize*2(字符集)连接方式理论计算结果集char数据真实大小OCI方式10000字节*10CHAR[100030]200KBTHIN方式10000字节*10CHAR[100030]200KB
  • 43. PS大小与select字段的关系字段长度PS大小 (字节)PS大小/字段长度141511495269.376105.6652799141511495269.376105.66527994412479232108.62012694412479232108.62012694412479232108.62012693736404172.8108.18329763000319488106.4962851319488112.06173273000317440105.81333332391259072108.35299042282246784108.14373361576178176113.05583761576178176113.055837672584992117.230344843852224119.232876740150688126.40399FETCHSIZE与PS的大小有直接的关系
  • 44. FETCHSIZEFETCHSIZE,从数据库的角度来说,就是每次从数据库中取多少条记录,即批次大小。假设有100条记录: Fetchsize=100,取1次,每次取100条,网络交互100次。 Fetchsize=10,取10次,每次取10条,网络交互10次。 Fetchsize=1,取100次,每次取1条,网络交互1次。 Fetchsize对客户端内存的影响: 客户端需要fetchsize条记录的内存大小来保存查询的结果集。每个记录为1KB,fetchsize为10,则客户端需要1KB*10=10KB的内存大小。 Fetchsize对网络的影响: 由于数据需要多次获取,会增加网络的交互次数。
  • 45. FETCHSIZE对性能的影响数据库连接方式PSCACHEfetchsize字段长度网络距离总记录数返回记录执行时间 (ms)ORACLEoci支持110015KM300300226.9533ORACLEoci支持510015KM30030086.44667ORACLEoci支持1010015KM30030043.74667ORACLEoci支持5010015KM30030010ORACLEoci支持10010015KM3003005.2ORACLEoci支持110015KM300108.44ORACLEoci支持510015KM300102.9ORACLEoci支持1010015KM300101.56ORACLEoci支持5010015KM300101.56ORACLEoci支持1100本地30030012.773ORACLEoci支持5100本地3003005.32ORACLEoci支持10100本地3003002.9ORACLEoci支持50100本地3003000.87ORACLEoci支持100100本地3003000.65
  • 46. 设置fetchsize的重要性FETCHSIZE直接决定了PS的大小,所以JDBC,IBATIS, hibernate框架,连接池都可以调整这个参数,可见这个值对内存的影响有多大。TRADE系统上占用内存最大的SQL select * from (select * from trade_voucher_04 where trade_no =:1 and refund_id = :2 and UPLOAD_FLAG = 7 order by id desc ) where rownum<2Fetchsize字段总长真实内存占用保存结果集的数组大小50141511.426MBChar[705200] :1.41MB(14151*50)1014151285KBChar[141040] :256KB(14151*10)11415140KB左右Char[14104] :25.6KB(14151*1)如果支持在SQL级别设置FETCHSIZE为1:调整这一个SQL,单台应用可节省内存:5*8*1.38M=55.2MB (5为数据源个数8为,每个数据源中的连接数。) 设置为10,可节约内存46.4MB
  • 47. PSCACHE收益网络收益 每个SQL提高响应在0.4-0.6ms左右 应用收益内存管理的负担减轻,缓解GC压力DAO响应时间变快,连接利用率变高综合收益等待事件“SQL *Net more data from client” 解析及CPU下降连接数下降数据库收益SQL命中PSCACHE,一般单个SQL可提高响应0.5-0.9ms。对于一笔交易的创建,可以提高响应多少?
  • 48. 交易系统PSCACHE调整分析TRADE 系统,99%上以都是单条SQL的查询,每个连接池SQL版本数在120个左右:PAY1:3000次/STotalper Secondexecute count10,243,8825,692.22parse count (hard)280.02session cursor cache hits2,555,6251,420.08parse count (total)2,805,4841,558.92parse count (failures)190.01pscache命中率47.660% 保证32位JVM内存足够,调整参数: Fetchsize :50->5(大部分系统需要下调) pscache:50->150。(如果SQL过多,可以适当上调)
  • 49. 交易系统PSCACHE调整后PAY1Totalper Secondexecute count19,453,57810,807.00session cursor cache hits899,470499.68parse count (total)970,058538.89pscache命中率90.38% DAL响应时间:调整前约为1.88ms,调整后为1.08ms,提升幅度 42.56% JVM内存下降:    正常业务压力,下降150MB左右。 DB连接数减少近5000个。(1000个/DB) DB CPU利用率降低10%以上。
  • 50. 课程总结Fetchsize: 依结果集而定,大部分系统需要下调。可以通过设置一个连接层面的参数。 < connection-property name="defaultRowPrefetch">50 PSCACHE: (如果SQL过多,可以适当上调,但是需要注意对JVM内存的影响)。 Min值, Max值 根据业务需要合理设置,可以适当偏大一点,预防连接风暴。 合理设置,确保满足业务的前提下,可以偏大一点。考虑数据库连接数。 Blocking-timeout-mills: 设置为500ms即可。 连接池问题咨询相应的开发DBA。
  • 51. 参考文章JBOSS连接池1-PreparedStatementCache参数的作用及原理: http://www.dbafree.net/?p=287 JBOSS连接池2-jboss连接池的启动及prefill参数配置: http://www.dbafree.net/?p=300 JBOSS连接池3-JBOSS连接池的初始化及关闭: http://www.dbafree.net/?p=342 JBOSS连接池4-从连接池中获取连接及返还连接: http://www.dbafree.net/?p=378 JBOSS连接池调优1-大规模应用集群如何防止连接风暴:http://www.dbafree.net/?p=438 JBOSS连接池调优2-合理的设置PreparedStatementCache:http://www.dbafree.net/?p=458 JBOSS连接池调优3-提高PSCACHE的命中率-inlist查询的优化: http://www.dbafree.net/?p=546 JBOSS连接池调优4-合理设置连接数的min值和max值:http://www.dbafree.net/?p=572 JBOSS连接池调优5-合理的设置fetchsiz:http://www.dbafree.net/?p=597 JBOSS连接池博客文章合集:http://www.dbafree.net/?p=655 JBOSS连接池附录,获取连接池中相关的统计信息:http://www.dbafree.net/?p=411 oracle 的sql解析过程: http://www.dbafree.net/?p=8 一个生产库的JBOSS连接池调整优化及分析: http://www.dbafree.net/?p=150
  • 52. (本页无文本内容)