虛擬化開發相較於普通開發是一個冷門的方向,大多數是使用Python開發,其中使用Java來作虛擬化的更是少之又少,資料更是少的可憐,爲了實現需求我也是踩了很多坑,今天就爲你們分享一下如何使用 libvirt-java
來採集KVM虛擬機的資源使用信息。html
libvirt
並無直接提供獲取虛擬機CPU使用率的接口,須要咱們本身來計算,網上分享的代碼或者公式五花八門,大部分都是錯誤的,通過個人測試,找到了一個相對準確的計算公式。java
cpu_usage = (cpu_time_now - cpu_time_t_second_ago) * 100 / (t * vCpus * 10^9)
Java代碼以下數組
// t秒前的CPU時間 long c1 = domain.getInfo().cpuTime; Thread.sleep(1000); // 當前CPU時間 long c2 = domain.getInfo().cpuTime; // 虛擬CPU數量 int vCpus = domain.getMaxVcpus(); // t 爲1秒 Double cpuUsage = 100 * (c2 - c1) / (1 * vCpus * Math.pow(10, 9)); log.debug("虛擬機[{}]CPU使用率爲: {}", uuid, cpuUsage);
不要使用domain.getInfo()
返回的 memory
字段,雖然它註釋寫的是the memory in KBytes used by the domain
,但它的意思真的不是虛擬機內部進程已使用的內存大小,而是從宿主機器的角度來看分配給這個虛擬機的內存它使用了多少,若是沒有特殊配置,它會和maxMem
字段的值是相同的。dom
正確作法是使用domain.memoryStats(10)
來獲取,那爲何參數要輸入一個10
呢?這是由於10
表明的是要返回的信息數量,通過我手動執行virsh dommemstat uuid
測試發現有10個參數返回,因此須要填入10
。另外命令返回的unused
字段值與數組中tag=8
的數據一致,最終咱們獲取到了未使用的內存大小,計算內存使用率更是輕輕鬆鬆。測試
Java代碼以下ui
MemoryStatistic[] memoryStatistics = domain.memoryStats(10); Optional<MemoryStatistic> first = Arrays.stream(memoryStatistics).filter(x -> x.getTag() == 8).findFirst(); if (first.isPresent()) { MemoryStatistic memoryStatistic = first.get(); long unusedMemory = memoryStatistic.getValue(); long maxMemory = domain.getMaxMemory(); double memoryUsage = (maxMemory - unusedMemory) * 100.0 / maxMemory; log.debug("虛擬機[{}]內存使用率爲: {}", uuid, memoryUsage); }
一樣libvirt
並無提供獲取虛擬機網卡的接口,所以須要獲取虛擬機的xml文件來查詢。debug
此處沒有什麼坑,解析xml
是使用了html
解析庫Jsoup
,xml
算是html
的親戚吧,比html
書寫嚴格不少,解析數據更爲方便。code
獲取到網卡名稱以後再獲取統計信息,能夠獲取的數據有:xml
字段 | 含義 |
---|---|
rx_bytes | 接收數據包大小 |
rx_packets | 接收數據包數量 |
rx_errs | 接收錯誤數據包數量 |
rx_drop | 接收丟棄數據包數量 |
tx_bytes | 發送數據包大小 |
tx_packets | 發送數據包數量 |
tx_errs | 發送錯誤數據包數量 |
tx_drop | 發送丟棄數據包數量 |
Java代碼以下htm
String xmlDesc = domain.getXMLDesc(0); Document document = Jsoup.parse(xmlDesc); // 網卡 Elements interfaces = document.getElementsByTag("devices").get(0).getElementsByTag("interface"); for (Element inter : interfaces) { String interName = inter.getElementsByTag("target").get(0).attr("dev"); DomainInterfaceStats domainInterfaceStats = domain.interfaceStats(interName); log.debug("dev {} stats {}", interName, Json.toJsonString(domainInterfaceStats)); }
和網卡一樣,libvirt
也沒有提供獲取虛擬機磁盤的接口,仍是須要獲取虛擬機的xml文件來查詢,獲取到磁盤名稱以後再獲取統計信息,能夠獲取的數據有:
字段 | 含義 |
---|---|
rd_req | 讀取請求總數 |
rd_bytes | 讀取的數據大小 |
wr_req | 寫入請求總數 |
wr_bytes | 寫入的數據大小 |
errs | 失敗次數 |
Java代碼以下
String xmlDesc = domain.getXMLDesc(0); Document document = Jsoup.parse(xmlDesc); // 磁盤 Elements disks = document.getElementsByTag("devices").get(0).getElementsByTag("disk"); for (Element disk : disks) { String dev = disk.getElementsByTag("target").get(0).attr("dev"); DomainBlockStats domainBlockStats = domain.blockStats(dev); log.debug("dev {} stats {}", dev, Json.toJsonString(domainBlockStats)); }
至此採集虛擬機狀態信息算是告一段落,學的越多才發現不會的越多...