性能优化之数据库和数据源连接池配置
什么?!数据库连接拿不到?
今天在公司对系统进⾏压测,由于我的sit和dev和uat环境都是⽤的⽤的是⼀个数据库服务器,我让⽤户在的sit进⾏压测,分别是单线程测
试,并发测试,但是⽤户⼀开始测,我的三个环境就都挂掉了。 ⽤户⼀下⼦全部上门来,我就跑去看容器是不是cpu内存或者io被耗尽
了,结果⼀看40%!还差的远呢!那就究竟是什么导致我的环境都访问不了呢?我打开Navicat去看看数据库,结果发现连接数据库居然耗
时特别久,我就明⽩了原来是数据库连接拿不到。那么应该的因素有哪些呢?⼀个是数据库的最⼤连接数;⼀个是配置⽂件中数据源连接池
的配置。
1. 查看当前数据库mysql最⼤连接数量和最⼤允许连接数量
driveerror是什么意思
通常,mysql的最⼤连接数默认是100, 最⼤可以达到16384
show variables like 'max_connections';(查可以看当前的最⼤连接数)
set global max_connections=1000;(设置最⼤连接数为1000,可以再次查看是否设置成功,这个只是暂时的,如果mysql服务重启,就会失效,真正要改还是要在my.
在修改最⼤连接数的时候会有这样⼀个疑问—这个值是不是越⼤越好,或者设置为多⼤才合适?这个参数的⼤⼩要综合很多因素来考虑,⽐
如使⽤的平台所⽀持的线程库数量(windows只能⽀持到2048)、服务器的配置(特别是内存⼤⼩)、每个连接占⽤资源(内存和负载)
的多少、系统需要的响应时间等。可以在global或session范围内修改这个参数。连接数的增加会带来很多连锁反应,需要在实际中避免由
此引发的负⾯影响。
⾸先看⼀下MySQL的状态:
show status;
Open tables:560,即当前数据库打开表的数量是560个,注意这个560并不是实际的560个表,因为MySQL是多线程的系统,⼏个不同的
并发连接可能打开同⼀个表,这就需要为不同的连接session分配独⽴的内存空间来存储这些信息以避免冲突。因此连接数的增加会导致
MySQL需要的⽂件描述符数⽬的增加。另外对于MyISAM表,还会建⽴⼀个共享的索引⽂件描述符。
在MySQL数据库层⾯,有⼏个系统参数决定了可同时打开的表的数量和要使⽤的⽂件描述符,那就是table_open_cache、
max_tmp_tables和open_files_limit
table_open_cache:2000,这就是说所有的MySQL线程⼀共能同时打开2000个表,我们可以搜集系统的打开表的数量的历史记录和这个参数来对⽐,决定是否要增加这个参数的⼤⼩。查看当前的打开表的数⽬(Open tables)可⽤上边提到过的status命令,另外可以直接查询这个系统变量的值:
Open_tables就是当前打开表的数⽬,通过flush tables命令可以关闭当前打开的表。 这个值如果过⼤,并且如果没有经常的执⾏flush tables命令,可以考虑增加table_open_cache参数的⼤⼩。
接下来看max_tmp_tables:
show variables like 'max_tmp%';
max_tmp_tables:32即单个客户端连接能打开的临时表数⽬。
查看当前已打开的临时表的信息:
show global status like '%tmp%table%';
根据这两个值可以判断临时表的创建位置,⼀般选取BLOB和TEXT列、Group by 和 Distinct语句的数据量超过512 bytes,或者union的时候select某列的数据超过512 bytes的时候,就直接在磁盘上创建临时表了,另外内存中的临时表变⼤的时候,也可能被MySQL⾃动转移到磁盘上(由tmp_table_size和max_heap_table_size参数决定)。
增加table_open_cache或max_tmp_tables 参数的⼤⼩后,从操作系统的⾓度看,mysqld进程需要使⽤的⽂件描述符的个数就要相应的增加,这个是由open_files_limit参数控制的。
show variables like 'open_files%';
但是这个参数是OS限制的,所以我们设定的值并不⼀定总是⽣效。如果OS限制MySQL不能修改这个值,那么置为0。如果是专⽤的MySQL服务器上,这个值⼀般要设置的尽量⼤,就是设为没有报Too many open files错误的最⼤值,这样就能⼀劳永逸了。当操作系统⽆法分配⾜够的⽂件描述符的时候,mysqld进程会在错误⽇志⾥记录警告信息。
redis命令大全介绍相应的,有两个状态变量记录了当前和历史的⽂件打开信息:
MySQL为每个连接分配线程来处理,可以通过threads_connected参数查看当前分配的线程数量:
show status like '%thread%';
⽐较threads_connected参数和前⾯提到的max_connections参数,也可以作为⽬前的系统负载的参照,决定是否需要修改连接数。
查看每个线程的详细信息:mysql>show processlist;对影响系统运⾏的线程:kill connection|query threadid的命令杀死。
动环监控系统架构图
Druid数据源配置
Java程序很⼤⼀部分要操作数据库,操作数据库需要不断建⽴连接释放连接,为了⾼性能操作数据库,数据库连接池横空出世。阿⾥开源在github 上⾯的数据库连接池是其中⼗分优秀的,国内⼤量的公式都在使⽤。
这⾥主要讲⾼并发下的数据源连接池配置,druid的其它优秀的公共包括监控、安全机制等都不作拓展。
配置参数:
和其它连接池⼀样DRUID的DataSource类为:com.alibaba.druid.pool.DruidDataSource,基本配置参数如下:
配置缺省值说明
name 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。
如果没有配置,将会⽣成⼀个名字,格式是:"DataSource-" + System.identityHashCode(this)
jdbcUrl 连接数据库的url,不同数据库不⼀样。例如:
mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username连接数据库的⽤户名
password 连接数据库的密码。如果你不希望密码直接写在配置⽂件中,可以使⽤ConfigFilter。详细看这⾥:github/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter
driverClassName 根据url⾃
动识别
这⼀项可配可不配,如果不配置druid会根据url⾃动识别dbType,然后选择相应的driverClassName(建
议配置下)
initialSize0初始化时建⽴物理连接的个数。初始化发⽣在显⽰调⽤init⽅法,或者第⼀次getConnection
时maxActive8最⼤连接池数量(不是越⼤越好)
maxIdle8已经不再使⽤,配置了也没效果js的运行原理
minIdle最⼩连接池数量
maxWait 获取连接时最⼤等待时间,单位毫秒。配置了maxWait之后,缺省启⽤公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使⽤⾮公平锁。
poolPreparedStatements false 是否缓存preparedStatement,也就是PSCache。PSCache对⽀持游标的数据库性能提升巨⼤,⽐如说oracle。在mysql下建议关闭。
maxOpenPreparedStatements-1要启⽤PSCache,必须配置⼤于0,当⼤于0时,poolPreparedStatements⾃动触发修改为true。在Druid中,不会存在Oracle下PSCache占⽤内存过多的问题,可以把这个数值配置⼤⼀些,⽐如说100
validationQuery ⽤来检测连接是否有效的sql,要求是⼀个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作⽤。
testOnBorrow true申请连接时执⾏validationQuery检测连接是否有效,做了这个配置会降低性能。testOnReturn false归还连接时执⾏validationQuery检测连接是否有效,做了这个配置会降低性能
testWhileIdle false 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间⼤于timeBetweenEvictionRunsMillis,执⾏validationQuery检测连接是否有效。
timeBetweenEvictionRunsMillis 有两个含义:
1) Destroy线程会检测连接的间隔时间2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明
numTestsPerEvictionRun不再使⽤,⼀个DruidDataSource只⽀持⼀个EvictionRun minEvictableIdleTimeMillis
connectionInitSqls物理连接初始化的时候执⾏的sql
mysql无法连接到服务器exceptionSorter 根据
dbType
⾃动识别
当数据库抛出⼀些不可恢复的异常时,抛弃连接
filters 属性类型是字符串,通过别名的⽅式配置扩展插件,常⽤的插件有: 监控统计⽤的filter:stat⽇
志⽤的filter:log4j防御sql注⼊的filter:wall
proxyFilters 类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并⾮替换关系
⾼并发的配置
数据库连接池的设置分析——测试数据
连接池设置数量越⼩、总耗时越少?
联想到为啥Nginx内部仅仅使⽤了4个线程,其性能就⼤⼤超越了100个进程的Apache HTTPD呢?好像更加坚定了这⼀观点。
这取决于你的资源:要知道,即使是单核 CPU 的计算机也能“同时”运⾏着数百个线程。但我们其实都知道,这只不过是操作系统快速切换时间⽚,跟我们玩的⼀个⼩把戏罢了。⼀核 CPU同⼀时刻只能执
⾏⼀个线程,然后操作系统切换上下⽂,CPU 核⼼快速调度,执⾏另⼀个线程的代码,不停反复,给我们造成了所有进程同时运⾏假象。其实,在⼀核 CPU 的机器上,顺序执⾏A和B永远⽐通过时间分⽚切
换“同时”执⾏A和B要快,其中原因,学过操作系统这门课程的童鞋应该很清楚。⼀旦线程的数量超过了 CPU 核⼼的数量,再增加线程数系统就只会更慢,⽽不是更快,因为这⾥涉及到上下⽂切换耗费的额外的性能。
时间⽚的概念是什么?
时间⽚即CPU分配给各个程序的时间,每个线程被分配⼀个时间段, 称作它的时间⽚,即该进程允许运⾏的时间,使各个程序从表⾯上看是同时进⾏的。
如果在时间⽚结束时进程还在运⾏,则CPU将被剥夺并分配给另⼀个进程。如果进程在时间⽚结束前阻塞或结束,则CPU当即进⾏切换。⽽不会造成CPU资源浪费。
在宏观上:我们可以同时打开多个应⽤程序,每个程序并⾏不悖,同时运⾏。
但在微观上:由于只有⼀个CPU,⼀次只能处理程序运⾏的⼀部分,如何处理公平,⼀种⽅法就是引⼊时间⽚,每个程序轮流执⾏。
结论:当线程数⼤于CPU的核⼼数,需要通过算法及时间分⽚切换该哪个线程获得CPU的使⽤权,这个是需要耗时的。因为这⾥涉及到上下⽂切换耗费的额外的性能。array push返回值
如果计算机是4核,机器值运⾏四个线程,处理速度相当快。但这只是理想状态。
限制因素
实际上,限制线程发挥的,不⽌有CPU,还有磁盘IO和⽹络IO。
下⾯分别来看CPU 磁盘IO ⽹络IO:
只考虑CPU
结论1:如果只考虑CPU,不考虑磁盘I/O和⽹络I/O,在⼀个8核的服务器上,数据库连接数/线程数设置为8能够提供最优的性能,如果再增加连接数,反⽽会因为上下⽂切换导致性能下降。(这是理想情况)
数据库连接数/线程数= CPU的核⼼数
耗时因素:寻址的耗时+旋转耗时;
当你的线程处理的是IO密集型业务时,便可以让 线程/连接数 设置的⽐CPU核⼼数⼤⼀些,这样就能够在同样的时间内,完成更多的⼯作,提升吞吐量。因为磁盘寻址的时候,CPU是空闲的,可以让CPU做点其他的。
问题:设置成多⼤合适呢?
取决于磁盘:SSD固态硬盘、普通机械硬盘
SSD固态硬盘,它不需要寻址,也不需要旋转碟⽚!是不是可以设置更⼤些?
结论正好相反! ⽆需寻址和没有旋回耗时的确意味着更少的阻塞,所以更少的线程( 更接近于CPU核⼼数)会发挥出更⾼的性能。只有当阻塞密集时,更多的线程数才能发挥出更好的性能。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。