公司生产环境的 Python 服务 OOM 了三次,我靠这五个方法终于稳住了.
事情是这样的,我们公司生产环境有个 Python 服务,负责处理用户上传的文件。这个服务跑了大半年一直挺稳。结果上个月连续三天,每天下午三点多准时 OOM。第一次我以为是巧合。第二次我开始慌了。第三次直接被老板叫去办公室。
那三天我的心情就像坐过山车。白天排查问题,晚上盯着监控。睡了不到十个小时。我翻遍了日志,查了内存分析,试了好几种方案。最后总算把问题压住了。
第一个方法,我检查了代码里的列表缓存。有个同事偷懒,把用户上传的文件数据全部加载到了一个全局列表里。文件小的时候没事。一旦有人传了几百兆的大文件,这个列表就爆炸了。我把这个逻辑改成了流式处理,读一点处理一点,不把全部数据放内存里。
第二个方法,我查了下数据库连接池。原来代码里每次查询都新建连接,又不主动关闭。连接对象越积越多,内存就被吃掉了。我配置了连接池,设置最大连接数,用完之后归还。还给每个连接加了个超时自动回收。
第三个方法,我看了下第三方库的使用方式。有个同事引入了一个图像处理库,每次处理图片都创建新对象,没有复用。我就把频繁使用的对象改成了单例模式。重复使用同一个实例,内存占用立马降下来。
第四个方法,我加了内存监控告警。写了个小脚本,每分钟检查一次进程的内存使用率。超过百分之八十就发钉钉通知。这样能提前发现异常,不等 OOM 才知道。内存一涨我就知道哪个接口出了问题。
第五个方法,我调整了 GC 参数。Python 的垃圾回收机制在某些场景下不灵敏。我手动调小了回收阈值,让解释器更频繁地去清理无用对象。虽然会多消耗一点 CPU,但内存稳定了。
改完之后,这个服务跑了两个星期没再出过问题。老板终于不找我谈话了。同事也不敢随便往代码里塞全局变量了。
现在回想起来,OOM 这东西就是一点一点积累起来的。你不管它,它就用三次事故教育你。你管了它,它就服服帖帖。