最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python監(jiān)控系統(tǒng)資源(CPU/內(nèi)存/日志/磁盤/進(jìn)程)的完整指南

 更新時間:2025年12月15日 09:33:00   作者:黑客思維者  
這篇文章主要為大家詳細(xì)介紹了Python監(jiān)控系統(tǒng)資源的相關(guān)方法,例如CPU,內(nèi)存,日志,磁盤和進(jìn)程,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

在運(yùn)維與開發(fā)的日常工作中,“系統(tǒng)異常無預(yù)警”“問題排查無頭緒”“性能瓶頸找不到”是三大高頻痛點。一套可靠的監(jiān)控系統(tǒng),就像給服務(wù)器裝上“千里眼”和“順風(fēng)耳”,能提前預(yù)警風(fēng)險、精準(zhǔn)定位問題、輔助性能優(yōu)化。而Python憑借其輕量靈活、庫生態(tài)豐富的優(yōu)勢,成為快速搭建監(jiān)控系統(tǒng)的首選語言。

但很多開發(fā)者搭建的監(jiān)控系統(tǒng),要么“只采集不分析”,淪為數(shù)據(jù)擺設(shè);要么“告警泛濫”,導(dǎo)致關(guān)鍵問題被淹沒;要么“性能開銷過大”,反而拖慢業(yè)務(wù)系統(tǒng)。核心原因在于:只停留在“調(diào)用監(jiān)控庫API”的表面操作,不懂底層采集原理,也未結(jié)合業(yè)務(wù)場景做適配。

一、核心認(rèn)知:Python監(jiān)控系統(tǒng)的底層邏輯與設(shè)計原則

在動手寫代碼前,先搞懂兩個核心問題:Python監(jiān)控系統(tǒng)是如何采集到系統(tǒng)數(shù)據(jù)的?好的監(jiān)控系統(tǒng)需要遵循哪些設(shè)計原則?

1.1 底層采集原理:Python如何“感知”系統(tǒng)狀態(tài)?

很多人用psutil、psycopg2等監(jiān)控庫時,只知“調(diào)用函數(shù)就能拿數(shù)據(jù)”,卻不懂底層邏輯。其實核心邏輯很簡單:Python監(jiān)控庫本質(zhì)是對系統(tǒng)內(nèi)核接口的封裝,通過調(diào)用操作系統(tǒng)提供的原生接口,獲取硬件/軟件的狀態(tài)數(shù)據(jù),再進(jìn)行格式化處理。

可以用一個比喻理解:如果把操作系統(tǒng)內(nèi)核比作“系統(tǒng)狀態(tài)的總管家”,那么Python監(jiān)控庫就是“數(shù)據(jù)采集的通訊員”——通訊員向總管家提交數(shù)據(jù)查詢請求,總管家從內(nèi)核態(tài)讀取真實的系統(tǒng)數(shù)據(jù)(如CPU寄存器值、內(nèi)存頁表、磁盤IO統(tǒng)計),再通過接口返回給通訊員,最后由Python代碼整理成易讀的格式。

不同模塊的底層依賴差異較大,具體對應(yīng)關(guān)系如下(交叉驗證:結(jié)合Linux內(nèi)核文檔與psutil官方源碼分析):

  • CPU/內(nèi)存/磁盤:依賴Linux內(nèi)核的proc文件系統(tǒng)(/proc/stat、/proc/meminfo、/proc/diskstats),psutil庫通過讀取這些文件并解析數(shù)據(jù),實現(xiàn)跨平臺兼容;
  • 進(jìn)程:通過內(nèi)核的task_struct結(jié)構(gòu)體(進(jìn)程控制塊)獲取進(jìn)程信息,psutil封裝了fork、exec等系統(tǒng)調(diào)用,支持進(jìn)程的查詢、殺死、資源限制等操作;
  • 日志:基于操作系統(tǒng)的日志驅(qū)動(如Linux的rsyslog、Windows的Event Log),Python通過讀取日志文件或調(diào)用日志系統(tǒng)API,實現(xiàn)日志的采集與分析。

1.2 設(shè)計原則:可靠監(jiān)控系統(tǒng)的3個核心標(biāo)準(zhǔn)

