问题背景
之前在做扫描器时,有一个功能是:生成任务实例。
使用场景是:用户在web页面上点击启动按钮,就可以立即运行指定的任务(比如指定哪些POC对哪些资产做漏洞扫描);定期运行扫描任务
因为”生成任务实例”时可能需要比较久的时间,并且有很多其他业务逻辑,所以这里由后台进程来生成任务实例,实现”异步”的效果。
在线上发现一个问题:”后台创建任务实例的进程”运行一段时间后,内存占用越来越大。
虽然当时能力有限,并没有找到”内存不断增长”的原因,但是最终还是解决了这个问题。
怎么解决的
我当时的想法是,虽然找不到原因,但是重启大法好啊,我可以处理N个任务后,删除这个”后台创建任务实例的进程”再新建进程。
项目中我用的是python语言,celery框架[1],刚好celery提供了两个参数
root@50f41bfab20a:/# celery worker --help
...
--max-tasks-per-child MAX_TASKS_PER_CHILD, --maxtasksperchild MAX_TASKS_PER_CHILD
Maximum number of tasks a pool worker can execute
before it's terminated and replaced by a new worker.
--max-memory-per-child MAX_MEMORY_PER_CHILD, --maxmemperchild MAX_MEMORY_PER_CHILD
Maximum amount of resident memory, in KiB, that may be
consumed by a child process before it will be replaced
by a new one. If a single task causes a child process
to exceed this limit, the task will be completed and
the child process will be replaced afterwards.
Default: no limit.
可以指定内存超过多少、处理多少任务后,生成新的进程来处理任务。
我就靠这两个参数解决了问题。
总结
后面我在做安全评估时,发现其他业务线有php语言开发的程序也是这种模式:使用子进程处理任务,处理N个任务后,”重新创建”子进程。
所以,凡是业务场景允许”进程重启”的,应该都可以用这种模式来解决”内存泄漏”。
难解决的是”长时间持续运行的程序”出现的”内存泄漏”
参考资料
celery框架: https://github.com/celery/celery
[2]既然每个程序占用的内存都是操作系统管理的,为什么内存泄漏还是个问题?- pansz的回答 – 知乎: https://www.zhihu.com/question/400104113/answer/1278541405
原文始发于微信公众号(leveryd):解决内存泄漏的通用思路