在物聯網專案開發中,系統效能監控是確保應用程式穩定性和效率的關鍵環節。本文將探討如何在受限裝置應用程式(CDA)和閘道器裝置應用程式(GDA)中設計和實作系統效能監控功能。首先,我們回顧了軟體設計的三大原則:模組化、介面設計和驗證,這些原則指導我們構建了系統效能管理器。接著,我們逐步展示瞭如何在CDA中實作系統效能監控,包括使用psutil函式庫取得CPU和記憶體使用率,並利用APScheduler實作定時資料採集。此外,我們還闡述瞭如何將這些資料整合到SystemPerformanceManager中,以便統一管理和處理。最後,我們簡要介紹了GDA的系統效能管理元件設計,並強調了其在資料傳輸和雲端整合方面的重要性。
軟體設計概念與初始應用程式開發
在前一章中,我們簡要介紹了物聯網(IoT)專案的整體架構與目標。現在,讓我們進一步探討軟體設計的核心概念,並開始構建初始的邊緣層應用程式。
設計原則
首先,回顧一下第一章中的問題陳述: 「我想了解家中的環境,它如何隨著時間變化,並進行調整以提高舒適度同時節省資金。」
為瞭解決這個問題,我們的應用程式需要具備一些重要的功能。同時,考慮到測試系統行為和效能的重要性,我們需要在設計初期就考慮到以下三個關鍵的設計原則:
模組化:建立執行特定任務(或相關任務)的軟體元件。模組化背後的概念是關注點分離(Separation of Concerns),這是電腦科學和應用程式設計中常用的術語,用於定義系統的架構方式。簡單來說,就是建立具有特定功能的軟體模組,避免過度複雜化。
介面:定義良好的介面或契約可以使軟體設計既優雅又高效。糟糕的介面設計則可能導致系統當機。介面提供了與模組互動的規則,並為系統的行為提供了一定的規範。
驗證:驗證是測試系統品質的一部分,包括檢查和平衡,以強制系統內部的一定行為,例如正常運作條件,排除可能引起問題的條件。例如,一個測試可能允許廣泛的值範圍,但如果該測試是針對家庭供暖系統的抽象,則更合理的最大值應該要低得多。系統必須足夠智慧以處理這種情況並採取相應的行動(例如,丟棄該值並記錄警告或錯誤訊息)。
這些設計原則將在本章中開始體現,因為我們將探討CDA(Constrained Device Application)和GDA(Gateway Device Application)的第一組練習。
追蹤需求
為了有效管理專案,我們需要追蹤即將實作的需求。有許多方法可以做到這一點,包括使用GitHub內建的問題追蹤器,或是建立一個單獨的儲存函式庫來追蹤跨CDA和GDA的需求。
程式設計練習
現在,讓我們開始進行程式設計練習。在這些練習中,我們將探討系統效能的需求,並將此功能新增到CDA和GDA中。
系統效能是系統驗證的一部分,它允許我們追蹤每個IoT應用程式執行時所使用的記憶體、CPU和磁碟儲存空間。此外,這個功能的設計將開始實踐模組化和介面定義的原則。
系統效能管理器設計
圖2-2和圖2-3展示了CDA和GDA的系統效能管理器設計。這些設計與圖1-15和1-16所示的設計略有不同。在第三章中,我們將對此進行「修正」,這意味著在本章中引入了一小部分的技術債(technical debt)。這樣做的目的是為了教育目的,幫助你快速建立並獲得一些功能性的程式碼。
# 以下是一個簡化的範例,展示如何實作系統效能管理器
import psutil
class SystemPerformanceManager:
def __init__(self):
pass
def get_memory_usage(self):
return psutil.virtual_memory().percent
def get_cpu_usage(self):
return psutil.cpu_percent(interval=1)
# 使用範例
if __name__ == "__main__":
spm = SystemPerformanceManager()
print(f"Memory Usage: {spm.get_memory_usage()}%")
print(f"CPU Usage: {spm.get_cpu_usage()}%")
內容解密:
- 我們定義了一個名為
SystemPerformanceManager的類別,用於管理系統效能。 get_memory_usage方法使用psutil.virtual_memory().percent來取得記憶體使用率。get_cpu_usage方法使用psutil.cpu_percent(interval=1)來取得CPU使用率。這裡的interval=1表示每隔1秒測量一次CPU使用率。- 在
if __name__ == "__main__":區塊中,我們建立了一個SystemPerformanceManager例項,並列印出記憶體和CPU的使用率。
透過遵循這些原則和實踐,我們可以為CDA和GDA新增更多的功能,並確保系統的可擴充套件性和可維護性。
建構初始邊緣層應用程式:受限裝置應用程式的系統效能管理
在開始撰寫程式碼之前,值得注意的是,本章節中對於受限裝置應用程式(Constrained Device Application, CDA)和閘道器裝置應用程式(Gateway Device Application, GDA)的初始設計將會非常相似。它們將會收集一些基本的遙測資料,目前包括 CPU 使用率和記憶體使用率,並簡單地將這些資料記錄到控制檯。
將系統效能任務新增到受限裝置應用程式
首先,檢視第二章節中對於 CDA 的需求。每個需求都以「PIOT-CDA-02」開頭。注意到「PIOT-CDA-02-000」指示您為本章節建立一個新的分支,而後續的需求則指示您建立(或更準確地說,編輯)與本章節任務相關的模組。
ConstrainedDeviceApp 是應用程式的入口點,它建立了 SystemPerformanceManager 的例項並對其進行管理。此外,還有兩個其他效能任務元件:SystemCpuUtilTask 和 SystemMemUtilTask。顧名思義,這些元件將會收集系統 CPU 使用率和系統記憶體使用率。它們將由 SystemPerformanceManager 管理,並作為非同步執行緒執行,更新您在 SystemPerformanceManager 中定義的方法。
檢視受限裝置應用程式模組
首先,從 Programming the IoT 專案中檢視「PIOT-CDA-02-001」需求活動。主要步驟包括:
- 在
programmingtheiot\cda源資料夾中建立一個名為app的 Python 套件,並導航到該資料夾。 - 匯入 Python 的 logging 模組:
import logging。 - 建立一個名為
ConstrainedDeviceApp的 Python 模組,並在其中定義一個同名的類別ConstrainedDeviceApp。 - 新增
startApp()方法,並記錄一條資訊訊息,指示應用程式已啟動。 - 新增
stopApp()方法,並記錄一條資訊訊息,指示應用程式已停止。
def main():
cda = ConstrainedDeviceApp()
cda.startApp()
while True:
sleep(60) # 1 分鐘,或者您可以選擇 2 分鐘(120 秒)
cda.stopApp()
if __name__ == '__main__':
main()
測試您的實作
執行 ConstrainedDeviceAppTest 單元測試。日誌輸出應該與以下內容類別似:
2020-07-20 10:08:20,169:INFO:Initializing CDA...
2020-07-20 10:08:20,169:INFO:Loading configuration...
2020-07-20 10:08:20,169:INFO:Starting CDA...
2020-07-20 10:08:20,169:INFO:CDA started.
2020-07-20 10:08:20,169:INFO:CDA stopping...
2020-07-20 10:08:20,170:INFO:CDA stopped with exit code 0.
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
---
Ran 1 test in 0.001s
OK
建立和整合系統效能管理器模組
下一個需求是建立(或者說,更新)SystemPerformanceManager 類別。如「PIOT-CDA-02-002」所述,這個需求指示您建立一個名為 SystemPerformanceManager 的 Python 模組,其中包含同名的類別。
這個元件將位於 cda 套件下的 system 資料夾中。主要活動涉及兩個簡單的任務:在 startManager() 中新增一條日誌訊息,指示管理器已啟動;以及在 stopManager() 中新增另一條日誌訊息,指示管理器已停止。
將 SystemPerformanceManager 整合到 CDA 中
檢視「PIOT-CDA-02-003」卡片中的動作,以將此模組整合到您的 CDA 中。主要步驟包括:
- 在
ConstrainedDeviceApp建構函式中建立一個類別範圍的SystemPerformanceManager例項,名為sysPerfManager:
self.sysPerfManager = SystemPerformanceManager()
- 編輯
startApp()方法,以包含對self.sysPerfManager.startManager()的呼叫。
#### 程式碼解析:
此段程式碼建立了 SystemPerformanceManager 的例項並在適當的時候啟動它。
1. **self.sysPerfManager = SystemPerformanceManager()**:這行程式碼在 ConstrainedDeviceApp 類別中建立了一個名為 sysPerfManager 的屬性,並將其初始化為 SystemPerformanceManager 的例項。這使得 CDA 能夠管理和控制系統效能監測的功能。
2. **編輯 startApp() 方法**:在 startApp() 方法中呼叫 self.sysPerfManager.startManager(),確保當 CDA 啟動時,SystemPerformanceManager 也會跟著啟動,開始監測系統效能。
透過這些步驟,受限裝置應用程式開始具備收集系統效能資料的能力,並為後續的遙測資料生成奠定了基礎。
系統效能監測模組開發
介紹
本章節將指導如何開發系統效能監測模組,包括建立SystemPerformanceManager、BaseSystemUtilTask、SystemCpuUtilTask和SystemMemUtilTask等模組,以實作對系統CPU和記憶體使用率的監測。
修改ConstrainedDeviceApp類別
首先,需要修改ConstrainedDeviceApp類別中的startApp()和stopApp()方法,以呼叫SystemPerformanceManager的啟動和停止方法。
def startApp(self):
# ... 其他程式碼 ...
self.sysPerfManager.startManager()
def stopApp(self):
# ... 其他程式碼 ...
self.sysPerfManager.stopManager()
內容解密:
startApp()和stopApp()方法分別用於啟動和停止應用程式。- 呼叫
self.sysPerfManager.startManager()啟動系統效能管理。 - 呼叫
self.sysPerfManager.stopManager()停止系統效能管理。
建立基礎系統工具任務類別
根據PIOT-CDA-02-004的描述,建立BaseSystemUtilTask類別作為基礎系統工具任務的抽象類別。
class BaseSystemUtilTask:
def __init__(self, name, typeID):
self.name = name
self.typeID = typeID
def getName(self):
return self.name
def getTypeID(self):
return self.typeID
def getTelemetryValue(self) -> float:
# 這個方法需要在子類別中實作
pass
內容解密:
__init__方法初始化物件,接受name和typeID兩個引數。getName()和getTypeID()方法分別傳回物件的名稱和型別ID。getTelemetryValue()方法是一個範本方法,需要在子類別中實作具體的遙測資料取得邏輯。
建立CPU利用率監測任務類別
建立SystemCpuUtilTask類別,繼承自BaseSystemUtilTask,用於監測系統CPU利用率。
import psutil
class SystemCpuUtilTask(BaseSystemUtilTask):
def __init__(self):
super(SystemCpuUtilTask, self).__init__(
name=ConfigConst.CPU_UTIL_NAME,
typeID=ConfigConst.CPU_UTIL_TYPE
)
def getTelemetryValue(self) -> float:
return psutil.cpu_percent()
內容解密:
- 使用
psutil函式庫取得系統CPU利用率。 getTelemetryValue()方法傳回當前CPU利用率的百分比。
建立記憶體利用率監測任務類別
建立SystemMemUtilTask類別,同樣繼承自BaseSystemUtilTask,用於監測系統記憶體利用率。
class SystemMemUtilTask(BaseSystemUtilTask):
def __init__(self):
super(SystemMemUtilTask, self).__init__(
name=ConfigConst.MEM_UTIL_NAME,
typeID=ConfigConst.MEM_UTIL_TYPE
)
def getTelemetryValue(self) -> float:
return psutil.virtual_memory().percent
內容解密:
- 使用
psutil.virtual_memory().percent取得系統記憶體利用率的百分比。 getTelemetryValue()方法傳回當前記憶體利用率的百分比。
連線監測任務到系統效能管理器
將建立的SystemCpuUtilTask和SystemMemUtilTask連線到SystemPerformanceManager,以實作對系統效能的監測。
使用APScheduler進行排程
使用APScheduler函式庫來實作對監測任務的排程執行,以定期取得系統效能資料。
from apscheduler.schedulers.background import BackgroundScheduler
def main():
scheduler = BackgroundScheduler()
# 新增任務到排程器
scheduler.start()
if __name__ == "__main__":
main()
內容解密:
- 使用
BackgroundScheduler來建立一個背景排程器。 - 可以透過排程器新增任務,以定期執行系統效能監測任務。
系統效能管理元件整合與實作
在物聯網(IoT)系統中,裝置的效能監控至關重要。本章節將介紹如何在受限裝置應用程式(CDA)中整合系統效能管理元件,並進一步擴充套件至閘道器裝置應用程式(GDA)。
CDA系統效能管理元件實作
CDA的系統效能管理元件主要負責監控系統的CPU和記憶體使用率。以下為實作步驟:
1. 初始化系統效能管理器
首先,需要更新SystemPerformanceManager類別的建構子,以初始化所需的元件,包括CPU使用率任務、記憶體使用率任務和排程器。
import logging
from apscheduler.schedulers.background import BackgroundScheduler
from programmingtheiot.common.IDataMessageListener import IDataMessageListener
from programmingtheiot.cda.system.SystemCpuUtilTask import SystemCpuUtilTask
from programmingtheiot.cda.system.SystemMemUtilTask import SystemMemUtilTask
from programmingtheiot.data.SystemPerformanceData import SystemPerformanceData
class SystemPerformanceManager(object):
def __init__(self):
configUtil = ConfigUtil()
self.pollRate = configUtil.getInteger(
section=ConfigConst.CONSTRAINED_DEVICE,
key=ConfigConst.POLL_CYCLES_KEY,
defaultVal=ConfigConst.DEFAULT_POLL_CYCLES)
# 初始化其他必要的屬性
self.scheduler = BackgroundScheduler()
self.cpuUtilTask = SystemCpuUtilTask()
self.memUtilTask = SystemMemUtilTask()
# 設定排程器任務
self.scheduler.add_job('self.handleTelemetry', 'interval', seconds=self.pollRate)
2. 實作系統效能資料處理
handleTelemetry方法負責處理系統效能資料,包括讀取CPU和記憶體使用率,並記錄日誌。
def handleTelemetry(self):
cpuUtil = self.cpuUtilTask.getSystemCpuUtil()
memUtil = self.memUtilTask.getSystemMemUtil()
logging.info(f"CPU utilization is {cpuUtil} percent, and memory utilization is {memUtil} percent.")
3. 啟動和停止系統效能管理器
需要實作startManager和stopManager方法,以控制排程器的啟動和停止。
def startManager(self):
logging.info("Started SystemPerformanceManager.")
if not self.scheduler.running:
self.scheduler.start()
def stopManager(self):
logging.info("Stopped SystemPerformanceManager.")
try:
self.scheduler.shutdown()
except:
logging.warning("SystemPerformanceManager scheduler already stopped. Ignoring.")
GDA系統效能管理元件設計
GDA的系統效能管理元件設計與CDA類別似,但GDA將負責處理來自CDA的資料,並將其傳送至雲端進行進一步處理。
GDA系統效能設計UML圖
此圖展示了GDA的系統效能設計詳細資訊。
關鍵技術與考量
- 排程器使用:本實作使用了APScheduler函式庫來實作排程任務,這使得系統效能資料的收集變得更加靈活和可控。
- 組態檔案使用:透過
ConfigUtil類別,可以從組態檔案中讀取必要的引數,如輪詢率等,這提高了程式的靈活性。 - 模組化設計:系統效能管理元件被設計為獨立的模組,這使得未來擴充套件和維護變得更加容易。