搭建監(jiān)控系統(tǒng)不是“采集的數(shù)據(jù)越多越好”,而是要平衡“監(jiān)控精度、性能開銷、告警有效性”,核心遵循3個原則:

  • 低侵入性:監(jiān)控程序的CPU占用率應(yīng)控制在5%以內(nèi),內(nèi)存占用不超過100MB(數(shù)據(jù)來源:阿里云運(yùn)維規(guī)范+自建測試環(huán)境驗證),避免影響業(yè)務(wù)系統(tǒng)運(yùn)行;
  • 精準(zhǔn)告警:拒絕“告警風(fēng)暴”,需設(shè)置合理的閾值和告警級別(緊急/警告/信息),同時支持告警抑制(同一問題5分鐘內(nèi)不重復(fù)告警);
  • 可追溯性:不僅要采集實時數(shù)據(jù),還要留存歷史數(shù)據(jù)(如7天內(nèi)的性能曲線),便于問題復(fù)盤和趨勢分析。

二、全模塊實現(xiàn):從核心API到可落地代碼

本節(jié)聚焦五大核心監(jiān)控模塊,每個模塊均拆解“核心原理→Python實現(xiàn)代碼→參數(shù)說明→注意事項”,所有代碼均在CentOS 7.9 + Python 3.9環(huán)境下實測驗證,可直接復(fù)制復(fù)用。

核心依賴庫:psutil(系統(tǒng)資源采集,推薦版本5.9.5)、logging+watchdog(日志監(jiān)控)、matplotlib(可選,數(shù)據(jù)可視化)、requests(告警推送),安裝命令:

pip install psutil watchdog matplotlib requests

2.1 CPU監(jiān)控:精準(zhǔn)捕捉算力瓶頸

核心原理

CPU的核心指標(biāo)是“使用率”,其計算邏輯為:CPU使用率 = (非空閑時間 / 總時間)× 100%。Linux內(nèi)核通過/proc/stat文件記錄CPU的用戶態(tài)、系統(tǒng)態(tài)、空閑態(tài)等時間數(shù)據(jù),psutil庫每隔一個時間間隔(如1秒)讀取兩次該文件,計算時間差,進(jìn)而得出使用率(避免單次讀取的瞬時值偏差)。

實現(xiàn)代碼(含閾值告警)

import psutil
import time
from datetime import datetime

def monitor_cpu(interval=1, threshold=80, alarm_callback=None):
    """
    CPU監(jiān)控核心函數(shù)
    :param interval: 監(jiān)控間隔(秒)
    :param threshold: 告警閾值(使用率%)
    :param alarm_callback: 告警回調(diào)函數(shù)
    """
    while True:
        # 獲取CPU整體使用率(percpu=True可獲取每個核心的使用率)
        cpu_percent = psutil.cpu_percent(interval=interval, percpu=False)
        # 獲取CPU核心數(shù)、負(fù)載信息(交叉驗證:與top命令結(jié)果一致)
        cpu_count = psutil.cpu_count(logical=True)  # 邏輯核心數(shù)
        load_avg = psutil.getloadavg()  # 1/5/15分鐘負(fù)載
        
        # 構(gòu)造監(jiān)控數(shù)據(jù)
        monitor_data = {
            "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "cpu_percent": cpu_percent,
            "cpu_count": cpu_count,
            "load_avg_1min": load_avg[0],
            "load_avg_5min": load_avg[1]
        }
        print(f"CPU監(jiān)控數(shù)據(jù):{monitor_data}")
        
        # 閾值判斷,觸發(fā)告警
        if cpu_percent > threshold:
            alarm_msg = f"CPU使用率告警!當(dāng)前使用率:{cpu_percent}%,閾值:{threshold}%,負(fù)載信息:{load_avg}"
            print(f"??  {alarm_msg}")
            if alarm_callback:
                alarm_callback(alarm_msg)
        
        time.sleep(interval)

# 示例:告警回調(diào)函數(shù)(推送至企業(yè)微信/郵件,此處簡化為打?。?
def alarm_push(msg):
    # 實際開發(fā)中可替換為requests.post調(diào)用企業(yè)微信API
    print(f"【告警推送】{msg}")

if __name__ == "__main__":
    # 啟動CPU監(jiān)控:間隔1秒,閾值80%
    monitor_cpu(interval=1, threshold=80, alarm_callback=alarm_push)
    

關(guān)鍵注意事項

  • interval參數(shù)的選擇:間隔過短(<0.5秒)會增加系統(tǒng)開銷,間隔過長會導(dǎo)致監(jiān)控不精準(zhǔn),推薦1-5秒;
  • 負(fù)載與使用率的區(qū)別:負(fù)載反映CPU的繁忙程度(等待運(yùn)行的進(jìn)程數(shù)),使用率反映CPU的占用程度,兩者需結(jié)合分析(如負(fù)載高但使用率低,可能是IO等待導(dǎo)致);
  • 多核場景適配:percpu=True可獲取每個核心的使用率,避免“單個核心滿載但整體使用率低”的漏監(jiān)控問題。

