【JAVA】准生产连接池爆了,水下数据源参数该怎么挑(Druid)

107 阅读7分钟

背景

  • 外包-项目经理-客户-质量失控
  • 请求处理慢,狮山代码卡死连接吃满了,再多配点?CN扛不住了死了。
  • 发现公司B域项目配的一直挺随意的,就优化性能和配置调优2手抓了

参数

maxWait
  • 默认 -1 永久等待我滴龟龟
  • 一般建议配置:10000 快速失败
minIdle
  • 最小空闲连接数量,顺利运行暖机后的,保底的连接持有数量;
  • 但也不是真保底,如果大于容忍时间(就是你闲的太久了,也会杀到小于minIdle的连接量)
  • 一般建议配置:1 或 同maxActive
  • 因为做好暖机,后面就交给业务吧,如果业务都没有打进来,那该杀杀别给数据库上强度,尤其现在国产化,不利于稳定的事不要做。
  • 当然你也得考虑实际业务场景,如果是一波一波大流量,那就要配置的大一些长期持有(或者时间节点前主动暖机),具体多大需要结合数据库CN能力+业务模型+节点数量+期望请求时间综合考虑了。
  • 说人话,如果有能力压测就看压测结果,达到峰值性能实时的active量,是多少我们就初始化&&minIdle多少
    • 这个话题就散了,因为“峰值性能”还意味着要符合设计峰值性能,从设计到验收的过程鸡生蛋蛋生鸡
      • 从设计开始应该就估算过多少实例每个要承载多少请求,正向的也一起估过主机配置/数据库资源量,都是要钱的,数据库资源就包括承载多少链接,分给每个实例可以多少即使有冗余那也是有数的;主机配置包括核数,可估算并发量/QPS
      • 所以实际连接数设置分2步,第一步纯落地建设的估算/经验数据,获得大致数据;第二步是上线前的压测调整,符合预期最好,达不到就要优化代码或调整配置
      • 估算还是必要的
      • 单说说不清楚,后面项目落地流程整体说吧
initialSize
  • 初始连接
  • 一般建议配置:咨询根据实际数据库CN节点抗压能力和你的应用数来
maxActive
  • 最大连接
  • 一般建议配置:咨询根据实际数据库CN节点抗压能力和你的应用数+业务模型来
    • Min(0.6* 数据库CN节点数量* 单CN最大支持连接/应用实例数,1.5 *应用实例核心数/DBIO时间占比)
    • 其中数字系数为经验冗余
  • 如何获得DBIO?
    • 1、抽查并分析典型接口:土法计算
    • 2、等压测:RT开始下降时,100% - 1 / QPS / (1000ms/RT ms) 即为
  • 比如:1C2G的实例,DBIO占20%,仅从应用实例需求来讲,只需要配5 * 1.5 = 8,配多了浪费

实际上 建议maxActive/minIdle/initialSize 三位一体,配置相同。min/maxEvictableIdleTimeMillis容忍空闲亦配置相同

降低复杂性,及时释放连接,按照业务特化指定时机主动暖机

minEvictableIdleTimeMillis
  • 最小超过__时间可考虑失效此连接
  • 超过这个时间,并且持有连接数大于minIdle,就会考虑杀掉连接;
  • 一般建议配置:默认 60 * 60 * 1000
  • 因为暖机后维持稳定运行,就不该存在杀连接的场景,max和min配一样,业务特化才是最好的,通用的不靠谱。
  • 一般根本做不到,分析什么时间并发分布,再分析个min和max。
  • 首先你可以做到提前暖机(在服务时间明确时)
  • 而且外面有云平台先抗压流量打到分散节点,这都不够零散请求导致的扩容耗时,那还是寄了吧。
maxEvictableIdleTimeMillis
  • 英文命名有歧义,实际是最大容忍空闲时间
  • 超过这个时间的空闲,就不管你够不够minIdle了,都鲨啦
  • 一般建议配置:同min 60 * 60 * 1000
  • 就和JVM Xmx Xms一样,伸缩个棒棒锤
phyTimeoutMillis
  • 理论上是最高优先级,连接存活超过这个时间一律杀
  • 实操中建议咨询数据库厂商他们的连接有效时间最长多久(不管活不活跃)
  • 一般建议配置:咨询厂商
