在物聯網邊緣計算中,閘道器裝置應用程式(GDA)扮演著關鍵角色,負責連線本地裝置和雲端平台。GDA 的穩定性和效能直接影響整個物聯網系統的運作。因此,有效地監控 GDA 的系統效能至關重要。本文將探討如何設計和實作 GDA 的系統效能監控模組,涵蓋 CPU 利用率、記憶體使用率和磁碟利用率等關鍵指標,並結合 Java 程式碼範例進行說明,同時也為後續與感測器、驅動器和雲端平台的整合做好準備。

閘道器裝置應用程式(GDA)開發

系統效能監測的重要性

在開發物聯網(IoT)閘道器裝置應用程式(GDA)時,系統效能監測是一個至關重要的環節。GDA不僅需要管理本地裝置的資料,還需要與其他裝置和雲端進行通訊。因此,監測系統資源的使用情況,如CPU利用率、記憶體使用率和磁碟利用率,對於確保GDA的穩定性和效率至關重要。

GDA的設計架構

圖2-4展示了GDA的設計架構。從圖中可以看出,GatewayDeviceApp是應用程式的入口點,它建立並管理SystemPerformanceManager的例項。這與CDA(Constrained Device Application)的設計類別似。SystemPerformanceManager負責監測系統的效能,並提供相關的資料。

新增的監測指標

除了基本的系統效能監測外,GDA還需要收集額外的指標,如磁碟利用率和網路利用率。這些指標對於後續章節中實作本地快取和裝置間的訊息傳遞至關重要。

現有的系統效能監測工具

雖然已經有許多工具可用於監測系統效能,但IoT Edge Tier中的裝置往往難以管理,且不總是能夠參與網路監測環境。因此,我們需要構建自己的系統效能監測模組。

實作SystemPerformanceManager

如同CDA一樣,GDA的SystemPerformanceManager模組需要被實作。這個模組負責建立和管理各個系統效能監測任務,如SystemCpuUtilTaskSystemMemUtilTaskSystemDiskUtilTask

程式碼實作

public class SystemPerformanceManager {
    // 初始化SystemPerformanceManager
    public SystemPerformanceManager() {
        // 建立各個系統效能監測任務
        SystemCpuUtilTask cpuUtilTask = new SystemCpuUtilTask();
        SystemMemUtilTask memUtilTask = new SystemMemUtilTask();
        SystemDiskUtilTask diskUtilTask = new SystemDiskUtilTask();
        
        // 啟動各個監測任務
        cpuUtilTask.start();
        memUtilTask.start();
        diskUtilTask.start();
    }
    
    // 其他方法...
}

內容解密:

  1. SystemPerformanceManager類別負責管理系統效能監測任務。
  2. 在建構函式中,建立了三個系統效能監測任務:CPU利用率、記憶體使用率和磁碟利用率。
  3. 各個監測任務被啟動,以便開始收集系統效能資料。

檢視和更新GatewayDeviceApp模組

在開始實作SystemPerformanceManager之前,需要檢視和更新GatewayDeviceApp模組。根據需求PIOT-GDA-02-001,GatewayDeviceApp模組已經提供了基本的實作,但仍需要進行一些更新。

執行整合測試

更新完成後,需要執行整合測試以確保GatewayDeviceApp模組正常運作。測試案例testRunGatewayApp()可以使用JUnit 4 Runner執行。

測試結果

執行測試後,應該會看到類別似以下的輸出:

Sep 05, 2020 5:48:10 PM programmingtheiot.gda.app.GatewayDeviceApp <init>
INFO: Initializing GDA...
Sep 05, 2020 5:48:10 PM programmingtheiot.gda.app.GatewayDeviceApp parseArgs
INFO: No command line args to parse.
Sep 05, 2020 5:48:10 PM programmingtheiot.gda.app.GatewayDeviceApp initConfig
INFO: Attempting to load configuration: Default.
Sep 05, 2020 5:48:10 PM programmingtheiot.gda.app.GatewayDeviceApp startApp
INFO: Starting GDA...
Sep 05, 2020 5:48:10 PM programmingtheiot.gda.app.GatewayDeviceApp startApp
INFO: GDA started successfully.
Sep 05, 2020 5:49:15 PM programmingtheiot.gda.app.GatewayDeviceApp stopApp
INFO: Stopping GDA...
Sep 05, 2020 5:49:15 PM programmingtheiot.gda.app.GatewayDeviceApp stopApp
INFO: GDA stopped successfully with exit code 0.

內容解密:

  1. GatewayDeviceApp模組被初始化並啟動。
  2. 組態檔案被載入。
  3. GDA成功啟動並停止。

實作系統效能管理與工具模組

本章節將介紹如何實作系統效能管理(SystemPerformanceManager)以及相關的系統工具模組,包括 CPU 與記憶體使用率的監控。

建立系統效能管理器

根據需求,首先需要建立 SystemPerformanceManager 類別,並實作預設建構函式以及啟動/停止管理器的方法。這些方法應該記錄資訊日誌,指示管理器是否已啟動或停止。

程式碼範例:

public class SystemPerformanceManager {
    // 類別層級變數
    private boolean isRunning = false;