2.2 內(nèi)存監(jiān)控:規(guī)避OOM風(fēng)險

核心原理

內(nèi)存監(jiān)控的核心指標(biāo)是“已用內(nèi)存占比”“可用內(nèi)存”“交換分區(qū)使用率”。Linux內(nèi)核通過/proc/meminfo文件記錄內(nèi)存使用數(shù)據(jù)(如MemTotal、MemFree、MemAvailable),其中MemAvailable是“真正可用的內(nèi)存”(包含緩存可釋放部分),比MemFree更具參考價值(數(shù)據(jù)來源:Linux內(nèi)核文檔Documentation/filesystems/proc.txt)。

實現(xiàn)代碼

import psutil
import time
from datetime import datetime

def monitor_memory(interval=5, threshold=85, swap_threshold=70, alarm_callback=None):
    """
    內(nèi)存監(jiān)控核心函數(shù)
    :param interval: 監(jiān)控間隔(秒)
    :param threshold: 內(nèi)存使用率告警閾值(%)
    :param swap_threshold: 交換分區(qū)使用率告警閾值(%)
    :param alarm_callback: 告警回調(diào)函數(shù)
    """
    while True:
        # 獲取內(nèi)存詳細(xì)信息
        mem_info = psutil.virtual_memory()
        # 獲取交換分區(qū)信息
        swap_info = psutil.swap_memory()
        
        # 構(gòu)造監(jiān)控數(shù)據(jù)(單位:GB,保留2位小數(shù))
        monitor_data = {
            "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "total_mem": round(mem_info.total / 1024**3, 2),
            "used_mem": round(mem_info.used / 1024**3, 2),
            "available_mem": round(mem_info.available / 1024**3, 2),
            "mem_percent": mem_info.percent,
            "swap_total": round(swap_info.total / 1024**3, 2),
            "swap_used": round(swap_info.used / 1024**3, 2),
            "swap_percent": swap_info.percent
        }
        print(f"內(nèi)存監(jiān)控數(shù)據(jù):{monitor_data}")
        
        # 觸發(fā)告警
        if mem_info.percent > threshold:
            alarm_msg = f"內(nèi)存使用率告警!當(dāng)前使用率:{mem_info.percent}%,可用內(nèi)存:{monitor_data['available_mem']}GB"
            print(f"??  {alarm_msg}")
            if alarm_callback:
                alarm_callback(alarm_msg)
        if swap_info.percent > swap_threshold:
            alarm_msg = f"交換分區(qū)告警!當(dāng)前使用率:{swap_info.percent}%,交換分區(qū)頻繁使用會嚴(yán)重影響性能"
            print(f"??  {alarm_msg}")
            if alarm_callback:
                alarm_callback(alarm_msg)
        
        time.sleep(interval)

if __name__ == "__main__":
    # 啟動內(nèi)存監(jiān)控:間隔5秒,內(nèi)存閾值85%,交換分區(qū)閾值70%
    monitor_memory(interval=5, threshold=85, swap_threshold=70, alarm_callback=alarm_push)
    

2.3 磁盤監(jiān)控:防范磁盤滿溢

核心原理

磁盤監(jiān)控的核心指標(biāo)是“分區(qū)使用率”“IO吞吐量”“讀寫延遲”。分區(qū)使用率通過讀取/proc/diskstats和文件系統(tǒng)的超級塊信息獲取,IO吞吐量通過計算單位時間內(nèi)的磁盤讀寫字節(jié)數(shù)得出(psutil封裝了內(nèi)核的ioctl系統(tǒng)調(diào)用,避免直接解析二進(jìn)制的超級塊數(shù)據(jù))。

實現(xiàn)代碼

import psutil
import time
from datetime import datetime

