新手问题 请教如何检测 docker rails application

leijun · 2020年08月03日 · 最后由 yakjuly 回复于 2020年08月07日 · 1684 次阅读

又来像大佬们发问了。 我公司从 Heroku 迁移到 IBM Cloud 上,就感觉复杂了很多,会出现不懂的错误。 我们在云上使用 docker, 比如 sidekiq 和 application. 现在我们发现 docker 上 sidekiq 会丢失 job, 目前 devops 人察觉到的是 sidekiq on docker 有时候发生错误会重启,这个错误是 OutOfMemoryError, 内存爆了 (举个例子,比如有时有 pdf generation,会占用超过 10 GB 的内存,好几千页的 pdf ) 一般发生这种错误的情况都发生在 auto scale up / down 的时候,目前 auto scaling 是根据 cpu 使用率来 scale 的。

所以呢 我的 leader 给了我一个开放性的任务, 第一,如何侦测和抓到 OutOfMemoryError 错误。然后使用 AirBrake 之类的插件发送 notification 给自己,然后确定丢失的 job 就是这个 OutOfMemoryError 引起的。(目前不确定,只是猜想) 第二,在 scale up 特别是 scale down 的时候,SIGTERM 这个信号有没有造成 job 丢失,还有然后观察 job 是如何被重新推进 sidekia queue 的。

目前我的做法是: 我现在还是 docker 初学者,先试着在本地搭建 docker, 然后适合把 rails sidekiq 放到 docker 上,然后试试如何把它爆掉,还有本地 scale up scale down. 这做法对吗?还有什么好的方法吗?

先谢谢大家了。

你用 docker 去复现 production 的做法没问题,本地 scale up 和 scale down 我没见过。

scale down 一般是系统级别的关机,一般会造成 job 丢失 除非你用 sidekiq-pro 或者 sidekiq-enterprise,任务没完成之前不会从 redis 里被删除。scale down 的时候别的 sidekiq 进程会重试之前失败的 job。

看得出来你们系统的几个问题

  • 启动一次 Sidekiq 的 thread 或者 process 太多
  • 任务消耗内存不均匀,某个后台 pdf 任务可能占 200mb 内存,有的后台任务就 1m,多个 200mb 内存的任务同时跑就可能导致 out of memory
  • 你说的好几千页的 pdf generation 是一个任务?如果消耗很多内存 处理时间很长,那么这个任务不适合放在 sidekiq 里

解决方案 把内存消耗大的任务单独放在一个 sidekiq container 里跑 sidekiq -q heavy_task -c 5 限制 threads 和 worker 的数量 让 5 个或者多个同时跑不超过服务器的内存 内存小的任务放在其他 container 里跑 sidekiq -q default -c 30 这些任务随便跑,30 个 thread 不超过服务器内存

资源消耗严重的任务 使用 container 跑一次性任务,比如 启动一个和 app 一样的环境 但是根据某些参数 只跑一个任务,跑完进程就结束 可以把任务信息持久化在 redis 或者数据库里,和 sidekiq 隔离开就行

https://github.com/mperham/sidekiq/wiki/Signals

TSTP tells Sidekiq to "quiet" as it will be shutting down at some point in the near future. It will stop fetching new jobs but continue working on current jobs. Use TSTP + TERM to guarantee shutdown within a time period. Best practice is to send TSTP at the start of a deploy and TERM at the end of a deploy.

如果有任务运行的比较久的话,-t 也要设置的够长

yakjuly 回复

非常感谢这回复,我模拟出 Docker 下的 OutOfMemory 了,这种情况下 如果 job 没结束的话就永久丢失了。 可能我们要看看 Sidekiq Pro 或者看看别的比如 RabbitMQ.

现在的 auto scale down,其实让我很困惑,请问 SIGTERM 属于系统级别的关机吗? 我看到的是 auto scale 是 IBM CLOUD 自动弄的,我感觉我们没那么大的权限来决定 scaling strategy. 为了能侦测到 sidekiq container 是否每次启动,我准备在 Sidekiq 启动代码上魔改 monkey patch,加上 airbrake, 这样就能知道是否重启,但还不能知道这次重启是因为 crash 导致的,还是正常的 scaling up.

使用 container 跑一次性任务这个做法我也不知道能不能行,我可以试试看,弄一个 container 专门服务一个 heavy queue 因为目前我们已经有 3 个不同的 sidekiq.yml 来启动不同的 sidekiq, 3 个都是隔离的。同时 scaling 的话,就是其中的一个复制一个。其实是怕浪费太多云资源,导致账单太高。

那个 PDF generation 我们试过好几个 GEM 了,已经选了一个比较少耗资源的 GEM,还进行了很多修改,但这东西跟新感觉有点跟不上进度

leijun 回复

我没用过 IBM CLOUD,不太清楚。我用 AWS ECS 自动伸缩的时候 是会强制杀死 正在跑的 sidekiq jobs 的。这需要你写 worker 的时候 写可以重试 容错的代码。简单的方法就是买 sidekiq pro。

PDF generation 我以前做过,如果用 html2pdf,prawn 之类的生成 pdf 内存高是肯定的,而且合并 pdf 的时候内存也会升高很多。 别的 gem 能做的就不要用 prawn。它是真的费内存。 内存降到一定程度就跟 gem 没太大关系,处理 pdf 就是耗内存。 这个时候你可以考虑 serverless。做一个服务 专门合并 pdf。把小页的 pdf 生成好 放到类似 s3 的服务里,然后所有的问价生成完了 请求一下 serverless API。severless 看能不能后台 负责合并。并且完成后发送一个新文件地址给你的 app。 好处是合并不影响主程序。但是 serverless 一般也有限制,运行时间不超过 5 分钟,cpu 和内存也许可以配置。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号