zoukankan      html  css  js  c++  java
  • [zz]OpenStack中虚拟机的监控

    整个方案的基本思想是由host负责运行程序,采集数据,额外一台服务器作为server收集每台host的数据进行分析。本文涉及的程序代码均可以从Github上下载,虚拟化使用kvm,使用libvirt作为C API。

    AD:

    本文涉及的程序代码均可以从我的github上下载, 并且持续更新代码

    虚拟化使用kvm,使用libvirt作为C API

    基本思想:host负责运行程序,采集数据,额外一台服务器作为server收集每台host的数据进行分析

    程序介绍:

    首先我们需要打开一个和hypervisor的连接,需要一个virConnectPtr的指针

    virConnectOpenReadOnly(char *) 返回的就是这麽一个指针。初始化程序例如:

    void conn_init(char *ip, virConnectPtr *conn) {
        *conn = NULL; /* the hypervisor connection */
        char *p;
        p = (char *)malloc(35*sizeof(char));
        *conn = virConnectOpenReadOnly(p);
        free(p);
        if (*conn == NULL) {
            fprintf(stderr, "Failed to connect to hypervisor\n");
        }
    }

    第二个参数是一个指向virConnectPtr变量的指针,这裡的p指向的是类似“qemu+ssh://10.0.0.1/system”的字符串,10.0.0.1是你的host ip

    关闭连接的函数

    void conn_close(virConnectPtr *conn) {
        if (*conn != NULL)
            virConnectClose(*conn);
    }

    现在我们有了一个指向host的hypervisor的连接,我们可以用他来获得host上跑的虚拟机的情况

    void list_id_domain(virConnectPtr conn) {
        int ids[10];
        int maxids=10;
        int num, i;
        num = virConnectListDomains(conn, ids, maxids);
        for(i = 0;i < num;i++) {
            printf("%d\n",ids[i]);
        }
    }

    这个函数使用上面得到的conn这个指针,列出host上跑的实例的id号

    有了id号我们就可以获取每个实例的详细信息,假设我有一个id为7的虚拟机实例:

    virDomainPtr dom = NULL;
    dom = virDomainLookupByID(conn, 7);

    dom这个变量就是以后我们要一直用到的,释放函数:

    virDomainFree(dom);

    cpu监控程序:

    void list_info_domain(virDomainPtr domain) {
        virDomainInfo info;
        int interval = 2;
        struct timeval startTime;
        struct timeval endTime;
        int realTime;
        int cpuTime;
        double cpuUsage;
        virDomainGetInfo(domain, &info);
        unsigned long long startCpuTime = info.cpuTime;
        if (gettimeofday(&startTime, NULL) == -1) {
            printf("Failed to get start time\n");
        }
        sleep(interval);
        virDomainGetInfo(domain, &info);
        unsigned long long endCpuTime = info.cpuTime;
        if (gettimeofday(&endTime, NULL) == -1) {
            printf("Failed to get end time\n");
        }
        cpuTime = (endCpuTime - startCpuTime)/1000;
        realTime = 1000000 * (endTime.tv_sec - startTime.tv_sec) + (endTime.tv_usec - startTime.tv_usec);
        cpuUsage = cpuTime / (double)(realTime);
        printf("\t\tstate is %d\n", info.state);
        printf("\t\tvCPU is %d\n", info.nrVirtCpu);
        printf("\t\tMAXmemory is %ld\n", info.maxMem/1024);
        printf("\t\tmemory is %ld\n", info.memory/1024);
        printf("\t\tcpuUsage is %.2f%\n", cpuUsage*100);
    }

    解释一下程序,首先virDomainGetInfo函数,传入刚才我们得到的domain,另外一个参数是要返回的virDomainInfo的结构体变量,其中包含了cpu个数,分配的时间,和分配的mem信息。我们分别取了间隔为2妙的info信息,使用裡面的info.cpuTime运行时间,把后一次减去前一次,然后再除以实际的gettimeofday函数得到host的cpu运行时间,得到一个近似的百分比,反应的是此虚拟机实例的cpu使用情况在整个host的cpu使用情况中的百分比。

    磁盘监控:

    void list_disk_domain(virDomainPtr domain) {
        virDomainBlockStatsStruct stats;
        size_t size;
        const char *disk = "vda";
        size = sizeof(stats);
        int interval = 2;
        virDomainBlockStats(domain, disk, &stats, size);
        long long start_rd_bytes = stats.rd_bytes;
        long long start_wr_bytes = stats.wr_bytes;
        sleep(interval);
        virDomainBlockStats(domain, disk, &stats, size);
        long long end_rd_bytes = stats.rd_bytes;
        long long end_wr_bytes = stats.wr_bytes;
     
        long rd_bytes = end_rd_bytes - start_rd_bytes;
        long wr_bytes = end_wr_bytes - start_wr_bytes;
        int rd_usage = rd_bytes/interval;
        int wr_usage= wr_bytes/interval;
    // printf("%s:\n", virDomainGetName(domain));
        printf("\t\tread: %dbytes/s\n", rd_usage);
        printf("\t\twrite: %dbytes/s\n", wr_usage);
        printf("\t\trd_req: %lld\n", stats.rd_req);
        printf("\t\trd_bytes: %lld\n", stats.rd_bytes);
        printf("\t\twr_req: %lld\n", stats.wr_req);
        printf("\t\twr_bytes: %lld\n", stats.wr_bytes);
    }

    磁盘使用情况的方法和cpu类似,这裡用到的是virDomainBlockStats(domain, disk, &stats, size)这个函数,disk指向的字符串这裡为“vda”,实际使用甚麽你要根据xml裡面的信息

    网络部份这裡我们要用到libvirt中的Network Filters

    openstack实例的libvirt.xml在nova.conf中定义的实例目录下,里面有

    ...
    <interface type='bridge'>
    <source bridge='br100'/>
    <mac address='02:16:3e:23:f3:7d'/>
    <model type='virtio'/>
    <filterref filter="nova-instance-instance-00000007-02163e23f37d">
    <parameter name="IP" value="10.200.200.56" />
    <parameter name="DHCPSERVER" value="10.200.200.54" />
    </filterref>
    </interface>
    ...

    filterref中包括了其他的filters,默认在/etc/libvirt/nwfilter目录下

    你也可以使用virsh管理工具查看具体filter内容

    # virsh nwfilter-dumpxml nova-instance-instance-00000007-02163e23f37d
    Filtering chains

    Filtering chains就是你在目录下看到的许多filters的文件。譬如有arp, 有dhcp, mac等

    在程序中使用libvirt

    int list_network_domain(virDomainPtr domain) {
        const char *path;
        virDomainInterfaceStatsStruct stats;
        size_t size;
        size = sizeof(stats);
        path = "vnet1";
        int interval = 2;
        if( virDomainInterfaceStats(domain, path, &stats, size) )
            return FALSE;
        long long start_rx_bytes = stats.rx_bytes;
        long long start_tx_bytes = stats.tx_bytes;
        sleep(interval);
        if( virDomainInterfaceStats(domain, path, &stats, size) )
            return FALSE;
        long long end_rx_bytes = stats.rx_bytes;
        long long end_tx_bytes = stats.tx_bytes;
        int rx_usage = (end_rx_bytes - start_rx_bytes)/interval;
        int tx_usage = (end_tx_bytes - start_tx_bytes)/interval;
        printf("\t\trx usage: %d bytes/s", rx_usage);
        printf("\trx bytes: %lld bytes", stats.rx_bytes);
        printf("\t\trx packets: %lld", stats.rx_packets);
        printf("\trx errs: %lld\n", stats.rx_errs);
        printf("\t\ttx usage: %d bytes/s", tx_usage);
        printf("\ttx bytes: %lld bytes", stats.tx_bytes);
        printf("\t\ttx packets: %lld", stats.tx_packets);
        printf("\ttx errs: %lld\n", stats.tx_errs);
    }

    这个函数很重要,其中将返回stats指针所指向的内容便是domain中各个网口的信息。这裡有个问题,就是path的值,他是由domain中网卡的名字,不是eth0也不是em0等,而是要通过获取domain的xml中<device>网卡的interface部分中<target dev="vnet0">这一部分中的vnet0,同理前面说得disk裡面的“vda”也是从这裡获取,

    所以你需要运行一下这个程序

        char *xmldesc;
        xmldesc = virDomainGetXMLDesc(dom, 0);
        if ((fp = fopen(virDomainGetName(dom), "w")) == NULL) {
            printf("Cannot open file test\n");
        }
        fprintf(fp,xmldesc);
        fclose(fp);
        free(xmldesc);

    返回的是字符串指针指向了xml的内容,记住这个程序运行好需要free指针。

    via livemoon的博客

    【编辑推荐】

    1. 专题:OpenStack简介与入门指南汇总
    2. OpenStack Compute(Nova)功能分析
    3. 以公司实际应用讲解OpenStack到底是什么(入门篇)
  • 相关阅读:
    7z usecaes
    最新状态
    ABAP 常用FUNCTION (最近工作中用到的)
    又是一个星期五
    阿牛
    自我定位的重要性
    smortform 创建
    换个角度想或许不一样
    为什么喜欢跟男生聊天小小分析
    BDC 代码设置
  • 原文地址:https://www.cnblogs.com/zhangzhang/p/2381479.html
Copyright © 2011-2022 走看看