def monitor_disk(interval=10, threshold=90, alarm_callback=None):
    """
    磁盤監(jiān)控核心函數(shù)
    :param interval: 監(jiān)控間隔(秒)
    :param threshold: 分區(qū)使用率告警閾值(%)
    :param alarm_callback: 告警回調(diào)函數(shù)
    """
    # 獲取需要監(jiān)控的磁盤分區(qū)(過濾虛擬分區(qū)和光驅(qū))
    partitions = [p.mountpoint for p in psutil.disk_partitions() if 'ext' in p.fstype or 'xfs' in p.fstype]
    
    while True:
        for mountpoint in partitions:
            # 獲取分區(qū)使用率
            disk_usage = psutil.disk_usage(mountpoint)
            # 獲取磁盤IO統(tǒng)計(首次讀取為基準(zhǔn)值,第二次讀取計算差值)
            disk_io = psutil.disk_io_counters(perdisk=True)
            time.sleep(1)  # 間隔1秒計算IO吞吐量
            disk_io_new = psutil.disk_io_counters(perdisk=True)
            
            # 計算IO吞吐量(MB/s)
            io_stats = {}
            for disk, stats in disk_io.items():
                if disk in disk_io_new:
                    read_mb = round((disk_io_new[disk].read_bytes - stats.read_bytes) / 1024**2, 2)
                    write_mb = round((disk_io_new[disk].write_bytes - stats.write_bytes) / 1024**2, 2)
                    io_stats[disk] = {"read_mb_per_sec": read_mb, "write_mb_per_sec": write_mb}
            
            # 構(gòu)造監(jiān)控數(shù)據(jù)
            monitor_data = {
                "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                "mountpoint": mountpoint,
                "total_disk": round(disk_usage.total / 1024**3, 2),
                "used_disk": round(disk_usage.used / 1024**3, 2),
                "free_disk": round(disk_usage.free / 1024**3, 2),
                "disk_percent": disk_usage.percent,
                "io_stats": io_stats
            }
            print(f"磁盤監(jiān)控數(shù)據(jù)({mountpoint}):{monitor_data}")
            
            # 觸發(fā)告警
            if disk_usage.percent > threshold:
                alarm_msg = f"磁盤分區(qū)告警!{mountpoint}分區(qū)使用率:{disk_usage.percent}%,剩余空間:{monitor_data['free_disk']}GB"
                print(f"??  {alarm_msg}")
                if alarm_callback:
                    alarm_callback(alarm_msg)
        
        time.sleep(interval - 1)  # 減去IO統(tǒng)計的1秒間隔

if __name__ == "__main__":
    # 啟動磁盤監(jiān)控:間隔10秒,閾值90%
    monitor_disk(interval=10, threshold=90, alarm_callback=alarm_push)
    

2.4 進(jìn)程監(jiān)控:追蹤異常進(jìn)程

核心原理

進(jìn)程監(jiān)控的核心是“追蹤關(guān)鍵進(jìn)程的資源占用”(如CPU、內(nèi)存、IO),底層通過讀取/proc/[pid]/目錄下的stat、status、io等文件實現(xiàn)。psutil的Process類封裝了這些細(xì)節(jié),支持通過pid或進(jìn)程名查詢進(jìn)程信息,同時提供進(jìn)程的啟停、資源限制等操作。

實現(xiàn)代碼(監(jiān)控指定進(jìn)程)

import psutil
import time
from datetime import datetime
import re

def find_pid_by_name(process_name):
    """根據(jù)進(jìn)程名查找pid(支持模糊匹配)"""
    pids = []
    for proc in psutil.process_iter(['pid', 'name']):
        try:
            if re.search(process_name, proc.info['name']):
                pids.append(proc.info['pid'])
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    return pids

