【docker知识】快速找出服务器中占用内存较高的容器

本文由Markdown语法编辑器编辑完成。

1.背景:

近期在处理现场问题,观察服务器时,会遇到某些进程占用较高内存的情况。由于我们的服务,基本上都是以容器的方式在运行,因此就需要找到,到底是哪个容器,占用的内存比较高。

以下是根据htop,查看到的,占内存较高的进程的信息。
在htop中,第一列是进程的id,通过进程id, 一般就可以看到进程的启动方式。进而,希望能够通过进程id, 找到是哪个启动的容器,占用内存较高,从而想办法来调整其内存占用,改善服务器的性能。

2. 具体操作:

2.1 htop按内存排序,查找内存占用较高的进程id

在这里插入图片描述

第一列显示的PID: 1249316, 就是目前占用内存最高的进程id.

那么怎么通过这个进程id, 来查找到是哪一个docker服务呢.
可以采用:

cat /proc/1249316/cgroup

这样就会输出docker的id. 比如这里就会输出:

0::/docker/19a3a51e7753133ff504b68ecffee477bdf40fe95f0865c5b922b173a6a0a7bd

然后,我们可以利用docker/后面的这一列数字.取前面的12以内的数字,再grep docker.

docker ps -a |grep -i 19a3a51e77

在这里插入图片描述

2.2 通过将所有的容器,按占用内存大小排序后输出

通过向AI提问后,可以通过shell脚本的方式,计算出当前服务器上面所有的容器的内存占用,并且按照内存占用的大小,排序后输出.具体指令是:

docker stats --no-stream --format "{{.MemUsage}}" | awk '{split($1, a, "MiB"); if (a[2] == "") {split($1, a, "GiB"); sum += a[1] * 1024} else {sum += a[1]}} END {print sum " MiB"}'

在这里插入图片描述
脚本运行完成后,我们便可以看到,根据内存占用大小排序后的容器的名称,id, 当前占用CPU的百分比,内存占用百分比等参数.
从而就可以来分析,到底是什么原因,占用较高的内存,是否符合预期等.

<think>我们正在讨论如何在Linux服务器查看各个Python任务占用CPU内存情况。 根据引用,我们可以使用psutil模块(引用[2]和[3]提到)来获取进程信息。 但是,用户要求的是在Linux服务器查看各个Python任务,所以我们可以通过命令行工具或者编写Python脚本来实现。 方法一:使用Linux命令行工具 1. 使用top命令:可以实时查看进程的CPU内存占用情况。我们可以通过grep过滤出Python进程。 命令:`top -p $(pgrep -d ',' python)` 或者 `top | grep python` 2. 使用ps命令:可以列出当前所有Python进程的资源占用。 命令:`ps aux | grep python` 或 `ps -eo pid,comm,pcpu,pmem | grep python` 3. 使用htop:更友好的交互式进程查看工具(如果安装),同样可以过滤python进程。 方法二:使用Python脚本(基于psutil模块,如引用[2][3]所述) 我们可以编写一个Python脚本,遍历所有进程,找出Python相关的进程,并打印其CPU内存使用情况。 考虑到用户想要查看各个Python任务,我们可以提供一个简单的脚本示例。 脚本思路: 1. 导入psutil模块 2. 遍历所有进程 3. 检查进程名是否包含"python"(或者检查命令行参数) 4. 获取该进程的CPU使用率和内存使用情况 注意:由于CPU使用率是动态的,我们可能需要一段时间内的采样(比如1秒)来获得瞬时使用率。 根据引用[3],我们可以这样获取: 由于引用中并没有直接给出获取每个Python进程的脚本,我们可以结合引用内容编写。 参考示例代码: ```python import psutil # 遍历所有进程 for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'cpu_percent', 'memory_percent']): try: # 检查是否是Python进程:通过进程名或命令行参数 if 'python' in proc.info['name'].lower() or \ (proc.info['cmdline'] and 'python' in ' '.join(proc.info['cmdline']).lower()): # 为了获取瞬时CPU使用率,我们需要调用一次cpu_percent(interval=0.1)之类的,但是注意这样会阻塞 # 如果已经通过参数获取了cpu_percent,那么这里可能为0,因为第一次调用需要间隔。所以我们可能需要重新获取 # 这里我们使用一个非阻塞的方式:先获取一次,然后等待一小段时间再获取?但是这样会使得整个脚本变慢。 # 另一种方法是使用之前调用过cpu_percent(interval=None)来开始计算,然后这里再获取。但是这样会使得代码复杂。 # 我们可以简单使用interval=0.1,但注意这会使得每次循环都等待0.1秒,整个脚本会变慢。 # 或者,我们可以不显示瞬时CPU使用率,而是显示最近一次的快照(但可能不准确)。 # 这里我们选择使用非阻塞模式,只获取从上次调用以来的CPU使用率。第一次调用cpu_percent(interval=None)会开始计算,然后返回0。 # 所以我们需要在循环开始前先等待一次? # 为了避免等待,我们可以先不显示CPU使用率,或者使用瞬时值(可能不准)。 # 另一种办法:我们可以先收集所有Python进程的PID,然后统一获取CPU使用率(通过调用一次psutil.cpu_percent(interval=1))再遍历每个进程获取百分比。 # 但是这样需要两次遍历。 # 简单处理:这里我们使用一个循环,第一次遍历只记录PID,然后调用cpu_percent(interval=1)来获取一个全局的,然后再遍历每个进程获取其CPU百分比。 # 但这样会耗时1秒。 # 由于我们想要实时性,我们可以按照如下方式(参考psutil文档): # 先调用一次psutil.cpu_percent(interval=None)来初始化,然后立即获取每个进程的cpu_percent(interval=0)(非阻塞),但这样获取的是从上次调用以来的。 # 因此,我们可以在循环之前先初始化,然后立即遍历,但是这样第一次获取可能为0。 # 我们采用另一种做法:不显示每个进程的CPU百分比,或者使用非阻塞方式获取(可能不准确),或者使用系统工具。 # 鉴于复杂度,我们可以显示内存占用,而CPU占用我们可以用另一种方式:使用psutil.Process(pid).cpu_percent(interval=0.1)来获取,但这样会等待0.1秒每个进程,如果进程多会慢。 # 这里我们为了简单,只显示内存占用CPU占用我们可以用快照(不精确)或者放弃显示。但是用户要求CPU内存。 # 根据引用[3]中的示例,获取CPU使用率的方法是调用cpu_percent(interval=0.1),但这样每个进程都需要0.1秒。 # 因此,我们修改策略:先获取所有Python进程的列表,然后逐个获取CPU使用率(间隔0.1秒),这样每个进程都会有一个瞬时值。 # 但是这样整个脚本运行时间将是0.1秒乘以进程数,可能会很慢。 # 另一种方法是使用一个循环,先获取所有进程,然后一起计算(但psutil没有提供批量获取瞬时CPU使用率的方法)。 # 所以,我们采用:先收集所有Python进程,然后逐个计算CPU使用率(间隔0.1秒),并打印。 # 但注意,这样会使得脚本执行时间较长,特别是进程多的时候。 # 因此,我们提供一个折中方案:只获取内存使用情况,而CPU使用情况可以通过其他方式(如top)查看。 # 但是用户要求同时查看CPU内存。 # 我们决定:先打印进程信息,但不包括实时CPU使用率(因为获取实时CPU使用率需要时间间隔),然后建议用户使用系统工具。 # 或者,我们可以只打印进程的CPU使用率(通过非阻塞方式,即上次调用以来的,但第一次调用可能为0)。我们可以先让每个进程都调用一次cpu_percent(interval=None)来初始化,然后再调用一次(间隔0)来获取。 # 步骤: # 1. 初始化:对于每个进程,调用一次cpu_percent(interval=None) 来开始计算。 # 2. 等待一小段时间(比如0.5秒) # 3. 再次遍历,调用cpu_percent(interval=0) 获取百分比。 # 这样需要两次遍历和等待时间。 # 由于上述复杂度,我们决定采用另一种方式:使用psutil的process_iter结合一个短暂的间隔来获取多个进程的CPU使用率。 # 但是,根据psutil文档,我们可以这样做: # 首先,遍历所有进程,初始化每个进程的cpu_percent计数器(通过调用cpu_percent(interval=None)) # 然后,等待1秒(这样可以得到一个时间间隔) # 接着,再次遍历,获取每个进程的cpu_percent # 这样整个脚本大约需要1秒,但可以获取所有进程的CPU使用率。 # 因此,我们编写如下: # 由于我们在遍历中已经获取了进程,所以我们可以先初始化所有Python进程的cpu_percent,然后等待,然后再获取。 pass # 这里我们先不实现,因为这样会使脚本变慢。 # 考虑到用户可能希望快速查看,我们建议使用命令行工具。 # 所以,我们提供命令行工具的查看方法,然后提供一个简单的脚本(只获取内存,或者获取CPU但可能不准确)。 # 这里我们改变策略:提供一个脚本,只显示内存使用情况,而CPU使用情况建议用户用top命令查看。 # 或者,我们可以尝试非阻塞的方式,但是可能不准确。 # 我们决定:显示内存使用情况,以及进程的CPU时间(累计的),而不是实时使用率。 # 实时使用率需要间隔,而累计时间可以直接获取。 # 累计CPU时间可以通过`proc.cpu_times()`得到,然后我们可以自己计算使用率?但是需要两次采样。 # 所以,我们放弃实时使用率,只显示内存使用情况。 # 但是用户要求的是“占用”,通常是指实时的使用率。 # 因此,我们建议用户使用系统自带的工具(如top)来查看实时CPU使用率。 # 而我们的脚本主要用来查看内存占用。 # 我们可以这样:打印每个Python进程的PID,进程名,内存占用(百分比或实际大小),以及命令行(可选) # 然后CPU使用率我们通过非阻塞方式获取,并注明可能不准确(尤其是第一次运行)。 # 我们尝试获取非阻塞的CPU使用率(即从上次调用以来的,但由于我们之前没有调用过,所以会是0,所以我们需要先调用一次) # 因此,我们可以在循环之前,对所有进程调用一次cpu_percent(interval=None)来初始化?但是这样需要遍历两次。 # 我们决定:不显示CPU使用率,或者显示为0(并说明需要间隔才能获取)。 # 所以,我们输出内存信息,以及CPU累计时间,然后让用户自己判断。 # 但是用户要求的是CPU占用率(实时)。 # 综上,我们建议用户使用命令行工具(如top)来查看实时的CPU使用率,而内存占用可以使用我们的脚本。 # 因此,我们提供一个只显示内存占用的脚本,并给出使用命令行查看CPU的建议。 except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): pass ``` 由于上述复杂性,我们决定提供一个简单脚本,只显示内存使用情况(因为内存使用是静态的),而CPU使用率我们使用一个非阻塞的方式获取(可能第一次为0)。 同时,我们也可以显示CPU累计时间(用户时间+系统时间),但这不是使用率。 另外,我们可以尝试另一种方式:使用`psutil.cpu_percent(interval=0.5)`来获取整个系统的CPU使用率,然后每个进程的CPU使用率可以通过两次采样(间隔一段时间)来获取每个进程的CPU时间增量,然后除以间隔时间再除以CPU核心数?然后乘以100?这样需要两次遍历和等待。 但是,为了满足用户需求,我们提供一个需要运行一段时间(比如总共1秒)的脚本。 我们采用以下方法: 1. 第一次遍历所有进程,记录每个Python进程的ID,并初始化每个进程的CPU时间(通过`proc.cpu_times()`获取累计时间) 2. 等待1秒 3. 第二次遍历,再次获取每个进程的CPU时间,计算增量,然后除以等待时间,得到该进程的CPU使用率(占一个核心的比例),然后乘以100得到百分比。注意,如果有多个核心,那么使用率可以超过100%。 但是,psutil的cpu_percent方法已经帮我们做了这个,不过它是针对单个进程的,并且需要两次采样。 实际上,我们可以使用`proc.cpu_percent(interval=0)`来获取非阻塞的,但是这样第一次会返回0,所以我们需要先调用一次(间隔不为0)才能得到非0值。 所以,我们可以在循环中为每个进程调用`proc.cpu_percent(interval=0.1)`,这样每个进程等待0.1秒,然后得到其CPU使用率。但是这样每个进程都要0.1秒,总共需要0.1秒*进程数。 我们折中:使用0.1秒的间隔,然后逐个进程获取。 脚本如下: ```python import psutil # 获取所有Python进程,并先存储起来 python_procs = [] for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'memory_percent']): try: if 'python' in proc.info['name'].lower() or \ (proc.info['cmdline'] and 'python' in ' '.join(proc.info['cmdline']).lower()): python_procs.append(proc) except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): pass # 然后我们遍历这个列表,获取每个进程的CPU使用率(间隔0.1秒) for proc in python_procs: try: # 获取CPU使用率,间隔0.1秒 cpu_percent = proc.cpu_percent(interval=0.1) mem_percent = proc.memory_percent() print(f"PID: {proc.pid}, 进程名: {proc.info['name']}, CPU使用率: {cpu_percent}%, 内存使用率: {mem_percent}%") print(f"命令行: {proc.info['cmdline']}") except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): pass ``` 注意:上述脚本的总运行时间大约是0.1秒乘以进程数(因为每个进程的cpu_percent(interval=0.1)会等待0.1秒)。如果进程很多,可能会很慢。 改进:我们可以使用多线程,但是这样会增加复杂性。因此,如果进程不多,这个脚本可以接受。 另外,我们可以使用一个间隔来同时获取多个进程的CPU使用率,但是psutil没有直接提供这种方法。我们可以这样做: 1. 记录每个进程的初始CPU时间(用户+系统) 2. 等待一个时间间隔(例如1秒) 3. 再次获取每个进程的CPU时间,然后计算增量,除以间隔时间,再除以CPU核心数?不对,CPU时间增量除以间隔时间就是该进程的CPU使用率(占一个核心的百分比)。例如,如果进程在1秒内使用了0.5秒的CPU时间,那么使用率就是50%。注意,如果进程是多线程的,它可以使用多个核心,所以使用率可能超过100%。 所以,我们可以这样: ```python import psutil import time # 第一步:获取所有Python进程并记录初始CPU时间 python_procs = [] for proc in psutil.process_iter(['pid', 'name', 'cmdline']): try: if 'python' in proc.info['name'].lower() or \ (proc.info['cmdline'] and 'python' in ' '.join(proc.info['cmdline']).lower()): # 获取初始CPU时间(用户+系统) cpu_times1 = proc.cpu_times() # 我们只需要用户+系统时间(两者之和) total_time1 = cpu_times1.user + cpu_times1.system python_procs.append((proc, total_time1)) except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): pass # 等待一段时间 interval = 1 # 1秒 time.sleep(interval) # 再次遍历,计算CPU使用率 for item in python_procs: proc, total_time1 = item try: cpu_times2 = proc.cpu_times() total_time2 = cpu_times2.user + cpu_times2.system # 计算增量 cpu_usage = (total_time2 - total_time1) / interval * 100 # 使用率百分比(占一个核心) # 注意:这里计算的是占用一个核心的百分比。如果进程是多线程的,可能超过100%。 # 另外,我们也可以除以总的CPU时间(即interval * 核心数)来得到占整个CPU的百分比?但是通常top命令显示的是占一个核心的百分比(所以可以超过100%) # 我们按照top命令的方式,即占一个核心的百分比,所以这里乘以100(这样4核系统上最高可以达到400%) # 获取内存使用率 mem_percent = proc.memory_percent() print(f"PID: {proc.pid}, 进程名: {proc.info['name']}, CPU使用率: {cpu_usage:.2f}%, 内存使用率: {mem_percent:.2f}%") print(f"命令行: {proc.info['cmdline']}") except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): pass ``` 这种方法只需要总共1秒的等待时间(不管进程有多少),但是也有缺点:两次采样之间,有些进程可能已经结束,所以需要异常处理。 我们选择第二种方法,因为它更快。 但是,内存使用率我们可以在第一次就获取吗?还是第二次?注意,内存使用率是瞬时的,我们可以第二次获取(也可以在第一次获取,但是为了数据一致性,我们在第二次获取,这样和CPU使用率是同一时刻?) 实际上,内存使用率在两次采样之间变化不大,我们可以第一次获取内存使用率,但为了简单,我们在第二次一并获取(注意,第一次没有获取内存)。 所以,我们在第二次获取内存使用率。 因此,我们提供第二种脚本。 另外,我们还可以获取内存的实际使用量(单位MB),而不仅仅是百分比。用户可能更关心实际内存。 我们可以使用`proc.memory_info().rss`来获取实际驻留内存(单位字节),然后转换为MB。 修改脚本如下: ```python import psutil import time # 第一步:获取所有Python进程并记录初始CPU时间 python_procs = [] for proc in psutil.process_iter(['pid', 'name', 'cmdline']): try: if 'python' in proc.info['name'].lower() or \ (proc.info['cmdline'] and 'python' in ' '.join(proc.info['cmdline']).lower()): # 获取初始CPU时间(用户+系统) cpu_times1 = proc.cpu_times() total_time1 = cpu_times1.user + cpu_times1.system python_procs.append((proc, total_time1)) except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): pass # 等待一段时间 interval = 1 # 1秒 time.sleep(interval) # 再次遍历,计算CPU使用率 for item in python_procs: proc, total_time1 = item try: cpu_times2 = proc.cpu_times() total_time2 = cpu_times2.user + cpu_times2.system cpu_usage = (total_time2 - total_time1) / interval * 100 # 使用率(占一个核心的百分比) # 获取内存信息 mem_info = proc.memory_info() rss_mb = mem_info.rss / 1024 / 1024 # 转换为MB # 还可以获取内存百分比,如果需要的话 mem_percent = proc.memory_percent() print(f"PID: {proc.pid}, 进程名: {proc.info['name']}, CPU使用率: {cpu_usage:.2f}%, 内存: {rss_mb:.2f}MB (内存使用率: {mem_percent:.2f}%)") print(f"命令行: {' '.join(proc.info['cmdline'])}") except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): pass ``` 这个脚本可以输出每个Python进程的PID,进程名,CPU使用率(占一个核心的百分比),内存占用(MB)和内存使用率(占系统总内存的百分比)。 注意:内存使用率是相对于整个系统内存的百分比。 但是,用户可能只关心实际内存占用(MB),所以我们可以只显示MB。 另外,我们也可以显示进程的启动时间、运行时间等信息,但用户需求是CPU内存。 因此,我们提供这个脚本。 最后,我们给出命令行工具的方法(快速查看)和脚本方法(需要1秒等待),让用户选择。 总结: ### 方法1:使用命令行工具 1. `ps aux | grep python`:查看所有Python进程的资源占用(包括CPU%,内存%,内存大小等) 2. `top -p $(pgrep -d ',' python)`:动态显示Python进程的资源占用(按q退出) ### 方法2:使用Python脚本(需要安装psutil) 安装psutil:`pip install psutil` 将上面的脚本保存为`python_monitor.py`,然后运行:`python python_monitor.py` 注意:脚本中我们等待1秒,所以脚本运行时间大约1秒。 我们选择第二种脚本,并给出完整代码。 但是,我们也可以使用第一种方法(命令行)更简单。 在回答中,我们给出两种方法。 </think>了解您需要监控Linux服务器上各个Python任务的CPU内存占用情况,以下是几种实用方法: ### 方法1:使用命令行工具(快速查看) 1. **`ps` 命令(推荐)** 显示所有Python进程的CPU内存占用: ```bash ps aux | grep ' python' | grep -v grep ``` - `%CPU`列:进程占用CPU百分比 - `%MEM`列:进程占用内存百分比 - `RSS`列:实际物理内存用量(KB) - 示例输出: ``` user 1234 0.5 2.1 10240 21000 ? S 12:00 0:10 python app.py ``` 2. **`top` 命令(实时监控)** 动态查看Python进程资源占用: ```bash top -p $(pgrep -d ',' python) ``` - 按 `Shift+M` 按内存排序 - 按 `P` 按CPU排序 - 按 `q` 退出 3. **按内存排序查看** ```bash ps -eo pid,user,%cpu,%mem,rss,cmd --sort=-%mem | grep python ``` --- ### 方法2:使用Python脚本(详细监控) 通过`psutil`库获取更详细信息(需先安装:`pip install psutil`): ```python import psutil def find_python_procs(): """找出所有Python进程并显示资源占用""" print("PID\tCPU%\tMEM%\t内存(MB)\t命令") for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'cpu_percent', 'memory_percent', 'memory_info']): try: # 识别Python进程 if 'python' in proc.info['name'].lower() or \ (proc.info['cmdline'] and 'python' in proc.info['cmdline'][0].lower()): # 获取CPU内存数据 cpu = proc.cpu_percent(interval=0.1) mem = proc.memory_percent() rss_mb = proc.memory_info().rss / 1024 / 1024 # 转MB print(f"{proc.pid}\t{cpu:.1f}\t{mem:.2f}\t{rss_mb:.2f}\t\t{' '.join(proc.info['cmdline'])}") except (psutil.NoSuchProcess, psutil.AccessDenied): continue if __name__ == "__main__": find_python_procs() ``` 输出示例: ``` PID CPU% MEM% 内存(MB) 命令 1234 25.5 1.23 152.34 python data_processor.py 5678 12.1 0.87 98.21 /usr/bin/python3 api_server.py ``` --- ### 方法3:通过进程文件系统(无需额外工具) 查看所有Python进程的内存映射: ```bash sudo grep -s '^Pss' /proc/[0-9]*/smaps | awk -F: '{pid=$1; gsub(/[^0-9]/, "", pid); cmd="ps -p "pid" -o cmd="; cmd | getline exe; close(cmd); sum[exe]+=$2} END {for(i in sum) printf "%8d MB %s\n", sum[i]/1024, i}' | grep python ``` --- ### 注意事项 1. **权限问题** - 普通用户只能查看自己的进程 - 系统级监控需使用 `sudo` 2. **容器环境** 若Python任务运行在Docker中,需进入容器执行: ```bash docker exec -it <容器名> ps aux | grep python ``` 3. **资源计算** - `RSS` (Resident Set Size):进程实际占用的物理内存 - `%MEM` = `(RSS / 总物理内存) * 100` > 推荐优先使用 `ps` 命令快速检查,需要详细分析时使用Python脚本或 `top` 实时监控[^2][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

inter_peng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值