书接上文:[CloudStack Host运行状态监控 – Management]
继续分析Hyperviser端对于Host监控的实现。Hyperviser端接受到命令GetHostStatsCommand,会有相应逻辑对其进行处理,获取Host当前状态并返回。

XenServer

CitrixResourceBase.java

protected GetHostStatsAnswer execute(GetHostStatsCommand cmd) {

    ......

        HostStatsEntry hostStats = getHostStats(conn, cmd, cmd.getHostGuid(), cmd.getHostId());
        return new GetHostStatsAnswer(cmd, hostStats);

    ......

}

在该类接受到此命令时,调用getHostStats方法,对主机状态进行查询,与VM类似,也是通过解析XenServer提供的RRD Data来进行数据获取。

protected HostStatsEntry getHostStats(Connection conn, GetHostStatsCommand cmd, String hostGuid, long hostId) {
    HostStatsEntry hostStats = new HostStatsEntry(hostId, 0, 0, 0, "host", 0, 0, 0, 0);
    Object[] rrdData = getRRDData(conn, 1); // call rrd method with 1 for host

    ......//获取RRD Data值

    for (int col = 0; col < numColumns; col++) {

        ......

        String type = columnMetadataList[1];
        String param = columnMetadataList[3];
        if (type.equalsIgnoreCase("host")) {
            if (param.matches("pif_eth0_rx")) {
                hostStats.setNetworkReadKBs(getDataAverage(dataNode, col, numRows)/1000);
            } else if (param.matches("pif_eth0_tx")) {
                hostStats.setNetworkWriteKBs(getDataAverage(dataNode, col, numRows)/1000);
            } else if (param.contains("memory_total_kib")) {
                hostStats.setTotalMemoryKBs(getDataAverage(dataNode, col, numRows));
            } else if (param.contains("memory_free_kib")) {
                hostStats.setFreeMemoryKBs(getDataAverage(dataNode, col, numRows));
            } else if (param.matches("cpu_avg")) {
                // hostStats.setNumCpus(hostStats.getNumCpus() + 1);
                hostStats.setCpuUtilization(hostStats.getCpuUtilization() + getDataAverage(dataNode, col, numRows));
            }

            ......

        }
    }
    ......
    return hostStats;
}

由此看出,实际对于Host运行状态的获取,XenServer只提供了eth0的出入流量瞬时值(以该段时间平均值为瞬时值),内存的总量和剩余量,cpu的平均使用率这5项内容,如果需要新加选项, 比如需要获取所有网卡流量等信息,可以修改此处代码获取。

Vmware

VmwareResource.java

protected Answer execute(GetHostStatsCommand cmd) {

    ......

    VmwareContext context = getServiceContext();
    VmwareHypervisorHost hyperHost = getHyperHost(context);
    HostStatsEntry hostStats = new HostStatsEntry(cmd.getHostId(), 0, 0, 0, "host", 0, 0, 0, 0);

    ......

        HostStatsEntry entry = getHyperHostStats(hyperHost);
        if (entry != null) {
            entry.setHostId(cmd.getHostId());
            answer = new GetHostStatsAnswer(cmd, entry);
        }

    ......

    return answer;

}

在getHyperHostStats方法中,调用VMware API来获取Host状态。

private static HostStatsEntry getHyperHostStats(VmwareHypervisorHost hyperHost) throws Exception {
    ComputeResourceSummary hardwareSummary = hyperHost.getHyperHostHardwareSummary();

    ......

    HostStatsEntry entry = new HostStatsEntry();
    entry.setEntityType("host");
    double cpuUtilization = ((double)(hardwareSummary.getTotalCpu() - hardwareSummary.getEffectiveCpu()) / (double)hardwareSummary.getTotalCpu() * 100);
    entry.setCpuUtilization(cpuUtilization);
    entry.setTotalMemoryKBs(hardwareSummary.getTotalMemory() / 1024);
    entry.setFreeMemoryKBs(hardwareSummary.getEffectiveMemory() * 1024);
    return entry;
}

由代码可以看出,VMware Host状态值获取了CPU使用率,内存总量和使用量。

hyperHost.getHyperHostHardwareSummary的逻辑如下:

public ComputeResourceSummary getHyperHostHardwareSummary() throws Exception {

    ......

    HostHardwareSummary hardwareSummary = getHostHardwareSummary();
    ComputeResourceSummary resourceSummary = new ComputeResourceSummary();
    resourceSummary.setNumCpuCores(hardwareSummary.getNumCpuCores());
    resourceSummary.setTotalMemory(hardwareSummary.getMemorySize());
    int totalCpu = hardwareSummary.getCpuMhz() * hardwareSummary.getNumCpuCores();
    resourceSummary.setTotalCpu(totalCpu);
    HostListSummaryQuickStats stats = getHostQuickStats();

    ......

    resourceSummary.setEffectiveCpu(totalCpu - stats.getOverallCpuUsage());
    resourceSummary.setEffectiveMemory(hardwareSummary.getMemorySize() / (1024 * 1024) - stats.getOverallMemoryUsage());

    ......

    return resourceSummary;

}

如果想要获取更多VMware Host的运行状态,可以在这两个方法中添加相应内容来获取。

KVM

private Answer execute(GetHostStatsCommand cmd) {
    final Script cpuScript = new Script("/bin/bash", s_logger);
    cpuScript.add("-c");
    cpuScript.add("idle=$(top -b -n 1| awk -F, '/^[%]*[Cc]pu/{$0=$4; gsub(/[^0-9.,]+/,\"\"); print }'); echo $idle");
    final OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser();
    String result = cpuScript.execute(parser);

    ......

    double cpuUtil = (100.0D - Double.parseDouble(parser.getLine()));

    long freeMem = 0;
    final Script memScript = new Script("/bin/bash", s_logger);
    memScript.add("-c");
    memScript.add("freeMem=$(free|grep cache:|awk '{print $4}');echo $freeMem");
    final OutputInterpreter.OneLineParser Memparser = new OutputInterpreter.OneLineParser();
    result = memScript.execute(Memparser);
    ......

    freeMem = Long.parseLong(Memparser.getLine());

    Script totalMem = new Script("/bin/bash", s_logger);
    totalMem.add("-c");
    totalMem.add("free|grep Mem:|awk '{print $2}'");
    final OutputInterpreter.OneLineParser totMemparser = new OutputInterpreter.OneLineParser();
    result = totalMem.execute(totMemparser);

    ......

    long totMem = Long.parseLong(totMemparser.getLine());

    Pair<Double, Double> nicStats = getNicStats(_publicBridgeName);
    HostStatsEntry hostStats = new HostStatsEntry(cmd.getHostId(), cpuUtil, nicStats.first() / 1024, nicStats.second() / 1024, "host", totMem, freeMem, 0, 0);
    return new GetHostStatsAnswer(cmd, hostStats);
}

由此看出,对于KVM的Host信息,CPU是根据top命令返回值来获取,内存使用信息则是通过free命令获取。网卡是调用getNicStats方法获取,getNicStats方法也是返回public bridge的上下行速度。

static Pair<Double, Double> getNicStats(String nicName) {
    return new Pair<Double, Double>(readDouble(nicName, "rx_bytes"), readDouble(nicName, "tx_bytes"));
}

static double readDouble(String nicName, String fileName) {
    final String path = "/sys/class/net/" + nicName + "/statistics/" + fileName;
    ......
        return Double.parseDouble(FileUtils.readFileToString(new File(path)));
    ......
}

网卡速度在/sys/class/net/[NICNAME]/statistics/[rx_bytes/tx_bytes]中读出