validationQuery
  • 一般建议配置:select 1 / select 1 from dual;
  • 以数据库版本为准,一定要显式配置声明消除歧义
  • 看到这个我就想笑,总监摇人摇来个T4,赶鸭子集成个审批流进来,结果数据源源码报错都不会看(Atomic数据源),胖哥哥简单看个几十分钟就找到了是因为log.trace日志级别的日志: validate sql执行的异常被吞了。这数据源比较严格必须validate通过才行。
timeBetweenEvictionRunsMillis
  • 多久检测一次空闲时长
  • 一般建议配置: 默认60 * 1000 性能影响忽略不计
testWhileIdle
  • 对,数据源是提供了配置项,但不一定非得用上,食之无味弃之可惜
  • 如果你的业务场景长期稳定被调用,那根本走不到被扫描空闲时长达标(timeBetweenEvictionRunsMillis默认1分钟),然后触发test
  • 如果你的业务场景一波波,那你该考虑及时释放资源(连接),比如控制上面的min/maxEvictableIdleTime
  • 一般建议配置: 默认true
testOnBorrow
  • !!充满歧义的命名,borrow->借,实际根本不是借,而是take->取/占有连接池中已有连接。
  • 当我们的代码取需要use数据库连接时,先take一个连接出来,没有就建,take的时候要不要test下可用?
  • 一般建议配置:性能影响大 默认false
testOnReturn
  • borrow是take,这里就是用完了还时要不要也test?
  • 所以同理
  • 一般建议配置:性能影响大 默认false
poolPreparedStatements
  • 各类框架说到底还是要把仓储转基础的sql statement的,所以有这个参数配是否缓存ps
  • 搜索了下,有几个顾虑点:

大模型说:

image.png

事实上呢?

线程不安全是无稽之谈他是connection独享的: com.alibaba.druid.pool.DruidConnectionHolder#statementPool

oracle确实有特殊处理,但是是关闭oracle的一些隐式缓存防止意外,没看到游标在哪。

image.png

所以说,大模型仅供参考,一切以实际代码为准。大模型会毁了新程序员的脑子的。

  • 是否开启取决于你的应用sql量多少?容器内存给到多少?
  • 一般C域的话,微服务相对纯净职能明确,SQL不会很多,如果响应时间敏感是可以开启的。
  • 一般B域M域的话,即使工程老旧乱炖,但是内存给足,也是可以开启的,毕竟sql没那么多说到底,crud才是主旋律,内存主要就给crud用合理。
  • 一般建议配置: 不敢建议,我是开了
  • 实现原理:老生常谈八股文: 继承LinkedHashMap,重写removeEldest方法
maxPoolPreparedStatementPerConnectionSize
  • 如果开启了缓存ps,最大缓存几个?
  • 默认10个,注意是每个连接connection都持有10个容量的缓存。
  • 连接数量:书接开头最开头的maxActive和minIdle,上面建议直接配成一致的,避免伸缩带了不确定性,那么这里就可以
    • 1C2G实例给了8的maxActive,那么其实可以调到100!8 * 100 也不吃多少内存。
  • 一般建议配置:加大药量 100!
maxOpenPreparedStatements
  • 原则上是一个connection最大同时开启多少个ps,默认-1
  • 实际上源码未使用
  • 一般建议配置: 不配/-1
removeAbandoned、removeAbandonedTimeoutMillis
  • 字面意思是移除废弃连接和阈值时间
  • 实际呢?判定条件是

image.png (currrentNanos - pooledConnection.getConnectedTimeNano())/ (1000 * 1000) >= removeAbandonedTimeoutMillis

而这个getConnectedTimeNano来自获取连接时设置

image.png

  • 那现在已知判定条件,你还知道不会有人直接用连接,都是持久化框架,你认为持久化框架会即用即建吗?

    • 当然不会,这就是重复建设,每个轮子都做自己的缓存/算法/holder。实际更应定性为职责不清,池子就在当前大环境下就该做好池子(类似于线程池)的本分,Manage的部分交给更高级的框架。
    • 但没人能开天眼,不是错误是历史问题。
  • 一般建议配置:不开启,除非你直接用dataSource获得连接比较基础的应用。

监控配置
  • 一般建议配置: 不开启
  • 现在都打agent做链路分析了,你一个小数据源时代过去了,大杂烩<各司其职
  • 及时没有现成平台你搭个也好