计算机性能监控体系:Quark2.0

举报
信也科技布道师 发表于 2024/11/04 12:18:03 2024/11/04
【摘要】 一、背景在过去的IT日常支持场景中,因为服务的用户、终端、系统等等因业务而异,往往会遇到以下类似这些问题或需求:• IT工程师定位终端问题跨越不同的平台或系统,低效繁琐• 用户想要获取一些个人相关的IT环境信息,只能咨询IT部门• 电脑终端的软硬件资源类性能消耗无法集中宏观监控、数字化管理• 主动预判终端问题的客观依据和快速定位能力有差异化通过建设一套“IT用户终端信息一体化管理平台”,采集...

一、背景

在过去的IT日常支持场景中,因为服务的用户、终端、系统等等因业务而异,往往会遇到以下类似这些问题或需求:

IT工程师定位终端问题跨越不同的平台或系统,低效繁琐

用户想要获取一些个人相关的IT环境信息,只能咨询IT部门

电脑终端的软硬件资源类性能消耗无法集中宏观监控、数字化管理

主动预判终端问题的客观依据和快速定位能力有差异化

通过建设一套“IT用户终端信息一体化管理平台”,采集用户信息、机器信息、软件信息、权限信息、网络信息等等,实现数据入库、实时更新、可视化。具备提供一站式查询管理、缩短case定位时间、集中数字化管理、提前预警终端软硬件风险等能力。

其中针对电脑及性能数据的采集,面临着指标多样性、数据实时性存储、系统差异性等高要求,下面针对电脑终端信息采集的Quark 2.0体系进行详细的介绍。


二、架构

Quark 2.0体系是为“IT用户终端信息一体化管理平台”建立的一套计算机性能监控体系,作为IT资产管理的延伸,帮助IT人员完成日常维护、故障排查和资源统计等工作。

该体系架构示意图如下:

安装在办公电脑的Agent按单位时间一次的心跳频率,采集计算机的CPU、内存、磁盘、网络、电池、进程占用等信息上报给Master集群,并把历史数据打点存入InfluxDB。支持Windows和MacOS两种主流的办公电脑操作系统。Master集群接收到Agent上报的心跳数据,将其存入Redis,并通过Etcd进行节点注册和健康检测。Registry集群作为IT一体化自助查询平台的后端服务器集群,承担了多个数据来源的集中查询、日志记录、任务调度等功能。

Agent客户端支持采集的数据类型如下:

心跳上报:实时获取最新数据,新数据会覆盖旧数据
数据打点:存储最新数据,保留旧数据

类型

指标

采集方式

备注

系统



操作系统

心跳上报

Windows/MacOS,包括具体版本号

计算机名

心跳上报


内核架构

心跳上报

例:x86_64

硬件



序列号

心跳上报


制造厂商

心跳上报


产品型号

心跳上报


CPU







型号

心跳上报


厂商

心跳上报


核数

心跳上报


占用核数

数据打点


频率

心跳上报


使用率

数据打点

user、sys、iowait、idle、busy

温度

数据打点


内存



容量

心跳上报/数据打点

单位:GiB

使用量

心跳上报/数据打点

单位:GiB

频率

心跳上报


磁盘







总空间

心跳上报/数据打点

单位:GiB

已使用空间

心跳上报/数据打点

单位:GiB

分区

心跳上报/数据打点

单位:GiB

驱动

心跳上报

包括型号、类型、状态

读写字节数

数据打点

单位:GiB

读写速度

数据打点

单位:KiB/s

读写次数

数据打点


网络








网络名

心跳上报


MTU

心跳上报


Mac地址

心跳上报


IP地址

心跳上报


驱动

心跳上报

包括名称、描述、厂商、产品号

上下行字节数

数据打点

单位:GiB

上下行数据包总数

数据打点


上下行速度

数据打点

单位:KiB/s

电池




状态

心跳上报/数据打点


状态码

心跳上报/数据打点

例:有无电池、使用电池/AC电源、是否满电

剩余电量

心跳上报/数据打点


剩余使用时间

心跳上报/数据打点

部分系统版本不支持此指标

进程



占用CPU进程

数据打点

记录前五个



占用内存进程

数据打点

占用IO进程

数据打点

WiFi



ESSID

数据打点


BSSID

数据打点


信号强度

数据打点


联网情况




