Rails Puma 频繁产生 CLOSE_WAIT 导致无响应?

xsown · 2019年05月16日 · 最后由 kalel 回复于 2019年05月22日 · 1727 次阅读

nginx + puma,rails 5,纯 api 模式提供 json 接口

不定期出现所有接口都无响应的症状,去服务器 lsof 的结果:非常多的 CLOSE_WAIT,如下图:

此时只能 kill puma 进程然后重开。

nginx 配置:

puma.rb:

database.yml:

请问大佬们,可能是什么原因?有什么彻底的解决方法么?(手动抠鼻)

看上去都是数据库?

加大点 pool 比如 30 - 50 试试 ?

把数据库的 pool 设置为 50 及以上试试。 用 ab 先压一下,确定问题

@jicheng1014 @awking pool 的大小应该为 cpu 核心数 *2 + 磁盘数

kikyous 回复

怎么得出来的

A connection pool synchronizes thread access to a limited number of database connections. The basic idea is that each thread checks out a database connection from the pool, uses that connection, and checks the connection back in. ConnectionPool is completely thread-safe, and will ensure that a connection cannot be used by two threads at the same time, as long as ConnectionPool's contract is correctly followed. It will also handle cases in which there are more threads than connections: if all connections have been checked out, and a thread tries to checkout a connection anyway, then ConnectionPool will wait until some other thread has checked in a connection. pool 的值应该与 puma 最大 thread 数一致,大于 thread 数其实是无效的。

Terry.Shi 回复

这个线程池个数设置方式 应该比较靠谱.

特例是, 在 puma 的一个 thread 里并行用到了一个以上的连接. 但是似乎我也没想到这种情况的场景.

而且算法是在 puma max threads 的情况下的, 一般压力不会那么大

kikyous 回复

简化一下情况

假设运行后端的服务器只有 1 核的 CPU

之后开一个 PUMA , puma 跑 20 个线程,

现在有大量数据库事务的任务,每个事务执行需要 1s,

再假设除了执行数据库, 其他操作小于 1ms 的响应

如果 pool 的大小是 2, 那么是不是此时就只能并发两个请求?

是否能等效理解为 在执行事务的时候, 此时服务器的 cpu 是空闲状态, 但是却因为数据库连接池的问题不能进行服务?

如果此时连接池开到 20, 将 puma 的线程池满

似乎就可以进入 20 个并发了

或者我的理解有问题, 有一些概念上的错误?

jicheng1014 回复

我的理解是: 线程数也是和 cpu 数量相关的,1 核的 cpu,你线程设置成 20,反而使 cpu 花费大量时间做上下文切换,导致性能降低。 所以我认为 puma 线程数,数据库连接池都应和 cpu 数量挂钩的

直接用 pg bouncer 吧,不要让 puma 管理连接池了

kikyous 回复

cpu 是跟 puma 进程数挂钩的吧。IO wait puma 多线程就管用了... DB pool 是要跟 puma 线程数挂钩的吧,如果 20 个线程全在跑,pool 数为 2,那显然是不够用...

kikyous 回复

在我举的例子当中, 当进行数据库事务的时候 本机的 CPU 是闲置的状态, 这个时候切换上下文是会提高 cpu 效率的, 而这种情况的变种我觉得还经常会发生 (瓶颈在数据库). 所以我会对您那个公式有点不同意见

13楼 已删除

将 pool 和 PUMA 的线程数配置 增大。你配 5 对现在的系统服务应该小了

这是数据库池问题,与 puma 没有直接关系。建议你看看 postgresql 的 log。你的连接被数据库关闭了。

你可以查看一下 postgresql 的配置文件, 检查下,下面三项配置,可以参考这里

tcp_keepalives_idle
tcp_keepalives_interval
tcp_keepalives_count
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册