性能调优Python集成Java的服务OOM问题分析经历

Posted sysu_lluozh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了性能调优Python集成Java的服务OOM问题分析经历相关的知识,希望对你有一定的参考价值。

一、问题背景

在一个遍历服务中,同时运行5个设备执行遍历任务时,快速出现如下错误

容器ExitCode :137, 原因:OOMKilled

该服务是通过python程序唤起执行Java任务

二、资源占用

既然是OOM,得确认资源占用情况

  • 服务的资源占用

发现系统中总内存使用较低,且python和Java进程的内存使用不高,那为什么会出现OOM的情况呢?
注:其实这里查看的是整个服务器的内存占用,该服务器内容总共25G,所以内存占用不高

  • 查看容器的内存配置

    容器的最大内存500M
    但是从这些信息中并未得到较高的内存占用

三、python内存分析

使用memory_profiler分析python的内存使用

from memory_profiler import profile

@profile
def compatibility_task(task_id):
    # do compatibility job

python task.py

获取具体的执行信息

内存占用200M以内,应该问题不大(这里其实有个大坑,导致后面折腾一通)

四、Java内存分析

既然不是python的性能问题,那么接下来分析一下java的内存
使用命令获取hprof文件

jmap -dump:format=b,file=/app/temp/test11.hprof pid

很开心的使用MAT工具分析dump文件
发现内存占用正常没有问题

配置OOM时自动触发headdump

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/temp/heapdump.hprof

在OOMKilled时并未触发生成dump文件,那是否是因为并不是Java程序的OOM呢?

五、进程内存使用分析

好吧。还是需要详细分析究竟是哪个进程的内存占用的问题

同时执行5个设备遍历,在运行时获取各个进程的内存使用

ps aux | awk 'print $6/1024 " MB\\t\\t" $11' | sort -n

得到信息

0 MB            COMMAND
0.00390625 MB           /pause
0.667969 MB             sleep
0.972656 MB             awk
2.29688 MB              sort
3.34766 MB              /bin/bash
3.41406 MB              /bin/bash
3.66016 MB              ps
4.05469 MB              top
9.15625 MB              java
53.5156 MB              java
487.68 MB               python3.6

竟然是python的程序内存撑满导致容器直接OOM

六、python源码分析

回到python内存分析这一步,为什么在内存分析中并未找到问题呢?
问题在于获取内存数据是在本地调试执行,且执行的是1个设备执行遍历任务

还是不能偷懒,先撸一遍遍历时python的执行逻辑吧,简化的相关逻辑如下:

  1. 从redis拉取任务
  2. 监测需要执行的任务数
  3. 最高拉起20个线程同时执行

比如任务列表中需要执行的任务数10,那么接下来10个线程每个线程都处理的任务如下:

  1. 解析任务信息
  2. 执行各自下载apk操作
  3. 初始化环境操作
  4. 下发安装操作
  5. cmd执行遍历服务jar包
  6. 处理并获取报告
  7. 环境清理处理

从python内存分析中也可以看到

Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
   137  58.6406 MiB  58.6406 MiB           1       @profile(precision=4, stream=open('memory_profiler_traverse_test.log', 'w+'))
   
   ......

   184  59.1328 MiB   0.0000 MiB           1               if not app_config_info:
   185                                                         Logger.logger.info('不存在该应用配置,已跳过,请在配置页面添加该应用配置')
   186                                                         return
   192                                         
   193 193.1602 MiB 134.0273 MiB           1               install_result, install_time = self.app_install_exec(package_name, apk_url)
   194 193.1602 MiB   0.0000 MiB           1               print("install_time: ", install_time)
   195                                                     # 测试应用启动时间
   196 193.1602 MiB   0.0000 MiB           1               start_result, app_start_time = self.get_app_start_time(package_name, app_config_info.get("main_activity"))
   197 193.1602 MiB   0.0000 MiB           1               self.yaml_file_name = compatibility_yaml_name.format(self.device_id + "_" + str(app_config_info.get("id")))
   198 193.1602 MiB   0.0000 MiB           1               Logger.logger.info("yaml file: ".format(self.yaml_file_name))
   199 193.1641 MiB   0.0039 MiB           1               app_performance = AppPerformance(self.subtask_id, self.device_id, package_name)

   ......
   

在安装操作self.app_install_exec(package_name, apk_url)时内存飙升,那么着重看一下安装的代码逻辑:

def app_install(self, download_url):
    get_response = requests.get(download_url, timeout=60)
    if get_response:
        app_content = get_response.content
        res = requests.post(
        	"http://:/mobile//installApp".format(self.agent_ip, self.agent_port, self.device_id),
            files=
                "app": app_content
            
        )

OMG!安装的过程是直接requests.get将数据包下载下来,然后再将包内容content直接下发给手机设备mobile执行安装操作
这种处理方式太诡异了,有几个问题:

  1. 多线程执行时包其实基本是同样的,但是都执行了同样的下载操作,为什么不做合并处理?
  2. 下载时直接将apk包load在内存对象中然后再转发给mobile,如果包较大且多个同时下载时内存是否可以支持?
  3. 有链接地址,为什么不传链接地址让mobile直接下载安装呢?

七、问题修复

其实现在问题已经很明显了,后面验证了5台、10台、20台设备时再次验证了从源码中的分析的原因

问题修复方式只要将apk包的链接地址传给mobile,mobile自行下载然后执行安装逻辑即可

以上是关于性能调优Python集成Java的服务OOM问题分析经历的主要内容,如果未能解决你的问题,请参考以下文章

JVM调优 - 用Arthas解决OOM问题

JVM调优 - 用Arthas解决OOM问题

spark性能调优 数据倾斜 内存不足 oom解决办法

2022-02-26-Spark-46(性能调优SparkUI)

Day853.WorkerThread模式 -Java 性能调优实战

python 使用SearchWrapper进行OOM,兼容回调,与Model API兼容的调优。