    // 預設建構函式
    public SystemPerformanceManager(int pollCycle) {
        // 初始化設定
    }

    // 啟動管理器
    public void startManager() {
        isRunning = true;
        // 記錄日誌
        Logger.getLogger(SystemPerformanceManager.class.getName()).log(Level.INFO, "SystemPerformanceManager is starting...");
    }

    // 停止管理器
    public void stopManager() {
        isRunning = false;
        // 記錄日誌
        Logger.getLogger(SystemPerformanceManager.class.getName()).log(Level.INFO, "SystemPerformanceManager is stopped.");
    }
}

內容解密:

  • SystemPerformanceManager 的建構函式負責初始化相關設定。
  • startManager() 方法將 isRunning 設為 true,並記錄日誌指示管理器已啟動。
  • stopManager() 方法將 isRunning 設為 false,並記錄日誌指示管理器已停止。

整合系統效能管理器至 GDA

接下來,需要在 GatewayDeviceApp 中建立 SystemPerformanceManager 的例項,並在應用程式的啟動/停止方法中呼叫管理器的對應方法。

程式碼範例:

public class GatewayDeviceApp {
    // 類別層級變數
    private SystemPerformanceManager sysPerfManager;

    // 建構函式
    public GatewayDeviceApp() {
        sysPerfManager = new SystemPerformanceManager(10); // 使用 10 作為引數
    }

    // 啟動應用程式
    public void startApp() {
        sysPerfManager.startManager();
        // 其他啟動邏輯
    }

    // 停止應用程式
    public void stopApp() {
        sysPerfManager.stopManager();
        // 其他停止邏輯
    }
}

內容解密:

  • GatewayDeviceApp 的建構函式中,建立了 SystemPerformanceManager 的例項。
  • startApp() 方法中,呼叫了 sysPerfManager.startManager() 以啟動系統效能管理器。
  • stopApp() 方法中,呼叫了 sysPerfManager.stopManager() 以停止系統效能管理器。

建立系統工具模組

為了監控系統資源使用情況,需要建立抽象類別 BaseSystemUtilTask,並實作其子類別,如 SystemCpuUtilTaskSystemMemUtilTask

程式碼範例(SystemCpuUtilTask):

public class SystemCpuUtilTask extends BaseSystemUtilTask {
    public SystemCpuUtilTask() {
        super("CPU Util Task", ConfigConst.CPU_UTIL_TASK_NAME);
    }

    @Override
    public float getTelemetryValue() {
        double cpuUtil = ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage();
        // 記錄日誌並傳回 CPU 使用率
        return (float) cpuUtil;
    }
}

內容解密:

  • SystemCpuUtilTask 繼承自 BaseSystemUtilTask,並在建構函式中呼叫父類別建構函式,傳入名稱和型別 ID。
  • getTelemetryValue() 方法使用 Java 的管理介面來取得系統負載平均值,並傳回 CPU 使用率。

程式碼範例(SystemMemUtilTask):

public class SystemMemUtilTask extends BaseSystemUtilTask {
    public SystemMemUtilTask() {
        super("Memory Util Task", ConfigConst.MEM_UTIL_TASK_NAME);
    }

    @Override
    public float getTelemetryValue() {
        MemoryUsage memUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
        double memUtil = ((double) memUsage.getUsed() / (double) memUsage.getMax()) * 100.0d;
        // 記錄日誌並傳回記憶體使用率
        return (float) memUtil;
    }
}

內容解密:

  • SystemMemUtilTask 同樣繼承自 BaseSystemUtilTask,並實作了 getTelemetryValue() 方法來計算 JVM 的記憶體使用率。
  • 該方法透過取得堆積記憶體使用情況,計算已使用記憶體佔最大記憶體的比例,並傳回記憶體使用率。

重複任務的執行

為了實作定期收集系統效能資料的功能,Java 提供了多種方式來建立輪詢系統。在後續章節中,將進一步介紹如何在 GDA 中實作此功能。

本章節完成了系統效能管理器的實作以及相關的系統工具模組,為後續的系統監控與資料收集奠定了基礎。

整合系統效能管理與定時任務的實作

在物聯網(IoT)邊緣層級的應用開發中,系統效能管理與定時任務的整合是至關重要的技術環節。本文將探討如何利用Java的並發程式函式庫實作定時任務,並將其與系統效能管理相結合。

使用ScheduledExecutorService實作定時任務

Java的並發程式函式庫提供了強大的定時任務功能,其中ScheduledExecutorService是實作定期輪詢任務的理想選擇。透過使用ScheduledExecutorService,開發者可以輕鬆地實作定時任務,同時處理大部分的複雜性。

程式碼實作

private ScheduledExecutorService schedExecSvc = Executors.newScheduledThreadPool(1);
private Runnable taskRunner = () -> {
    this.handleTelemetry();
};

public void startManager() {
    if (!this.isStarted) {
        ScheduledFuture<?> futureTask = this.schedExecSvc.scheduleAtFixedRate(
            this.taskRunner, 0L, this.pollRate, TimeUnit.SECONDS);
        this.isStarted = true;
    }
}