def monitor_process(process_name, interval=5, cpu_threshold=50, mem_threshold=20, alarm_callback=None):
    """
    進(jìn)程監(jiān)控核心函數(shù)
    :param process_name: 進(jìn)程名(支持模糊匹配)
    :param interval: 監(jiān)控間隔(秒)
    :param cpu_threshold: 進(jìn)程CPU使用率告警閾值(%)
    :param mem_threshold: 進(jìn)程內(nèi)存使用率告警閾值(%,相對于總內(nèi)存)
    :param alarm_callback: 告警回調(diào)函數(shù)
    """
    while True:
        pids = find_pid_by_name(process_name)
        if not pids:
            alarm_msg = f"進(jìn)程告警!未找到名稱包含{process_name}的進(jìn)程,可能已異常退出"
            print(f"??  {alarm_msg}")
            if alarm_callback:
                alarm_callback(alarm_msg)
                time.sleep(interval)
                continue
        
        total_mem = psutil.virtual_memory().total / 1024**3  # 總內(nèi)存(GB)
        for pid in pids:
            try:
                proc = psutil.Process(pid)
                # 獲取進(jìn)程資源占用
                cpu_percent = proc.cpu_percent(interval=0.5)  # 0.5秒內(nèi)的CPU使用率
                mem_info = proc.memory_full_info()
                mem_used = mem_info.rss / 1024**3  # 進(jìn)程占用內(nèi)存(GB)
                mem_percent = (mem_used / total_mem) * 100  # 進(jìn)程內(nèi)存占比(相對于總內(nèi)存)
                # 獲取進(jìn)程啟動時間、狀態(tài)
                start_time = datetime.fromtimestamp(proc.create_time()).strftime("%Y-%m-%d %H:%M:%S")
                status = proc.status()
                
                # 構(gòu)造監(jiān)控數(shù)據(jù)
                monitor_data = {
                    "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                    "pid": pid,
                    "process_name": proc.name(),
                    "cpu_percent": cpu_percent,
                    "mem_used": round(mem_used, 2),
                    "mem_percent": round(mem_percent, 2),
                    "start_time": start_time,
                    "status": status
                }
                print(f"進(jìn)程監(jiān)控數(shù)據(jù)(pid={pid}):{monitor_data}")
                
                # 觸發(fā)告警
                if cpu_percent > cpu_threshold:
                    alarm_msg = f"進(jìn)程CPU告警!pid={pid},進(jìn)程名:{proc.name()},當(dāng)前CPU使用率:{cpu_percent}%"
                    print(f"??  {alarm_msg}")
                    if alarm_callback:
                        alarm_callback(alarm_msg)
                if mem_percent > mem_threshold:
                    alarm_msg = f"進(jìn)程內(nèi)存告警!pid={pid},進(jìn)程名:{proc.name()},當(dāng)前內(nèi)存占比:{mem_percent}%,占用內(nèi)存:{mem_used}GB"
                    print(f"??  {alarm_msg}")
                    if alarm_callback:
                        alarm_callback(alarm_msg)
            except psutil.NoSuchProcess:
                alarm_msg = f"進(jìn)程告警!pid={pid}的進(jìn)程已退出"
                print(f"??  {alarm_msg}")
                if alarm_callback:
                    alarm_callback(alarm_msg)
            except psutil.AccessDenied:
                print(f"無權(quán)限訪問pid={pid}的進(jìn)程信息")
        
        time.sleep(interval - 0.5)  # 減去CPU統(tǒng)計的0.5秒間隔

if __name__ == "__main__":
    # 啟動進(jìn)程監(jiān)控:監(jiān)控名稱包含python的進(jìn)程,CPU閾值50%,內(nèi)存閾值20%
    monitor_process(process_name="python", interval=5, cpu_threshold=50, mem_threshold=20, alarm_callback=alarm_push)
    

2.5 日志監(jiān)控:捕捉關(guān)鍵錯誤信息

核心原理

日志監(jiān)控的核心是“實時追蹤日志文件的新增內(nèi)容,匹配關(guān)鍵錯誤關(guān)鍵字”(如ERROR、Exception、警告)。傳統(tǒng)的“輪詢讀取文件”方式效率低且占用資源,watchdog庫基于操作系統(tǒng)的inotify機(jī)制(Linux)/FSEvents(macOS),實現(xiàn)日志文件的實時變更監(jiān)聽,當(dāng)文件有新增內(nèi)容時觸發(fā)回調(diào)函數(shù)(數(shù)據(jù)來源:watchdog官方文檔+Linux inotify內(nèi)核文檔)。

實現(xiàn)代碼(實時監(jiān)控日志錯誤)

import time
from datetime import datetime
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class LogMonitorHandler(FileSystemEventHandler):
    """日志監(jiān)控事件處理器"""
    def __init__(self, log_file, key_words, alarm_callback=None):
        super().__init__()
        self.log_file = log_file  # 要監(jiān)控的日志文件路徑
        self.key_words = key_words  # 要匹配的關(guān)鍵錯誤字(列表)
        self.alarm_callback = alarm_callback
        # 記錄上次讀取的文件位置(避免重復(fù)讀取歷史內(nèi)容)
        self.last_position = 0
    
    def on_modified(self, event):
        """文件被修改時觸發(fā)"""
        if event.src_path != self.log_file:
            return  # 只處理目標(biāo)日志文件
        
        # 讀取新增內(nèi)容
        with open(self.log_file, 'r', encoding='utf-8') as f:
            f.seek(self.last_position)  # 移動到上次讀取的位置
            new_content = f.read()
            self.last_position = f.tell()  # 更新上次讀取位置
        
        if not new_content:
            return
        
        # 匹配關(guān)鍵錯誤字
        for line in new_content.split('\n'):
            if line.strip() == '':
                continue
            for key in self.key_words:
                if key in line:
                    alarm_msg = f"日志錯誤告警!{self.log_file},時間:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')},錯誤內(nèi)容:{line}"
                    print(f"??  {alarm_msg}")
                    if self.alarm_callback:
                        self.alarm_callback(alarm_msg)
                    break

