poolboy是Erlang中运用非常广泛的进程池库,它有很多优点,使用简单,在很多项目中都能看到它的身影。不过,它也有一些坑,使用时候需要注意。(本文对poolboy的分析基于1.5.1版本)

worker创建不能失败

poolboy初始化的时候,或者当前进程池的worker数量超过默认值,都会新建worker。我们看一下新建worker的代码:

new_worker(Sup) ->
{ok, Pid} = supervisor:start_child(Sup, []),
true = link(Pid),
Pid.

可以看到,supervisor:start_child的时候是不能失败的,也就是说worker创建如果失败,会导致poolboy这个gen_server挂掉,导致整个进程池崩溃。

这会有什么影响呢,我们看一下用poolboy管理eredis的例子,参考其中的一个实现eredis_pool

创建worker失败,pool无法启动

eredis初始化代码,如果连接失败,eredis直接退出。如果用eredis_pool的话,当redis没有起来,或者某些其它原因导致eredis初始化失败(只要一次失败),会导致eredis_pool无法正常启动。

当然,如果redis无法正常工作,eredis_pool是不应该启动成功。但是如果进程池有100个worker,创建成功99个,第100个失败了,结果导致整个进程池退出,似乎有点太严格了。

所以有人对eredis提了个 issue,应该就是针对这个问题的。

创建worker失败,pool异常退出

具体可以看 create_pool的代码。

假如现在连接池配置有100个eredis client,当超过100个client时,poolboy会尝试启用overflow,新建eredis client。如果这时候因为某些原因,创建失败,结果也是一样,eredis_pool 异常退出。

观察网络连接,就会发现,这时候已有的redis client全部断链。当poolboy被重新拉起来的话,又会重新尝试建链。

根据上面分析可以看到,poolboy管理的worker有非常严格的规定,worker创建不能失败。如果失败,可能导致进程池无法正常启动,或者正常运行的进程池异常退出。

解决方法,加代理进程

在poolboy和进程之间加一个proxy process,proxy创建时不会去尝试建链,只做一些很简单的工作,确保进程初始化可以成功。在进行具体操作时,再去尝试建链。这样可以避免前面的问题,可以看 epgsql_pool或者 phoenix,或者我们自己fork的eredis_pool

proxy代理进程的问题

但是proxy有一个问题,那就是proxy进程里面的client不一定是正常的。看epgsql_pool和phoenix代码可以知道,proxy只保证自己创建的时候不会失败,至于它管理的client是不是正常的,只有在进行具体工作的时候,才可以知道。

这个大部分情况也没有什么问题,当新建worker,如果client连接有问题时,只会影响本次的poolboy调用,但是不会导致进程池崩溃。

当然可以在proxy进程里面加个定时器,定时去检查client的连接情况,如果失败,尝试重新建链。

但是深入代码时,会发现还是有一个坑。看poolboy checkin代码。当checkin时候,如果这个时候进程池数量大于默认值,已经启用了overflow,那么它会尝试关闭这个worker,dismiss_worker代码如下:

dismiss_worker(Sup, Pid) ->
true = unlink(Pid),
supervisor:terminate_child(Sup, Pid).

这个会有什么影响呢,我们分析一下这种情况。

poolboy默认配置100个worker,当worker超过100时,会启用overflow数量的worker。比如overflow为20,现在已经110个worker了。如果再次新建的client建链不成功,而同时110个worker已经有11个worker在checkin。这会导致10个worker被关闭,而这个不正常的worker checkin时可能没有被关闭。

换句话说,由于下面原因,导致正常的client被关闭,而不正常的client被保留。

  1. worker启动不能失败
  2. proxy不了解它管理的client是否正常
  3. 当进程启用overflow后,poolboy checkin会关闭worker

poolboy是一个简单,高效的进程池库,但是它对管理的worker有很严格的限制。例如管理redis client时,启动redis client不能失败,而且需要redis client自己管理链接,重连等等情况。即使采用proxy进程来管理redis client,仍然可能导致正常的redis client被关闭,而不正常的redis client存在pool中。

关于作者

