【openGauss告警检测机制】cpu负载检测

系列文章目录

openGauss数据库告警机制介绍
openGauss告警检测机制-慢盘检测



前言

操作系统的性能和稳定性是数据库高效运行及用户体验的关键保障,而CPU负载作为衡量系统健康的核心指标,其监控与预警尤为重要。openGauss数据库提供了CPU负载检测与实时告警机制,为用户提供了快速识别并响应系统异常的能力。


一、原理

在 Linux 系统中,/proc/stat 是一个虚拟文件,位于 /proc 文件系统下,用于提供系统自启动以来的各项统计信息,包括 CPU 使用时间、上下文切换次数、中断数量、启动进程数等。由于 /proc 是内存中的伪文件系统,/proc/stat 不占用外存空间,而是动态反映系统的运行状态 。

运行cat /proc/stat命令后,可以看到如下输出:

在这里插入图片描述

各列的含义如下,其中首行为所有CPU对应列值的总和

字段描述
user用户态时间(非特权进程)
nice用户态时间(低优先级进程)
system内核态时间
idle空闲时间
iowaitI/O 等待时间
irq硬中断时间
softirq软中断时间
steal虚拟化环境下被其他 OS 占用的时间
guest运行虚拟 CPU 的时间
guest_nice低优先级虚拟 CPU 时间

通过读取 /proc/stat 中 CPU 时间的变化,可计算任意时间间隔内的 CPU 利用率。

第一次采样:

  • total1 = ((user1 + nice1 + system1 + idle1 + iowait1 + irq1 + softirq1 + steal1 + guest1 + guest_nice1))
  • idle_total1 = idle1

第二次采样:

  • total2 = ((user2 + nice2 + system2 + idle2 + iowait2 + irq2 + softirq2 + steal2 + guest2 + guest_nice2))
  • idle_total2 = idle2

CPU利用率计算

cpuUtil = ((total2 - total1) - (idle_total1 - idle_total2)) / (total2 - total1)

二、检测方法

1、每隔1秒,通过sscanf_s函数扫描出所有CPU各个列值的和,累加计算cpuTotalTime。

status_t SetCpuStatInfo(const char* line, CpuSimpleInfo* cpuSimpleInfo) {
    const int cpuNameLen = 8;
    const int cpuInfoCount = 11;
    char cpuName[cpuNameLen] = {0};
    CpuInfo* tmpCpuInfo = &(cpuSimpleInfo->cpuInfo);
    errno_t rc = sscanf_s(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", cpuName, cpuNameLen,
        &tmpCpuInfo->cpuUser, &tmpCpuInfo->cpuNice, &tmpCpuInfo->cpuSys, &tmpCpuInfo->cpuIdle, &tmpCpuInfo->cpuIwait,
        &tmpCpuInfo->cpuHardirq, &tmpCpuInfo->cpuSoftirq, &tmpCpuInfo->cpuSteal, &tmpCpuInfo->cpuGuest,
        &tmpCpuInfo->cpuGuestNice);
    check_sscanf_s_result(rc, cpuInfoCount);
    if (rc != cpuInfoCount) {
        write_runlog(ERROR, "get cpu info from %s failed, line %s, count %d.\n", FILE_CPUSTAT, line, rc);
        return CM_ERROR;
    }

    cpuSimpleInfo->cpuIdleTime = tmpCpuInfo->cpuIdle;
    cpuSimpleInfo->cpuUserTime = tmpCpuInfo->cpuUser;
    cpuSimpleInfo->cpuSystemTime = tmpCpuInfo->cpuSys;
    cpuSimpleInfo->cpuTotalTime = 0;
    uint64* value = (uint64*)tmpCpuInfo;
    uint32 len = (uint32)sizeof(CpuInfo) / sizeof(uint64);
    for (uint32 i = 0; i < len; ++i) {
        cpuSimpleInfo->cpuTotalTime += *(value++);
    }
    return (strcmp(cpuName, "cpu") == 0) ? CM_SUCCESS : CM_ERROR;
}