ping内网

数据打点

min_rtt、max_rtt、avg_rtt、std_dev_rtt、loss



ping外网

数据打点

ping网关

数据打点

DNS解析

数据打点

是否能解析特定域名


三、数据采集

Agent客户端基于Go语言开发,通过gopsutil库、wmic等采集计算机数据。对于MacOS,则以解析ioreg、system_profiler等指令获取对应指标。由于采集指标众多,下面仅以电池和WiFi作为示例,讲解具体的数据采集原理。

电池信息

对于Windows,通过wmic指令调用Win32_Batteryapi,获取电脑的状态、状态码、剩余电量等信息。

//go:build windows

// +build windows


package battery


import (

    "errors"

    "math"


    "git.ppd.com/quark/pkg/logger"

    "git.ppd.com/quark/pkg/metrics"

    "github.com/shopspring/decimal"

    "github.com/yusufpapurcu/wmi"

)


type batteryInfo struct {

    Availability aStatus

    BatteryStatus bStatus

    Status string

    EstimatedChargeRemaining uint16

    EstimatedRunTime uint32

    DesignCapacity uint32

    FullChargeCapacity uint32

}


func win32BatteryInfo() (*batteryInfo, error) {

    var batteryInfo []batteryInfo

    err := wmi.Query("SELECT * FROM Win32_Battery", &batteryInfo)

    if err != nil {

        return nil, err

    }

    if len(batteryInfo) > 0 {

        return &batteryInfo[0], nil

    }

    return nil, errors.New("empty battery info")

}


func BatteryInfo() metrics.BatteryInfo {

    battery, err := win32BatteryInfo()

    if err != nil {

        logger.Errorf("get BatteryInfo error: %s", err.Error())

        return metrics.BatteryInfo{Status: "NoBattery"}

    }

    var estimatedRunTime float64

    if battery.EstimatedRunTime == uint32(math.Pow(2, 32)/60) {

        estimatedRunTime = 0

    } else {

        tmpRunTime := decimal.NewFromFloat(float64(battery.EstimatedRunTime) / 60)

        estimatedRunTime, _ = tmpRunTime.Round(1).Float64()

    }

    return metrics.BatteryInfo{

        Status: battery.Status,

        Availability: metrics.BatStatus{

            Code: uint16(battery.Availability),

            Desc: battery.Availability.String(),

        },

        BatteryStatus: metrics.BatStatus{

            Code: uint16(battery.BatteryStatus),

            Desc: battery.BatteryStatus.String(),

        },

        CurrentCap: float64(battery.FullChargeCapacity),

        DesignCap: float64(battery.DesignCapacity),

        EstimatedTime: estimatedRunTime,

        EstimatedPower: int64(battery.EstimatedChargeRemaining),

    }

}

对于MacOS,则通过解析system_profiler SPPowerDataType和pmset -g batt指令的返回获取电池的对应信息。

WiFi信息

对于Windows,通过解析netsh wlan show interfaces指令的返回获取WiFi的BSSID、ESSID和信号强度。

对于MacOS,则通过解析/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I和ioreg -l -n AirPortDriver | perl -lne print $1 if $_ =~ /IO80211BSSID.*<(.*)>/指令获取WiFi的对应信息。


四、心跳上报

QRPC组件

Master集群与Agent客户端之间基于自研的QRPC组件进行长连接通信。与市面上常见的开源RPC组件相比,QRPC组件具有通信简单、连接管理透明、完全可控等优点。

名称

开发者

简述

优点

缺点

GRPC

Google

功能强大,是一款非常完善的rpc框架

功能强大完善;多语言支持;序列化效率高

学习、维护的成本较高;引入大量第三方库,存在潜在风险

net/rpc(标准库)

GO Team

内置RPC包

标准库内置,无需引入新库

TCP网络连接管理缺失;序列化(GO内置)效率较低

QRPC

自研

用于Master集群与Agent客户端的通信

轻量化框架;通信简单;连接管理透明

适用性较窄

通信过程

首次心跳上报时,Agent需要先从Etcd中获取一个可用的Master节点,并采用Hash算法保证Master集群的负载均衡。获取到Master节点之后,建立长连接并写入Agent配置。Master节点接收到连接请求之后完成握手连接,并将心跳数据存储到Redis中,完成本次通信。如果发生意外导致连接中断或Master节点挂掉,Agent会自动重新获取新的可用节点。