public void stopManager() {
    this.schedExecSvc.shutdown();
}

內容解密:

  1. ScheduledExecutorService初始化:使用Executors.newScheduledThreadPool(1)建立一個單執行緒的排程執行器服務。
  2. Runnable任務定義:定義一個taskRunner,其內部呼叫handleTelemetry()方法以處理遙測資料。
  3. startManager()方法:啟動定時任務,若尚未啟動,則使用scheduleAtFixedRate方法按照固定的頻率執行taskRunner任務。
  4. stopManager()方法:停止定時任務,透過呼叫schedExecSvc.shutdown()方法來關閉排程執行器服務。

系統效能管理的整合

為了實作系統效能管理,需要整合CPU和記憶體使用率的監控任務。

程式碼實作

private SystemCpuUtilTask sysCpuUtilTask = new SystemCpuUtilTask();
private SystemMemUtilTask sysMemUtilTask = new SystemMemUtilTask();

public void handleTelemetry() {
    double cpuUtilPct = this.sysCpuUtilTask.getTelemetry();
    double memUtilPct = this.sysMemUtilTask.getTelemetry();
    // 紀錄CPU和記憶體使用率
}

內容解密:

  1. 系統效能監控任務初始化:建立SystemCpuUtilTaskSystemMemUtilTask例項以監控CPU和記憶體使用率。
  2. handleTelemetry()方法:取得CPU和記憶體的使用率,並進行相關處理或紀錄。

測試與驗證

完成上述實作後,可以透過執行GatewayDeviceAppTest單元測試中的testRunTimedGatewayApp()方法來驗證功能的正確性。

測試結果分析

成功的測試執行將產生類別似以下的紀錄輸出:

INFO: Handle telemetry results: cpuUtil=-1.0, memUtil=0.1469148

這表明系統效能管理與定時任務已成功整合並執行。

連線到物理世界

連線電腦到物理世界可能相當棘手,因為電腦使用數位訊號(二進位制資料,即0和1),而物理世界則是在輸入和輸出的範圍內運作(類別比資料),這些資料可以代表各種事物,如溫度、風速和方向,或是力的程度。

然而,物聯網(IoT)的一大部分正是將電腦連線到物理世界和網際網路,以解決問題(如自動氣候控制)。這種連線始於邊緣層(Edge Tier),我們的軟體(此例中為CDA)解釋這些物理世界的輸入(感測),並將其轉換成我們的計算系統所理解的0和1。它還可以將這些0和1轉換成命令,傳送給另一個物理系統,以開啟、關閉或調整(驅動)。

感測與驅動

感測是透過將機械輸入訊號轉換成電訊號(最終轉換成數位訊號,即前述的0和1)的過程。驅動則是感測的相反過程:將電訊號轉換成機械輸出的過程。

根據感測器和執行器的不同,這個過程可能會大不相同。在本文中,我們只需要從感測器“源”收集資料,並向執行器“目標”傳送命令。為了保持簡單並專注於構建邊緣層軟體應用程式,我們的目標是模擬——或模擬——這種物理世界的互動。

幸運的是,這相對容易做到。感測器源輸入範圍和相關的驅動觸發器,可以儲存在組態檔案中,並由我們為CDA和GDA開發的軟體處理。我們將在第3章開始這個過程,透過構建一個簡單的模擬器功能,並在第4章透過加入一個軟體模擬器,允許手動控制這個過程——所有這些都不依賴於任何特定的硬體。

本章節學習內容

本章節將開始探討第一部分中討論的所有三個關鍵活動:測量(資料收集)、建模(資料管理)和管理(系統觸發器)。然而,大部分重點將放在資料收集上,至少在初期是如此。我們將在第4章和第5章進一步探討資料管理和系統觸發器的簡單方面,然後在第10章討論一個整合的方法。

章節安排

  • 第3章和第4章將展示如何為CDA新增功能,以從模擬和模擬感測器收集資料,將這些資料儲存和解釋在資料物件包裝器中,並將這些資料轉換成JSON(JavaScript Object Notation)和從JSON轉換回來。這對於不僅與第5章和第三部分的GDA整合,而且與第四部分從第11章開始的雲端整合至關重要。
  • 第5章將把GDA帶回圖片中,並在其功能中新增類別似的資料物件包裝器和JSON轉換功能。這不僅對於將應用程式相互連線並最終連線到雲端很重要,而且對於直接在邊緣層的GDA上執行一些基本的分析也很重要。
  • 我們還將使用Redis(一種記憶體資料快取)為GDA引入本地儲存機制。

應用程式組態檢視

在第1章中,我們討論了克隆的Python和Java Git儲存函式庫中的“common”包。組態工具——ConfigUtil——及其“consts”類別——ConfigConst——值得快速檢視。

組態工具與常數類別

  • ConfigUtil 提供了一種管理組態設定的方法,使得應用程式能夠根據不同的環境或需求進行調整。
  • ConfigConst 定義了組態中的常數,這些常數在應用程式的不同部分被參照,以保持組態的一致性。

透過檢視這些工具和類別,我們可以更好地理解如何管理和使用組態設定,從而使我們的應用程式更加靈活和可組態。