微博@liaolinbo,云巴首席工程师。曾于Oracle工作。

poolboy的坑的更多相关文章

  1. worker_pool的例子

    鉴于poolboy的坑,pooler不支持r18,又有在知乎上看到大神推荐worker_pool这个进程池框架(工作者进程在创建时崩溃,worker_pool不受影响),所以研究了下,贴个小例子 my ...

  2. 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑

    阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...

  3. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  4. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  5. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  6. 踩石行动:ViewPager无限轮播的坑

    2016-6-19 前言 View轮播效果在app中很常见,一想到左右滑动的效果就很容易想到使用ViewPager来实现.对于像我们常说的banner这样的效果,具备无限滑动的功能是可以用ViewPa ...

  7. 为C# as 类型转换及Assembly.LoadFrom埋坑!

    背景: 不久前,我发布了一个调试工具:发布:.NET开发人员必备的可视化调试工具(你值的拥有) 效果是这样的: 之后,有小部分用户反映,工具用不了(没反应或有异常)~~~ 然后,建议小部分用户换个电脑 ...

  8. 首个threejs项目-前端填坑指南

    第一次使用threejs到实际项目中,开始的时候心情有点小激动,毕竟是第一次嘛,然而做着做着就感受到这玩意水好深,满满的都是坑,填都填不过来.经过老板20天惨无人道的摧残,终于小有成就. 因为第一次搞 ...

  9. dll文件32位64位检测工具以及Windows文件夹SysWow64的坑

    自从操作系统升级到64位以后,就要不断的需要面对32位.64位的问题.相信有很多人并不是很清楚32位程序与64位程序的区别,以及Program Files (x86),Program Files的区别 ...

随机推荐

  1. ubuntu-16.10-desktop-amd64.iso 版本 安装 oracle 11gR2 11.2.0.1 database

    特点: 需要重新安装:libaio1_0.3.109-2ubuntu?_amd64.deb.默认的libaio库有问题,和其默认libaio的编译方式有关! 需要重新安装gcc 4.x,默认的gcc ...

  2. hdu1251在词典里统计前缀出现的个数

    banana band bee absolute acm    ba b band abc #include<iostream> using namespace std; //数据结构 s ...

  3. Reveal-Plugin-for-Xcode 自动结合 Reveal 进行 UI 分析

    下载地址:https://github.com/shjborage/Reveal-Plugin-for-Xcode 还记得之前我们如何使用 Reveal UI 分析工具进行实时查看 UI 的结构吗?如 ...

  4. java之抽象类

    1.用abstract关键字来修饰一个类时,这个类叫做抽象类:用abstract来修饰一个方法时,该方法叫做抽象方法. 2.含有抽象方法的类必须被声明抽象类,抽象类必须被继承,抽象方法必须被重写. 3 ...

  5. ThoughtWorks 2016年第1期DNA活动总结

    今天受邀参加了2016年ThoughtWorks公司成都分公司的2016年第一期DNA活动. 什么是DNA? DNA 即 Design And Analysis.设计与分析.这个活动主要是针对产品经理 ...

  6. 通过RFC给SAP新建用户

    1.首先引用dll,然后在程序开头:using SAP.Middleware.Connector; 2.接下去就是设置登陆参数了,以前相关博文都有说明: public class MyBackendC ...

  7. CDN 和 DNS

    原文地址:http://www.cnblogs.com/xitang/p/3575255.html 相信有很多的朋友会被这几个名词绕的有些头大,很多朋友觉得智能DNS跟双线加速.CDN加速是类似的技术 ...

  8. 指定的参数已超出有效值的范围 参数名: utcDate WebResource异常

    指定的参数已超出有效值的范围.参数名: utcDate 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息.  异常详细信息 ...

  9. 基于 CentOS7 的 Kubernetes 集群

    一.环境 相关主机 master 192.168.12.197 minion 192.168.12.198~232 etcd 192.168.12.233~236 相关软件 OS CentOS 7 软 ...

  10. Hadoop入门进阶课程12--Flume介绍、安装与应用案例

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,博主为石山园,博客地址为 http://www.cnblogs.com/shishanyuan  ...