获取Master节点实现如下:

import (

    "encoding/json"

    "fmt"

    "hash/fnv"


    "git.ppd.com/quark/agent_v2/config"

    "git.ppd.com/quark/agent_v2/stats"

    "git.ppd.com/quark/pkg/client/etcd"

    "git.ppd.com/quark/pkg/logger"

    "git.ppd.com/quark/pkg/metrics"

)


func (a *Agent) getMasterIP() (string, error) {

    // 获取本机IP

    localIP := stats.IP()

    if localIP == "" {

        return "", fmt.Errorf("get local_ip failed: local_ip is <nil>")

    }


    // 获取所有可用的Master节点

    // 要求:当前节点负载低于预设的最大负载

    var assignAddrs []string

    maxLoad := config.Config().MasterConfig.MaxLoad

    masterInfo := registryMasterNode()

    for _, v := range masterInfo {

        if v.ReportNum < maxLoad {

            assignAddrs = append(assignAddrs, v.IP)

        }

    }


    // Hash算法获取Master节点

    hashValue := hash(localIP)

    index := int(hashValue) % len(assignAddrs)

    masterNode := assignAddrs[index]


    return masterNode, nil

}


// 获取已注册的Master节点

func registryMasterNode() map[string]*metrics.MasterHeartBeat {

    tmp := make(map[string]*metrics.MasterHeartBeat, 0)


    // etcd初始化

    cfg := config.Config().EtcdConfig

    etcd.Init(cfg.EtcdAddr)

    defer func() {

        if err := etcd.EClient.Close(); err != nil {

            logger.Errorf("close etcd client failed: %s", err.Error())

        }

    }()


    resp, err := etcd.EClient.Get(cfg.MasterPath, clientv3.WithPrefix())

    if err != nil {

        logger.Errorf("从etcd获取master节点列表失败: %s", err.Error())

        return tmp

    }


    for k, v := range resp.Kvs {

        master := &metrics.MasterHeartBeat{}

        err := json.Unmarshal(v.Value, &master)

        if err != nil {

            logger.Errorf("master节点%d序列化失败: %s", k, err.Error())

            continue

        }

        tmp[master.IP] = master

    }


    return tmp

}


// Hash: string to int

func hash(key string) uint32 {

    h := fnv.New32a()

    h.Write([]byte(key))

    return h.Sum32()

}

Agent在线状态管理

Master获取Agent在线状态,主要是通过Redis的键过期订阅机制。预先设置Agent键的过期时间,每次心跳上报时更新值,同时重置初始时间。超过过期时间仍未更新,则视为Agent已离线。


五、历史数据打点

InfluxDB

InfluxDB是一个用于存储和分析时间序列数据的开源数据库,主要特性如下:

内置HTTP接口,使用方便

数据可以打标记,查询很灵活

类SQL的查询语句

安装管理简单,并且读写数据高效

支持实时查询

Quark 2.0体系基于InfluxDB v1的HTTP POST方式,对Agent采集的历史数据进行打点存储。

InfluxDB-Relay

由于InfluxDB v1开源版不支持集群模式,故采用官方推荐的社区开源高可用方案InfluxDB-Relay。

InfluxDB-Relay为InfluxDB提供双写能力,确保其中一个节点挂掉后数据不会丢失。注意InfluxDB-Relay只代理写流量,查询数据时直接访问InfluxDB。

influxdb-relay.toml 配置如下:

[[http]]

name = "influx-http"

bind-addr = "127.0.0.1:9096"

output = [

{ name="db1", location = "http://XX.XXX.XX.XXX:8086/write" },

{ name="db2", location = "http://XX.XXX.XX.XXX:8086/write" },

{ name="db3", location = "http://XX.XXX.XX.XXX:8086/write" },

]

页面交互

“IT用户终端信息一体化管理平台”支持根据域账号和计算机名查询对应信息,包括用户的基本信息、名下资产和所在群组、办公电脑的IT资产信息、心跳数据和历史数据等。



六、未来展望

在后续的平台建设中,“IT用户终端信息一体化管理平台”还将完善接入更完整的其他用户信息,例如各相关系统权限、入网认证各环节状态、虚拟资产等信息,进行一体化关联,为实现终端智能化管理夯实基础。


【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。