使用libvirt-java採集KVM虛擬機狀態信息

虛擬化開發相較於普通開發是一個冷門的方向,大多數是使用Python開發,其中使用Java來作虛擬化的更是少之又少,資料更是少的可憐,爲了實現需求我也是踩了很多坑,今天就爲你們分享一下如何使用 libvirt-java 來採集KVM虛擬機的資源使用信息。html

CPU使用率

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解析庫Jsoupxml算是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));
}

磁盤IO信息

和網卡一樣,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));
}

至此採集虛擬機狀態信息算是告一段落,學的越多才發現不會的越多...

相關文章
相關標籤/搜索