Virtualization development is a cold direction compared with ordinary development, most of which use Python development, and the use of Java to do virtualization is even less, the data is even less poor, in order to achieve the requirements I also stepped on a lot of pits, Libvirt-java is used to collect resource usage information for KVM virtual machines.

CPU utilization

Libvirt does not directly provide an interface to obtain VM CPU usage, so we need to calculate it ourselves. There are various codes and formulas shared online, most of which are wrong. After testing, I found a relatively accurate calculation formula.

cpu_usage = (cpu_time_now - cpu_time_t_second_ago) * 100 / (t * vCpus * 10^9)
Copy the code

The Java code is as follows

// The CPU time of t seconds ago
long c1 = domain.getInfo().cpuTime;
Thread.sleep(1000);
// The current CPU time
long c2 = domain.getInfo().cpuTime;

// Number of virtual cpus
int vCpus = domain.getMaxVcpus();
// t is 1 second
Double cpuUsage = 100 * (c2 - c1) / (1 * vCpus * Math.pow(10.9));
log.debug("Vm [{}]CPU usage is: {}", uuid, cpuUsage);
Copy the code

Memory usage

Do not use the memory field returned by domain.getInfo(). Although it says the memory in KBytes used by the domain, it really does not mean the amount of memory used by the processes inside the virtual machine. It’s how much memory is allocated to the virtual machine from the perspective of the host machine, and if it’s not configured, it will be the same value as the maxMem field.

The correct way to do this is to use domain-.memoryStats (10), so why enter a 10 for the parameter? This is because 10 represents the amount of information to be returned, and I manually performed the virsh dommemstat uUID test and found that 10 parameters were returned, so I needed to fill in 10. In addition, the unused field value returned by the command is the same as the value of the array tag=8. Finally, we get the unused memory size, making it easier to calculate the memory usage.

The Java code is as follows

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("Vm [{}] memory usage is: {}", uuid, memoryUsage);
}
Copy the code

Nic packet information

Libvirt also does not provide an interface to obtain the VM NETWORK adapter. Therefore, you need to obtain the VM XML file to query the VM NETWORK adapter.

XML is a relative of HTML. It is written much more strictly than HTML. It is more convenient to parse data.

After obtaining the nic name, you can obtain the following statistics:

field meaning
rx_bytes Received packet size
rx_packets Number of received packets
rx_errs Number of received incorrect packets
rx_drop Number of discarded packets received
tx_bytes Sent packet size
tx_packets Number of packets sent
tx_errs Number of incorrect packets sent
tx_drop Number of discarded packets sent

The Java code is as follows

String xmlDesc = domain.getXMLDesc(0);
Document document = Jsoup.parse(xmlDesc);

/ / network card
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));
}
Copy the code

Disk IO Information

Libvirt also does not provide an interface to obtain vm disks. You need to obtain the VM XML file to obtain the disk name and statistics. The following data can be obtained:

field meaning
rd_req Total read requests
rd_bytes The size of the data read
wr_req Total number of write requests
wr_bytes Size of the data to be written
errs Number of failures

The Java code is as follows

String xmlDesc = domain.getXMLDesc(0);
Document document = Jsoup.parse(xmlDesc);
/ / disk
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));
}
Copy the code

This is the end of collecting VM status information. The more you learn, the more you learn.