GenericObjectPool对象池使用优化

背景

  • 某应用1.0性能测试

  • 服务强依赖于mysql, 许多接口都会请求mysql

  • 对mysql的请求用GenericObjectPool的连接池来进行管理, 设置如下:

    当前内容已被隐藏,您需要登录才能查看

问题

  • 用100并发打压服务,发现拿到连接并在干活的线程数只有10+, 而其余80+的线程wait在borrowObject的逻辑, 相应的stack如下:

    当前内容已被隐藏,您需要登录才能查看

分析

  • 为什么maxActive设置为100, 还会有如此多的线程在makeObject?这是我们的setMaxActive没有生效, 还是GenericObjectPool有其他destroy对象的机制被我们忽略了?

  • 查看GenericObjectPool的java doc, 了解对象池关于对象创建和销毁相关的方式以及配置方式

  • 打压开始后, 动态debug, 发现pool对象有许多我们未进行配置的成员变量,对照doc逐一check各变量
    发现一个可怀疑点: numIdle, 其值一直在2-8之间波动, 且doc中如是描述:

    当前内容已被隐藏,您需要登录才能查看
  • 可知默认的maxIdle值为8,若未进行配置,当pool中idle的object超过默认值8时,多余的对象就会被destroy

  • 至此,问题基本定位到

验证

  • 增加对maxIdle的配置,即:

    当前内容已被隐藏,您需要登录才能查看
  • 重新打压, 发现吞吐增长近一倍,响应速度也显著加快,stack中无线程blocked在borrowObject或makeObject相关的逻辑

另一个重要的问题

  • 未设置maxWait, doc中对maxWait说明如下:

    当前内容已被隐藏,您需要登录才能查看
  • 可知若不进行设置,当被依赖的服务由于某些故障(如机器资源被某进程大量占用)而响应极慢时,会有大量线程blocked在borrowObject的逻辑,最终导致resin线程耗尽,服务卡死,用户请求被拒绝

  • 可参考之前的一次线上故障:某服务变慢导致依赖于它的另一web卡死,其原因为改web请求改服务时的连接池未对borrowObject设置timeout,导致大量线程blocked在borrowObject的逻辑

  • 因此需要对maxWait进行设置,且设置的时间不宜过大(高吞吐时仍有可能导致web卡死),也不宜过小(可能导致较多的请求失败),具体的配置可参考如下:

    当前内容已被隐藏,您需要登录才能查看
  • 具体的配置如下:

    当前内容已被隐藏,您需要登录才能查看

参考文档

 
所属分类:产品

 0条回应

我有话说:
    • 春建童鞋
    • 关注
      • 515773发布
      • 93评论
    ×
    订阅图标按钮