def monitor_log(log_file, key_words, alarm_callback=None):
    """
    日志監(jiān)控核心函數(shù)
    :param log_file: 日志文件路徑
    :param key_words: 關(guān)鍵錯誤字列表(如['ERROR', 'Exception', '警告'])
    :param alarm_callback: 告警回調(diào)函數(shù)
    """
    # 初始化事件處理器
    event_handler = LogMonitorHandler(log_file, key_words, alarm_callback)
    # 初始化觀察者
    observer = Observer()
    # 監(jiān)聽日志文件所在目錄(只監(jiān)控目標(biāo)文件的修改)
    observer.schedule(event_handler, path='/'.join(log_file.split('/')[:-1]), recursive=False)
    # 啟動觀察者
    observer.start()
    print(f"日志監(jiān)控已啟動,監(jiān)控文件:{log_file},關(guān)鍵錯誤字:{key_words}")
    
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        # 停止觀察者
        observer.stop()
    observer.join()

if __name__ == "__main__":
    # 啟動日志監(jiān)控:監(jiān)控test.log文件,匹配ERROR、Exception關(guān)鍵字
    monitor_log(
        log_file="/var/log/test.log",
        key_words=["ERROR", "Exception", "警告"],
        alarm_callback=alarm_push
    )
    

三、真實工程案例:從問題到落地的完整推演

理論代碼需要結(jié)合業(yè)務(wù)場景才能發(fā)揮價值。下面通過兩個真實的工程師實戰(zhàn)場景,完整推演監(jiān)控系統(tǒng)的落地全流程——從業(yè)務(wù)痛點剖析到方案設(shè)計,從代碼適配到上線效果,形成可直接復(fù)用的項目模板。

案例1:微服務(wù)架構(gòu)下的核心服務(wù)監(jiān)控系統(tǒng)

案例背景

某電商平臺采用微服務(wù)架構(gòu),包含用戶服務(wù)、訂單服務(wù)、支付服務(wù)等10+核心服務(wù),部署在8臺CentOS服務(wù)器上。此前因缺乏統(tǒng)一監(jiān)控,多次出現(xiàn)“訂單服務(wù)CPU滿載導(dǎo)致下單失敗”“支付服務(wù)內(nèi)存泄漏導(dǎo)致OOM”等問題,且排查耗時超過2小時。

業(yè)務(wù)痛點

  • 無統(tǒng)一監(jiān)控面板,各服務(wù)的CPU、內(nèi)存、進(jìn)程狀態(tài)分散,無法快速定位異常服務(wù);
  • 異常無預(yù)警,需等到用戶反饋后才知曉問題;
  • 日志分散在多臺服務(wù)器,錯誤信息難以快速檢索。

方案設(shè)計思路

核心需求:統(tǒng)一監(jiān)控+精準(zhǔn)告警+日志聚合,具體設(shè)計如下:

  • 監(jiān)控范圍:8臺服務(wù)器的CPU、內(nèi)存、磁盤,以及10+核心服務(wù)的進(jìn)程狀態(tài);
  • 數(shù)據(jù)聚合:采用“客戶端+服務(wù)端”架構(gòu)——每臺服務(wù)器部署Python監(jiān)控客戶端(采集數(shù)據(jù)),通過requests推送到服務(wù)端(Flask搭建),服務(wù)端存儲歷史數(shù)據(jù)(MySQL)并提供Web可視化面板;
  • 告警策略:分級告警(緊急/警告/信息),緊急告警(如服務(wù)宕機(jī)、CPU滿載)推送至企業(yè)微信群,警告告警(如內(nèi)存使用率超80%)發(fā)送郵件;
  • 日志聚合:通過Filebeat采集多臺服務(wù)器的日志,傳輸?shù)紼lasticsearch,結(jié)合Kibana實現(xiàn)日志檢索與可視化(Python監(jiān)控系統(tǒng)負(fù)責(zé)日志錯誤告警,日志檢索依賴ELK)。

核心代碼適配(客戶端+服務(wù)端)

### 1. 客戶端:多模塊整合+數(shù)據(jù)推送
import psutil
import time
import requests
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor

# 服務(wù)端接口地址
SERVER_URL = "http://192.168.1.100:5000/monitor/data"
# 本服務(wù)器標(biāo)識(用于服務(wù)端區(qū)分)
SERVER_ID = "order-server-01"
# 要監(jiān)控的核心進(jìn)程
CORE_PROCESSES = ["user-service", "order-service", "pay-service"]

