Python进程和内存管理案例
这是一个Instagram的工程师写的他们的优化案例,他们使用Python和uWSGI提供服务。
uWSGI会fork多个worker进程,并将请求分配到不同的worker进行处理,但是fork多少worker进程是通过配置文件静态配置的,使用者需要根据自身程序的情况和服务器的资源情况来选择配置多少合适。
在可靠性工程(Site reliability engineering,SRE)实践中,这类静态配置通常都是不合适的,因为随着时间的推移,系统的迭代,程序对内存和CPU的消耗也会发生变化。
每次都通过修改配置文件来调整是繁琐且不切实际的,通过自适应算法来调整是SRE实践中常用的方案。
原文中的方案如下:
- 统一初始化 在master进程中完成比较耗时的初始化操作,worker与master通过共享内存共享初始化后的数据,提高worker的初始化速度
- 控制单进程内存占用防止内存泄漏
Master和worker之间通过一块共享内存来交换状态
在worker进程内启动一个后台线程,定时监控当前进程的内存占用情况,并在共享区内更新自己的内存占用数据
每次处理完成一个请求,worker都检查一下自己占用的内存是否超出reload-on-rss阈值,超出则在共享区内标记准备退出,然后执行退出过程
Master进程监控worker进程:
- 若worker进程标记准备退出,但在规定时间内还没有退出,则杀掉该进程
- 若worker进程占用的内存超出evil-reload-on-rss设定的阈值,则杀掉该进程
- 全局内存控制防止OOM Master循环监控主机的内存是否达到内存占用的下限阈值(Lower bound),若内存占用超过下限阈值,master找到内存占用最高的N个worker,将其标记为退出,worker在处理完每个请求时检查是否需要退出 若主机的内存占用达到上限阈值(Upper bound),master找到N个占用内存最高的worker,直接kill掉 其中 N 是通过一个公式计算出来的
- 根据请求队列创建Worker 根据请求的排队情况自适应创建worker,避免创建出一些空闲的worker占用系统内存
文章中说,经过这些改造后,Python服务的承载能力提升了11%,监控中看到内存占用的尖刺也平缓了很多。