2、将当前采集的数据与上一次采集到的数据相减得到两次采样之间CPU的使用时间,除以总时间可计算得到CPU利用率

status_t CheckCpuStatus(CpuStatInfo* cpuStatInfo) {
    CpuSimpleInfo curCpuInfo = {0};
    char line[MAX_PATH_LEN] = {0};
    FILE* fp = fopen(FILE_CPUSTAT, "re");
    if (fp == NULL) {
        write_runlog(ERROR, "failed to open file %s.\n", FILE_CPUSTAT);
        return CM_ERROR;
    }
    while (fgets(line, sizeof(line), fp)!= NULL) {
        if (SetCpuStatInfo(line, &curCpuInfo)!= CM_SUCCESS) {
            write_runlog(ERROR, "failed to set cpu stat info, line=[%s].\n", line);
            FCLOSE_AND_RESET(fp);
            return CM_ERROR;
        }
        break;
    }
    fclose(fp);
    if (cpuStatInfo->oldCpuInfo.cpuTotalTime != 0) {
        uint64* oldValue = (uint64*) &(cpuStatInfo->oldCpuInfo);
        uint64* curValue = (uint64*) &(curCpuInfo);
        uint32 count = (uint32)sizeof(CpuSimpleInfo) / sizeof(uint64);
        for (uint32 i = 0; i < count; ++i) {
            if (*(curValue++) < *(oldValue++)) {
                write_runlog(ERROR, "get cpu info wrong, curCpuTime(%lu) < oldCpuTime(%lu). and index=[%u]\n",
                    *(curValue--), *(oldValue--), i);
                errno_t rc = memcpy_s(&(cpuStatInfo->oldCpuInfo), sizeof(CpuSimpleInfo), &(curCpuInfo), sizeof(CpuSimpleInfo));
                securec_check_errno(rc, (void)  rc);
                return CM_ERROR;
            }
        }
        uint64 totalTimeInterval = curCpuInfo.cpuTotalTime - cpuStatInfo->oldCpuInfo.cpuTotalTime;
        uint64 sysTimeInterval = curCpuInfo.cpuSystemTime - cpuStatInfo->oldCpuInfo.cpuSystemTime;
        uint64 userTimeInterval = curCpuInfo.cpuUserTime - cpuStatInfo->oldCpuInfo.cpuUserTime;
        uint64 idleTimeInterval = curCpuInfo.cpuIdleTime - cpuStatInfo->oldCpuInfo.cpuIdleTime;
        cpuStatInfo->cpuUtil = (float)(totalTimeInterval - idleTimeInterval) / (float)totalTimeInterval * PERCENT;
        cpuStatInfo->cpuSystemUtil = (float)sysTimeInterval / (float)totalTimeInterval * PERCENT;
        cpuStatInfo->cpuUserUtil = (float)userTimeInterval / (float)totalTimeInterval * PERCENT;
    }
    errno_t rc = memcpy_s(&(cpuStatInfo->oldCpuInfo), sizeof(CpuSimpleInfo), &(curCpuInfo), sizeof(CpuSimpleInfo));
    securec_check_errno(rc, (void)  rc);
    return CM_SUCCESS;
}

3、如果CPU使用率超出指定的阈值,则产生一次告警

void ReportSystemStatusAlarm(const SystemStatInfo* systemStat, const EnvThreshold* threshold) {
    int cpuUsed = (int)systemStat->cpuStatInfo.cpuUtil;
    if (threshold->cpu > 0 && cpuUsed > threshold->cpu) {
        write_runlog(LOG, "system cpu usage is %u, threshold is %u, report alarm.\n", cpuUsed, threshold->cpu);
        ReportCpuAbnormalAlarm(cpuUsed, threshold->cpu);
    }
    .......
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值