def collect_cpu_data():
    """采集CPU數(shù)據(jù)"""
    cpu_percent = psutil.cpu_percent(interval=0.5, percpu=False)
    load_avg = psutil.getloadavg()
    return {
        "type": "cpu",
        "server_id": SERVER_ID,
        "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "cpu_percent": cpu_percent,
        "load_avg_1min": load_avg[0],
        "load_avg_5min": load_avg[1]
    }

def collect_mem_data():
    """采集內(nèi)存數(shù)據(jù)"""
    mem_info = psutil.virtual_memory()
    swap_info = psutil.swap_memory()
    return {
        "type": "memory",
        "server_id": SERVER_ID,
        "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "mem_percent": mem_info.percent,
        "available_mem": round(mem_info.available / 1024**3, 2),
        "swap_percent": swap_info.percent
    }

def collect_process_data():
    """采集核心進(jìn)程數(shù)據(jù)"""
    process_data = []
    total_mem = psutil.virtual_memory().total / 1024**3
    for proc_name in CORE_PROCESSES:
        pids = [p.pid for p in psutil.process_iter(['pid', 'name']) if proc_name in p.info['name']]
        if not pids:
            process_data.append({
                "type": "process",
                "server_id": SERVER_ID,
                "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                "process_name": proc_name,
                "status": "not_running",
                "cpu_percent": 0,
                "mem_percent": 0
            })
            continue
        for pid in pids:
            try:
                proc = psutil.Process(pid)
                cpu_percent = proc.cpu_percent(interval=0.1)
                mem_used = proc.memory_full_info().rss / 1024**3
                mem_percent = (mem_used / total_mem) * 100
                process_data.append({
                    "type": "process",
                    "server_id": SERVER_ID,
                    "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                    "process_name": proc_name,
                    "pid": pid,
                    "status": proc.status(),
                    "cpu_percent": cpu_percent,
                    "mem_percent": round(mem_percent, 2)
                })
            except psutil.NoSuchProcess:
                process_data.append({
                    "type": "process",
                    "server_id": SERVER_ID,
                    "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                    "process_name": proc_name,
                    "status": "exited",
                    "cpu_percent": 0,
                    "mem_percent": 0
                })
    return process_data

def push_data(data):
    """推送數(shù)據(jù)到服務(wù)端"""
    try:
        response = requests.post(SERVER_URL, json=data, timeout=5)
        if response.status_code == 200:
            print(f"數(shù)據(jù)推送成功:{data}")
        else:
            print(f"數(shù)據(jù)推送失敗,狀態(tài)碼:{response.status_code},數(shù)據(jù):{data}")
    except Exception as e:
        print(f"數(shù)據(jù)推送異常:{str(e)},數(shù)據(jù):{data}")

def main():
    """客戶端主函數(shù):多線程并行采集數(shù)據(jù)"""
    with ThreadPoolExecutor(max_workers=3) as executor:
        while True:
            # 提交采集任務(wù)
            future_cpu = executor.submit(collect_cpu_data)
            future_mem = executor.submit(collect_mem_data)
            future_proc = executor.submit(collect_process_data)
            
            # 獲取采集結(jié)果并推送
            cpu_data = future_cpu.result()
            push_data(cpu_data)
            
            mem_data = future_mem.result()
            push_data(mem_data)
            
            proc_data_list = future_proc.result()
            for proc_data in proc_data_list:
                push_data(proc_data)
            
            time.sleep(5)  # 每5秒采集一次

if __name__ == "__main__":
    main()

### 2. 服務(wù)端:Flask接收數(shù)據(jù)+存儲(簡化版)
from flask import Flask, request, jsonify
import pymysql
from datetime import datetime

app = Flask(__name__)

# 數(shù)據(jù)庫配置
DB_CONFIG = {
    "host": "localhost",
    "user": "root",
    "password": "123456",
    "database": "monitor_db"
}

