使用 druid 连接池,前几次请求总是特别慢,经过 debug 分析:druid 在应用启动时建立的连接,在首次执行请求时,都会进行创建 statement 操作,而这一步耗时特别长。后面再执行请求时,就没有创建 statement 的操作,请求处理的也特别快。
请大佬帮忙分析一下,这个第一次请求耗时是否可以优化?现在应用启动后,前几次请求都特别长,体验非常不好。
应用启动时,druid 创建了连接,这一步符合预期:
2021-07-23 15:32:11.599 WARN 26288 --- [ main] com.alibaba.druid.pool.DruidDataSource [1243] : removeAbandoned is true, not use in production.
2021-07-23 15:32:11.856 DEBUG 26288 --- [ main] druid.sql.Connection [129] : {conn-10001,procId-55682} connected
2021-07-23 15:32:11.957 DEBUG 26288 --- [ main] druid.sql.Connection [129] : {conn-10002,procId-55684} connected
2021-07-23 15:32:12.062 DEBUG 26288 --- [ main] druid.sql.Connection [129] : {conn-10003,procId-55685} connected
首次请求时,创建 statment 用了将近 200ms,见下面 {conn-10030, pstmt-20000} created
日志,导致首次请求特别慢。
2021-07-23 15:32:28.498 DEBUG 26288 --- [l-thread-1] druid.sql.Connection [129] : {conn-10030} pool-connect
2021-07-23 15:32:28.501 DEBUG 26288 --- [l-thread-1] druid.sql.Connection [129] : {conn-10030} setAutoCommit false
2021-07-23 15:32:28.670 DEBUG 26288 --- [l-thread-1] druid.sql.Statement [134] : {conn-10030, pstmt-20000} created. insert into table_name
2021-07-23 15:32:28.687 DEBUG 26288 --- [l-thread-1] druid.sql.Statement [134] : {conn-10030, pstmt-20000} Parameters : [..]
2021-07-23 15:32:28.687 DEBUG 26288 --- [l-thread-1] druid.sql.Statement [134] : {conn-10030, pstmt-20000} Types : [VARCHAR, INTEGER]
2021-07-23 15:32:28.700 DEBUG 26288 --- [l-thread-1] druid.sql.Statement [134] : {conn-10030, pstmt-20000} executed. 14.004616 millis. insert into table_name
druid 版本:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
druid 配置:
spring:
datasource:
dynamic:
primary: master
strict: false
datasource:
master:
url: jdbc:mysql://ip:port/database?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useAffectedRows=true&nullCatalogMeansCurrent=true
username: xxx
password: xxx
driver-class-name: com.mysql.jdbc.Driver
druid:
default-auto-commit: true
initial-size: 30
min-idle: 30
max-active: 30
test-while-idle: true
keep-alive: true
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
max-evictable-idle-time-millis: 900000
connection-init-sqls: SELECT now()
validation-query: SELECT now()
connection-error-retry-attempts: 3
remove-abandoned: true
transaction-query-timeout: 200
max-wait: 100
filters: slf4j,wall,stat
filter:
slf4j:
enabled: true
statement-log-enabled: true
stat:
enabled: true
web-stat-filter:
enabled: true
url-pattern: "/*"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
stat-view-servlet:
url-pattern: "/druid/*"
reset-enable: false
login-username: admin
login-password: admin
enabled: true
slave:
(配置略)
mysql 版本: MySQL 5.7.15
1条答案
按热度按时间92dk7w1h1#
我也遇到类似问题, 在springboot项目中使用mybatis+druid, 项目启动后第一次访问慢, 体现在18,19行耗时有450ms左右, 已打开debug日志,第一次之后请求访问就比较快了,只有30ms左右。
版本:springboot 2.4.1,mybatis-spring-boot-starter 2.1.4, druid 1.2.6,druid-spring-boot-starter 1.2.6
配置如下:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/abc?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&autoReconnect=true&useSSL=false&verifyServerCertificate=false
username: root
password: 123
使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
配置初始化大小、最小、最大
initial-size: 10
minIdle: 10
max-active: 20
配置获取连接等待超时的时间(单位:毫秒)
max-wait: 60000
配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 2000
配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 600000
max-evictable-idle-time-millis: 900000
用来测试连接是否可用的SQL语句,默认值每种数据库都不相同,这是mysql
validationQuery: select 1
应用向连接池申请连接,并且testOnBorrow为false时,连接池将会判断连接是否处于空闲状态,如果是,则验证这条连接是否可用
testWhileIdle: true
如果为true,默认是false,应用向连接池申请连接时,连接池会判断这条连接是否是可用的
testOnBorrow: false
如果为true(默认false),当应用使用完连接,连接池回收连接的时候会判断该连接是否还可用
testOnReturn: false
是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle
poolPreparedStatements: true
要启用PSCache,必须配置大于0,当大于0时, poolPreparedStatements自动触发修改为true,
在Druid中,不会存在Oracle下PSCache占用内存过多的问题,
可以把这个数值配置大一些,比如说100
maxOpenPreparedStatements: 20
连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作
keepAlive: true
Spring 监控,利用aop 对指定接口的执行时间,jdbc数进行记录
aop-patterns: "com.123.boot.mapper.*"
########### 启用内置过滤器(第一个 stat必须,否则监控不到SQL)##########
filters: stat,wall,log4j2
自己配置监控统计拦截的filter
filter:
开启druiddatasource的状态监控
stat:
enabled: true
db-type: mysql
开启慢sql监控,超过2s 就认为是慢sql,记录到日志中
log-slow-sql: true
slow-sql-millis: 2000
日志监控,使用slf4j 进行日志输出
slf4j:
enabled: true
statement-log-error-enabled: true
statement-create-after-log-enabled: false
statement-close-after-log-enabled: false
result-set-open-after-log-enabled: false
result-set-close-after-log-enabled: false
########## 配置WebStatFilter,用于采集web关联监控的数据 ##########
web-stat-filter:
enabled: true # 启动 StatFilter
url-pattern: /* # 过滤所有url
exclusions: ".js,.gif,.jpg,.png,.css,.ico,/druid/" # 排除一些不必要的url
session-stat-enable: true # 开启session统计功能
session-stat-max-count: 1000 # session的最大个数,默认100
########## 配置StatViewServlet(监控页面),用于展示Druid的统计信息 ##########
stat-view-servlet:
enabled: true # 启用StatViewServlet
url-pattern: /druid/ # 访问内置监控页面的路径,内置监控页面的首页是/druid/index.html
reset-enable: false # 不允许清空统计数据,重新计算
login-username: root # 配置监控页面访问密码
login-password: 123
allow: 127.0.0.1 # 允许访问的地址,如果allow没有配置或者为空,则允许所有访问
deny: