From f4f5475ffb63e2d9409404b6655e81be51ec00de Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 14 May 2026 14:48:48 +0800 Subject: [PATCH] =?UTF-8?q?v0.0.3:=20=E4=BF=AE=E5=A4=8DCPU/=E5=86=85?= =?UTF-8?q?=E5=AD=98=E6=98=BE=E7=A4=BA=20-=20=E5=88=97=E8=A1=A8=E5=92=8C?= =?UTF-8?q?=E4=BB=AA=E8=A1=A8=E7=9B=98=E6=98=BE=E7=A4=BA=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E9=87=8F/=E6=80=BB=E9=87=8F=E6=A0=BC=E5=BC=8F=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AF=A6=E6=83=85=E9=A1=B5CPU=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=8E=B7=E5=8F=96bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/routers/monitor.py | 47 +++++++++++++++++++++++++++----- backend/app/routers/vm.py | 18 ++++++++++-- frontend/src/views/Dashboard.vue | 26 ++++++++++++++++-- frontend/src/views/VMList.vue | 20 ++++++++++++-- 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/backend/app/routers/monitor.py b/backend/app/routers/monitor.py index be6621e..c4d3ffe 100644 --- a/backend/app/routers/monitor.py +++ b/backend/app/routers/monitor.py @@ -112,32 +112,65 @@ async def monitor_vm(name: str, host_id: str = Query("local")): def _get_vm_cpu_percent(dom, cache_key: str) -> float: - """计算虚拟机 CPU 使用率""" + """计算虚拟机 CPU 使用率(归一化到 0-100%,基于 vCPU 数量)""" try: + # dom.info() 返回: [state, maxMem, memory, nrVirtCpu, cpuTime] info1 = dom.info() - cpu_time1 = info1[2] + cpu_time1 = info1[4] # cpuTime 在索引4(之前错误地用了索引2=memory) + nr_vcpu = info1[3] or 1 # vCPU 数量 t1 = time.time() with _cache_lock: prev = _stats_cache.get(cache_key) if prev: - cpu_time0, t0 = prev + cpu_time0, t0, prev_vcpu = prev elapsed = t1 - t0 - cpu_diff = cpu_time1 - cpu_time0 - cpu_percent = round((cpu_diff / 1e9) / elapsed * 100, 1) - cpu_percent = min(cpu_percent, 100.0) + if elapsed > 0: + cpu_diff = cpu_time1 - cpu_time0 + # 除以 vCPU 数量归一化,使满载时 = 100% + cpu_percent = round((cpu_diff / 1e9) / elapsed / nr_vcpu * 100, 1) + cpu_percent = max(0.0, min(cpu_percent, 100.0)) + else: + cpu_percent = 0.0 else: cpu_percent = 0.0 with _cache_lock: - _stats_cache[cache_key] = (cpu_time1, t1) + _stats_cache[cache_key] = (cpu_time1, t1, nr_vcpu) return cpu_percent except Exception: return 0.0 +def get_vm_runtime_stats(dom, cache_key: str) -> dict: + """获取虚拟机运行时统计(供其他模块调用,如 VM 列表页) + + Returns: + dict: { cpu_percent, memory: { rss_mb, actual_mb, usage_percent } } + """ + if not dom.isActive(): + return {"cpu_percent": 0, "memory": {}} + + cpu_percent = _get_vm_cpu_percent(dom, cache_key) + + mem_stats = {} + try: + raw = dom.memoryStats() + mem_stats = { + "rss_mb": raw.get("rss", 0) // 1024 if "rss" in raw else 0, + "actual_mb": raw.get("actual", 0) // 1024 if "actual" in raw else 0, + "usage_percent": round( + raw.get("rss", 0) / raw.get("actual", 1) * 100, 1 + ) if "rss" in raw and "actual" in raw else 0, + } + except Exception: + pass + + return {"cpu_percent": cpu_percent, "memory": mem_stats} + + def _get_vm_disk_stats(dom) -> list: """获取虚拟机磁盘IO""" from lxml import etree diff --git a/backend/app/routers/vm.py b/backend/app/routers/vm.py index 1a8cba3..3b07a77 100644 --- a/backend/app/routers/vm.py +++ b/backend/app/routers/vm.py @@ -8,6 +8,7 @@ import os from app.libvirt_conn import conn_pool from app.utils import parse_vm_info, generate_vm_xml +from app.routers.monitor import get_vm_runtime_stats import libvirt router = APIRouter() @@ -45,6 +46,12 @@ async def list_vms(host_id: str = Query("local"), include_ip: bool = False): for dom in domains: try: vm_info = parse_vm_info(dom, host_id, include_ip=include_ip) + # 添加运行时统计(CPU使用率、内存使用量) + cache_key = f"{host_id}_{vm_info['name']}" + runtime = get_vm_runtime_stats(dom, cache_key) + vm_info["cpu_percent"] = runtime["cpu_percent"] + vm_info["memory_rss_mb"] = runtime["memory"].get("rss_mb", 0) + vm_info["memory_usage_percent"] = runtime["memory"].get("usage_percent", 0) vms.append(vm_info) except Exception as e: vms.append({ @@ -71,6 +78,12 @@ async def list_all_vms(include_ip: bool = False): vm_info = parse_vm_info(dom, host.id, include_ip=include_ip) vm_info["host_id"] = host.id vm_info["host_name"] = host.name + # 添加运行时统计 + cache_key = f"{host.id}_{vm_info['name']}" + runtime = get_vm_runtime_stats(dom, cache_key) + vm_info["cpu_percent"] = runtime["cpu_percent"] + vm_info["memory_rss_mb"] = runtime["memory"].get("rss_mb", 0) + vm_info["memory_usage_percent"] = runtime["memory"].get("usage_percent", 0) all_vms.append(vm_info) except Exception: all_vms.append({ @@ -100,8 +113,9 @@ async def get_vm_detail(name: str, host_id: str = Query("local")): # 运行中的虚拟机获取更多动态信息 if info["state"] == "running": try: - _, _, cpu_time, _ = dom.info() - info["cpu_time_ns"] = cpu_time + # dom.info(): [state, maxMem, memory, nrVirtCpu, cpuTime] + dom_info = dom.info() + info["cpu_time_ns"] = dom_info[4] # cpuTime 在索引4 except Exception: pass diff --git a/frontend/src/views/Dashboard.vue b/frontend/src/views/Dashboard.vue index 2cab734..31578f8 100644 --- a/frontend/src/views/Dashboard.vue +++ b/frontend/src/views/Dashboard.vue @@ -63,9 +63,23 @@ - - - + + + + + - - - + + + + +