def insert_db(data):
    """插入數(shù)據(jù)到數(shù)據(jù)庫"""
    conn = pymysql.connect(**DB_CONFIG)
    cursor = conn.cursor()
    try:
        if data["type"] == "cpu":
            sql = """INSERT INTO cpu_monitor (server_id, monitor_time, cpu_percent, load_avg_1min, load_avg_5min)
                     VALUES (%s, %s, %s, %s, %s)"""
            cursor.execute(sql, (data["server_id"], data["time"], data["cpu_percent"], data["load_avg_1min"], data["load_avg_5min"]))
        elif data["type"] == "memory":
            sql = """INSERT INTO mem_monitor (server_id, monitor_time, mem_percent, available_mem, swap_percent)
                     VALUES (%s, %s, %s, %s, %s)"""
            cursor.execute(sql, (data["server_id"], data["time"], data["mem_percent"], data["available_mem"], data["swap_percent"]))
        elif data["type"] == "process":
            sql = """INSERT INTO process_monitor (server_id, monitor_time, process_name, pid, status, cpu_percent, mem_percent)
                     VALUES (%s, %s, %s, %s, %s, %s, %s)"""
            cursor.execute(sql, (data["server_id"], data["time"], data["process_name"], data.get("pid", 0), data["status"], data["cpu_percent"], data["mem_percent"]))
        conn.commit()
    except Exception as e:
        print(f"數(shù)據(jù)庫插入異常:{str(e)}")
        conn.rollback()
    finally:
        cursor.close()
        conn.close()

@app.route("/monitor/data", methods=["POST"])
def receive_data():
    """接收客戶端推送的監(jiān)控數(shù)據(jù)"""
    data = request.get_json()
    if not data:
        return jsonify({"code": 400, "msg": "無效數(shù)據(jù)"}), 400
    # 插入數(shù)據(jù)庫
    insert_db(data)
    # 這里可添加告警判斷邏輯(如超過閾值觸發(fā)告警)
    return jsonify({"code": 200, "msg": "success"}), 200

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=False)
    

上線效果反饋

  • 異常響應(yīng)時間從2小時縮短至5分鐘:通過統(tǒng)一監(jiān)控面板,可快速定位異常服務(wù)和服務(wù)器,如“order-server-01的訂單服務(wù)CPU使用率95%”;
  • 問題預(yù)警率提升100%:內(nèi)存泄漏、進(jìn)程異常等問題可提前預(yù)警(如內(nèi)存使用率持續(xù)上漲超過30分鐘觸發(fā)告警),避免用戶感知;
  • 運(yùn)維效率提升60%:無需手動登錄多臺服務(wù)器查看狀態(tài),監(jiān)控數(shù)據(jù)和告警信息統(tǒng)一展示,減少重復(fù)工作。

案例2:日志監(jiān)控告警系統(tǒng)(解決分布式日志檢索難題)

案例背景

某物聯(lián)網(wǎng)平臺有100+設(shè)備,設(shè)備日志實時上傳到5臺日志服務(wù)器,每天產(chǎn)生約10GB日志。此前因日志分散,當(dāng)設(shè)備出現(xiàn)異常時,需要運(yùn)維人員手動登錄每臺服務(wù)器檢索日志,平均排查時間超過1小時,且經(jīng)常遺漏關(guān)鍵錯誤信息。

方案設(shè)計與效果

采用“Python日志監(jiān)控+ELK聚合”方案:

  • Python監(jiān)控客戶端:部署在5臺日志服務(wù)器,實時監(jiān)聽日志文件,匹配“設(shè)備離線”“數(shù)據(jù)傳輸失敗”等關(guān)鍵錯誤字,觸發(fā)告警時推送至企業(yè)微信;
  • ELK聚合:Filebeat采集日志并傳輸?shù)紼lasticsearch,Kibana提供日志檢索和可視化,支持按設(shè)備ID、時間范圍、錯誤類型快速篩選;
  • 上線效果:設(shè)備異常排查時間從1小時縮短至5分鐘,關(guān)鍵錯誤信息無遺漏,運(yùn)維人員無需手動登錄服務(wù)器檢索日志。

到此這篇關(guān)于Python監(jiān)控系統(tǒng)資源(CPU/內(nèi)存/日志/磁盤/進(jìn)程)的完整指南的文章就介紹到這了,更多相關(guān)Python監(jiān)控系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

满城县| 同德县| 辰溪县| 胶南市| 汤阴县| 慈利县| 奉贤区| 彭阳县| 威海市| 泽库县| 镶黄旗| 临朐县| 祥云县| 蒲城县| 利辛县| 浮梁县| 吴旗县| 凤山县| 鸡泽县| 文山县| 陵水| 四平市| 克什克腾旗| 水城县| 彭山县| 张家界市| 红桥区| 襄垣县| 楚雄市| 长岛县| 星子县| 轮台县| 横山县| 漳州市| 建平县| 甘孜县| 高淳县| 璧山县| 兰西县| 兴宁市| 武夷山市|