关于监控服务器指标、CPU、内存、警报的一些解决方案

news2024/9/21 13:37:45

文章目录

  • 关于监控服务器指标、CPU、内存、警报的一些解决方案
    • `Prometheus` + `Grafana` 配置 `IRIS` / `Caché` 监控服务器
      • `Prometheus`
        • 简介
        • 特点
        • 架构图
      • `Grafana`
        • 简介
        • 特点
      • 配置流程
    • 自定义`Prometheus`接口定义
    • 配置 `Exporter` 监控服务器系统资源
      • 简介
      • 配置流程
    • 使用 `Alertmanager`报警
      • 简介
      • 配置流程
    • 基于`M`实现监控服务器,并用邮件报警
      • 解析`Prometheus`数据接口信息
      • 使用嵌入式`Python`方式获取系统`CPU`、内存等
        • `python`模块之`psutil`详解
          • `CPU`相关
          • `Memory`内存相关
          • `Disk`相关
          • `Network`相关
          • `Process`相关
        • 通过嵌入式`Python`调用`psutil`库
      • 使用邮件发送报警信息
        • 使用`M`发送邮件发送消息
        • 通过配置文件`csv`文件,来获取维护指标,进行邮件报警。
    • 总结
    • 思考

关于监控服务器指标、CPU、内存、警报的一些解决方案

本文章主要介绍以下几个章节内容:

  • Prometheus + Grafana 配置 IRIS / Caché 监控服务器
  • 自定义Prometheus接口定义 - 配置 Caché 监控服务
  • 配置 Exporter 监控服务器系统资源
  • 使用 Alertmanager报警
  • 基于M实现监控服务器,并用邮件报警
    • 解析Prometheus数据接口信息
    • 使用嵌入式Python方式获取系统CPU、内存等
    • 使用邮件发送报警信息

Prometheus + Grafana 配置 IRIS / Caché 监控服务器

首先我们介绍一下如何用IRIS结合Prometheus + Grafana的使用,在介绍如何配置之前我们先了简单了解一下工具。

Prometheus

简介

Prometheus是一个最初在SoundCloud上构建的开源系统监视和警报工具包 。 自2012年成立以来,许多公司和组织都采用了Prometheus,该项目拥有一个非常活跃的开发人员和用户社区。它现在是一个独立的开源项目,可以独立于任何公司进行维护。为了强调这一点,并澄清项目的治理结构,Prometheus2016年加入 云计算本地计算基金会,作为继Kubernetes之后的第二个托管项目。

特点

  • 具有由度量名称和键/值对标识的时间序列数据的多维数据模型。
  • 一个灵活的查询语言 来利用这一维度。
  • 不依赖分布式存储,单个服务器节点是自治的。
  • 时间序列收集通过 HTTP 上的拉模型发生。
  • 通过中间网关支持推送时间序列。
  • 通过服务发现或静态配置发现目标。
  • 多种图形和仪表板支持模式。

架构图

在这里插入图片描述

Grafana

简介

Grafana是一个跨平台的开源的度量分析和可视化工具,可以通过将采集的数据查询然后可视化的展示,并及时通知。

特点

  • 展示方式:快速灵活的客户端图表,面板插件有许多不同方式的可视化指标和日志,官方库中具有丰富的仪表盘插件,比如热图、折线图、图表等多种展示方式。
  • 支持多种数据源:GraphiteInfluxDBOpenTSDBPrometheusElasticsearchCloudWatchKairosDB等。
  • 通知提醒:以可视方式定义最重要指标的警报规则,Grafana将不断计算并发送通知,在数据达到阈值时通过SlackPagerDuty等获得通知。
  • 混合展示:在同一图表中混合使用不同的数据源,可以基于每个查询指定数据源,甚至自定义数据源。
  • 注释:使用来自不同数据源的丰富事件注释图表,将鼠标悬停在事件上会显示完整的事件元数据和标记。
  • 过滤器:Ad-hoc过滤器允许动态创建新的键/值过滤器,这些过滤器会自动应用于使用该数据源的所有查询。

配置流程

  1. 下载Prometheus,选择操作系统,下载对应安装包,以windows为例。
  • 下载地址:https://prometheus.io/download/

在这里插入图片描述

  1. 下载完成后,直接解压在所需目录即可。解压后进入目录直接运行premetheus.exeprometheus默认端口为9090

在这里插入图片描述

  1. 在浏览器输入地址、即可查看监控页面。
  • 地址 - http://localhost:9090/

在这里插入图片描述

  1. 配置监控服务器信息,编辑 prometheus-2.27.1.windows-amd64/prometheus.yml文件。在scrape_configs:输入以下代码:
    • 这里以我的私有服务器地址为例:https://8.142.29.250:2443/api/monitor/metrics。

输入以下代码:

  - job_name: "250-IRIS"
    metrics_path:  /api/monitor/metrics
    scheme: https
    tls_config:
      insecure_skip_verify: true
    static_configs:
    - targets: ['8.142.29.250:2443']

其中:

  • job_name - 服务器名称。
  • metrics_path - 监控服务器地址路径。
  • scheme - 网络协议。
  • tls_config - insecure_skip_verify - 过滤完成验证。
  • static_configs - targets - IP端口号。
  1. prometheus.yml文件修改完成后,重新启动prometheus.exe程序,进入到Status->Targets下,即可看到添加的监控服务器信息;

在这里插入图片描述

  1. 监控具体指标,点击Graph->勾选UseLocalime->输入监控指标iris_cpu_usage->点击Excute->选择监控时长范围30min
  • iris_cpu_usage - 代表CPU使用率。

在这里插入图片描述

说明:这里监控指标为服务器接口里的具体指标,输入接口地址具体查看。

在这里插入图片描述

  1. 由于Prometheus展示的信息相对简单,图表类型也比较少,下面介绍如何使用Grafana展示数据。输入Grafana地址,下载对应版本。
  • 下载地址:https://grafana.com/grafana/download?

在这里插入图片描述

  1. 下载后直接运行安装,安装完成后进入grafana/bin目录下,双击运行garafana-server.exe
    • garafana默认端口为3030
    • 访问地址:http://localhost:3000/
    • 默认用户名密码admin/admin

在这里插入图片描述

  1. grafana里添加数据源Data Source

在这里插入图片描述

  1. 选择Prometheus

在这里插入图片描述

  1. 填写数据源信息,并保存。
  • Name - Prometheus
  • Url - http://localhost:9090

在这里插入图片描述

  • 点击Save&test显示测试成功。

在这里插入图片描述

  1. 创建模版,点击Dashboards->点击Browse->输入模版名称->New->NewDashboard

在这里插入图片描述

  1. 点击Add a new panel

在这里插入图片描述

  1. 选择数据源Data source,指标iris_cpu_usage -> Run query
  • Title - 修改仪表盘名称。

在这里插入图片描述

  1. 输入仪表盘名称,点击保存即可。

在这里插入图片描述

  1. 最终效果,依次类推建立多个监控指标。
  • iris_csp_sessions - 会话使用数
  • iris_cpu_usage - cpu使用率
  • iris_system_alerts - 系统警报数
  • iris_process_count - 进程数量
  • iris_glo_ref_per_sec - Global每秒引用数量

在这里插入图片描述

自定义Prometheus接口定义

那么我们是否可以自定义Prometheus接口呢?

答案肯定是可以的,整好 Caché 没有自带的监控服务,所以我们给Caché 自定义个一个监控服务接口。

  1. 首先我们需要创建一个Rest接口类M.Metrics
Class M.Metrics Extends %CSP.REST
{
}
  1. Portal中配置Rest接口,系统->安全管理->Web应用程序->编辑Web引用程序。
  • 名称 - /api/metrics
  • 命名空间 - 选择Rest接口类所在命名空间
  • 分派类 - M.Metrics

在这里插入图片描述

  1. 编写Rest接口逻辑,下面展示主要业务逻辑代码。
  • 基础仪表盘接口
ClassMethod GetDashboardMetrics(ByRef array As %DynamicArray) As %Status
{
	s dashboard = ##class(SYS.Stats.Dashboard).Sample()
	s properties = ##class(%Dictionary.ClassDefinition).%OpenId(dashboard.%ClassName(1)).Properties
	for i = 1 : 1 : properties.Count() {
		s property = properties.GetAt(i)
		s propertyName = property.Name
		s propertyValue = $property(dashboard, propertyName)
		if ((propertyValue '= "") && ('$match(propertyValue, ".*[-A-Za-z ]+.*"))) {
			s metricsName = ..CamelCase2Underscore(propertyName)
			s metricsValue = propertyValue
			s obj = {}
			s obj.key = metricsName
			s obj.val = metricsValue
			d array.%Push(obj)
		}
	}
	q $$$OK
}
  • 系统使用情况
d ##class(SYS.Metrics).GetMainMetrics(""0.pValues, .pStatus, .pMsg)
  • 系统监视器统计
d ##class(SYS.Metrics).GetGlobalStatistics(""0.pValues, .pStatus, .pMsg)
  • ECP 数据统计
d ##class(SYS.Metrics).GetECPStatistics(""0.pValues, .pStatus, .pMsg)
  • 磁盘和缓冲区数据统计
d ##class(SYS.Metrics).GetStatistics(""0.pValues,.pStatus,.pMsg)
  • 许可数据统计
ClassMethod GetLicenseStatistics(ByRef array As %DynamicArray)
{
    s licenseUsed = ##class(%SYSTEM.License).LUConsumed()
    s obj = {}
    s obj.key = ..#PREFIX _ "_license_used"
    s obj.val = licenseUsed
    d array.%Push(obj)

    s licenseAvailable=##class(%SYSTEM.License).LUAvailable()
    s obj = {}
    s obj.key = ..#PREFIX _ "_license_avail"
    s obj.val = licenseAvailable
    d array.%Push(obj)

    s licenseTotal=##class(%SYSTEM.License).GetUserLimit()
    s obj = {}
    s obj.key = ..#PREFIX _ "_license_total"
    s obj.val = licenseTotal
    d array.%Push(obj)

    s obj = {}
    s obj.key =..#PREFIX _ "_license_load"
    s obj.val = $fn((licenseUsed / (licenseAvailable + licenseUsed))"N""4")
    d array.%Push(obj)
}
  • 开放性事务数据统计
ClassMethod GetOpenTransactionStatistics(ByRef array As %DynamicArray)
{
	if ($zv [ "Cache") {
		s index = "^CacheTemp.SysMetrics"
	} else {
		s index = "^IRIS.Temp.SysMetrics"
	}
	if (@index@("Transactions")) = "OK" {
		s val = 1
	} else {
		s val = 0
	}
    s obj = {}
    s obj.key = ..#PREFIX _ "_open_transaction"
    s obj.val = val
    d array.%Push(obj)
}
  • 数据库情况
ClassMethod GetDatabaseStatistics(ByRef array As %DynamicArray)
{
	s statement = ##class(%SQL.Statement).%New()
	s sc = statement.%PrepareClassQuery("%SYS.DatabaseQuery""FreeSpace")
	s rs = statement.%Execute()
	while (rs.%Next()) {
	    s databaseName = rs.%Get("DatabaseName")
	    s freeRate = rs.%GetData(7)
	    s availableNum = rs.%Get("AvailableNum")
	    s diskFreeSpaceNum = rs.%Get("DiskFreeSpaceNum")
	    
 		s obj = {}
   	 	s obj.key =..#PREFIX _ "_database_free"
    	s obj.val = (100 - freeRate) / 100
    	
    	s tag = {}
		s tag.id = databaseName
	    s obj.tag = tag
	    d array.%Push(obj)
	}
}
  • 把所有数据组装到一起。
ClassMethod GetMetrics()
{
	s array = []
	
	#; 基础仪表盘
	d ..GetDashboardMetrics(.array)
	
	#; 系统使用情况
	d ##class(SYS.Metrics).GetMainMetrics(""0.pValues, .pStatus, .pMsg)
	d ..ParseJson(.pValues, .array)
	
	#; 系统监视器统计
	d ##class(SYS.Metrics).GetGlobalStatistics(""0.pValues, .pStatus, .pMsg)
	d ..ParseJson(.pValues, .array)
	
	#; ECP 数据统计
	d ##class(SYS.Metrics).GetECPStatistics(""0.pValues, .pStatus, .pMsg)
	d ..ParseJson(.pValues, .array)
	
	#; 磁盘和缓冲区数据统计
	d ##class(SYS.Metrics).GetStatistics(""0.pValues,.pStatus,.pMsg)
	d ..ParseJson(.pValues, .array)
	
	#; 许可数据统计
	d ..GetLicenseStatistics(.array)
	
	#; 开放性事务数据统计
	d ..GetOpenTransactionStatistics(.array)
	
	#; 数据库情况
	d ..GetDatabaseStatistics(.array)

	q array
}
  • 将数据解析成Prometheus数据格式。

prometheus将所有数据保存为timeseries data,用metric namelabel区分,label是在metric name上的更细维度的划分,其中的每一个实例是由一个float64timestamp组成,只不过timestamp是隐式加上去的,#HELP代表指标的注释信息,#TYPE用于定义样本的类型注释信息。如下示例:

# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0
  • metrics name - 为go_gc_duration_seconds
  • label - 为quantile="0"
  • float64 - 为0
ClassMethod Metrics2Prometheus() As %Status
{
    s %response.ContentType = "text/plain;version=0.0.4;charset=utf-8"
    s array = ..GetMetrics()
    s iter = array.%GetIterator()
    while iter.%GetNext(.key, .json) { 
		s str =  json.key
		if (json.%IsDefined("tag")) {
			s tag = json.tag
			s tagIter = tag.%GetIterator()
			s str = str _ "{" 
			while tagIter.%GetNext(.tagKey, .tagVal) { 
				s str = str _ tagKey _ "=" _ """" _ tagVal _ """"  _ ","
			}
			s str = $e(str, 1* - 1) _ "}" 
		}
		w str _" "_ json.val  _ $c(10)
    }
    q $$$OK
}
  • 配置路由
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
	<Route Url="/prometheus" Method="GET" Call="Metrics2Prometheus" />
	<Route Url="/json" Method="GET" Call="Metrics2Json" />
</Routes>
}
  1. 在界面输入自定义配置的Prometheus接口地址。
  • prometheus格式地址接口:http://localhost:57772/api/metrics/prometheus

在这里插入图片描述

  • Json格式地址接口:http://localhost:57772/api/metrics/json

在这里插入图片描述

  1. prometheus.yml配置文件中添加自定义的接口。代码如下:
  - job_name: "localhost-Cache"
    metrics_path:  /api/metrics/prometheus
    static_configs:
    - targets: ['localhost:57772']
  1. 重新启动prometheus,查看配置界面。这样我们就可以给Caché配置一个自定义的接口拉。

在这里插入图片描述

配置 Exporter 监控服务器系统资源

  • 通过服务器配置Exporter监控服务器的系统信息,例如内存使用情况,CPU使用情况。

简介

Prometheus提供监控数据源的应用都可以被成为Exporter,比如Node Exporter则用来提供节点相关的资源使用状况,而Prometheus从这些不同的Exporter中获取监控数据,然后可以在诸如Grafana这样的可视化工具中进行结果的显示。

广义上讲所有可以向Prometheus提供监控样本数据的程序都可以被称为一个Exporter。而Exporter的一个实例称为target,如下所示,Prometheus通过轮询的方式定期从这些target中获取样本数据。

在这里插入图片描述

配置流程

  1. 下载windows_exporter-0.21.0-amd64.msi文件后,直接双击运行;
  • 下载地址:https://github.com/prometheus-community/windows_exporter/releases

在这里插入图片描述

  1. windows_exporter默认端口号为9182,运行后浏览器访问地址, 出现以下信息,说明安装成功。
  • 地址:http://localhost:9182/metrics

在这里插入图片描述

  1. Exporter接口添加到Prometheus中。
  - job_name: "localhost-Exporter"
    metrics_path:  /metrics
    static_configs:
    - targets: ['localhost:9182']

在这里插入图片描述

使用 Alertmanager报警

简介

Alertmanager是一个独立的告警模块,接收Prometheus等客户端发来的警报,之后通过分组、删除重复等处理,并将它们通过路由发送给正确的接收器。

Prometheus 的报警分为两部分:

  • Prometheus 服务器中的警报规则向警报管理器(Alertmanager)发送警报。
  • 警报管理器负责管理这些警报,包括告警信息进行去重,降噪,分组等,并通过丰富的告警通知渠道,如电子邮件、微信、钉钉、Slack等常用沟通工具发出通知。

配置流程

  1. 下载Prometheus,选择操作系统,下载对应安装包,下载完毕后并挤压,以windows为例。
  • 下载地址:https://github.com/prometheus/alertmanager/releases

在这里插入图片描述

  1. 双击alertmanager.exe,启动alertmanager服务,浏览器访问端口地址可以看到默认提供的 UI 页面。
  • 端口 - 9093
  • 地址 - http://localhost:9093/#/alerts

在这里插入图片描述

  1. AlertManager 默认配置文件为 alertmanager.yml,打开配置文件,配置使用 Email 方式通知报警信息,这里以 QQ 邮箱为例,配置信息如下:
  • global - 全局配置,包括报警解决后的超时时间、SMTP 相关配置、各种渠道通知的 API 地址等等。
  • route - 用来设置报警的分发策略,它是一个树状结构,按照深度优先从左向右的顺序进行匹配。
  • receivers - 配置告警消息接受者信息,例如常用的 emailwechatslackwebhook 等消息通知方式。
  • inhibit_rules - 抑制规则配置,当存在与另一组匹配的警报时,抑制规则将禁用与一组匹配的警报(目标)。
global:
  resolve_timeout: 5m
  smtp_from: 'xxxx@qq.com'
  smtp_smarthost: 'smtp.qq.com:465'
  smtp_auth_username: 'xxxx@qq.com'
  smtp_auth_password: 'xxxxxxxxxxxxxx'
  smtp_require_tls: false
  smtp_hello: 'qq.com'

route:
  group_by: ['alertname']
  group_wait: 5s
  group_interval: 5s
  repeat_interval: 5m
  receiver: 'email'
receivers:
- name: 'email'
  email_configs:
  - to: 'xxxxx@mediway.cn'
    send_resolved: true

inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['alertname', 'dev', 'instance']
  1. 接下来,需要在 Prometheus 配置 AlertManager 服务地址以及告警规则,新建报警规则文件 alert_rules.yml,,放在prometheus.yml同级路径下,配置如下:
  • name - 规则名称,可自己定义。
  • alert - 报警名称,当触发报警时,会作为邮件标题显示。
  • expr - 报警规则,为 PromQL 表达式验证特定节点,如上述配置中up{job="250-IRIS"}为验证job="250-IRIS"是否还活着,如果等于0则启动报警。
  • for - 表示报警状态为 Pending 后等待 15s 变成 Firing 状态,一旦变成 Firing 状态则将报警发送到 AlertManager
  • summary - 报警信息描述。
groups:
    - name: "服务器报警"
      rules:
      - alert: yx服务器报警
        expr: up{job="250-IRIS"} == 0
        for: 15s
        labels:
          status: warning
        annotations:
          summary: "服务器{{ $labels.instance }} 挂了"
          description: "姚鑫服务器挂了.请立即查看!"

      - alert: 本地Cache报警
        expr: up{job="localhost-Cache"} == 0
        for: 15s
        labels:
          status: warning
        annotations:
          summary: "服务器{{ $labels.instance }} 挂了"
          description: "本地Cache服务器挂了.请立即查看!"
          
      - alert: 本地IRIS报警
        expr: up{job="localhost-IRIS"} == 0
        for: 15s
        labels:
          status: warning
        annotations:
          summary: "服务器{{ $labels.instance }} 挂了"
          description: "本地IRIS服务器挂了.请立即查看!"


    - name: test-rules
      rules:
      - alert: "内存报警"
        expr: 100 - ((node_memory_MemAvailable_bytes * 100) / node_memory_MemTotal_bytes) > 3
        for: 15s
        labels:
          status: warning
        annotations:
          summary: "服务器:{{$labels.instance}}内存使用率超过3%了"
          description: "内存使用率: {{ $value }}"
          value: "{{ $value }}"
  1. 配置好报警规则文件后,需要修改 prometheus.yml 配置文件,添加 rules 规则文件:
alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - 'localhost:9093'
         # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  - "alert_rules.yml"
  # - "second_rules.yml"
  1. 配置完毕后打,浏览器访问prometheus主页,进入AlertsRules界面,可查看报警规则信息:
  • 地址:http://localhost:9090/alerts?search=

在这里插入图片描述

  1. 测试报警功能,将本地Caché关闭,停库。

在这里插入图片描述

  1. 观察页面本地Cache警报状态。

Prometheus Alert 告警状态有三种:InactivePendingFiring

  • Inactive - 非活动状态,表示正在监控,但是还未有任何警报触发。
  • Pending - 表示这个警报将被触发。由于警报可以被分组、压抑/抑制或静默/静音,所以等待验证,一旦所有的验证都通过,则将转到 Firing 状态。
  • Firing - 将警报发送到AlertManager,将按照配置将警报的发送给所有接收者。一旦警报解除,则将状态转到 Inactive,如此循环。

首先发现警报变为Pending状态。

在这里插入图片描述

过了15秒后变为Firing状态

在这里插入图片描述

  1. 触发报警,根据定义的报警规则,如果有触发告警的条件,自动向配置的接收邮箱中发送邮件,如下:

在这里插入图片描述

在这里插入图片描述

基于M实现监控服务器,并用邮件报警

解析Prometheus数据接口信息

  • 获取接口信息
ClassMethod GetMetrics(url) As %Status
{
	#; 初始化request对象
	#dim request as %Net.HttpRequest= ##class(%Net.HttpRequest).%New()
	
	#; 根据地址解析是否是https调用SSL配置
	d ##class(%Net.URLParser).Parse(url, .components)
	s scheme = components("scheme")
	if (scheme = "https") {
		s request.Https = 1
		if ($zv [ "IRIS") {
			s request.SSLConfiguration = "ISC.FeatureTracker.SSL.Config"
		} else {
			s request.SSLConfiguration = "WebTerminalSSL"
		}	
		s request.SSLCheckServerIdentity = 0  
	}
	
	#; 请求地址并返回流数据
	s sc = request.Get(url)
	$$$ThrowOnError(sc)
	s response = request.HttpResponse
	s stream = response.Data
	q stream
}
  • 将接口信息转为Json格式
ClassMethod Metrics2Json(stream) As %Status
{
	s array = []
	while (stream.AtEnd = 0) {
		
		#; 读取每行信息
		s metrics = stream.ReadLine()
		
		#; 过滤注释描述信息
		continue:(metrics [ "# HELP")
		continue:(metrics [ "# TYPE")
		
		#; 指标字符串
		s str = $p(metrics, " "1)
		
		#; 指标值
		s value = $p(metrics, " "2)
		
		#; 指标字名称
		s metricsName = $p(str, "{"1)
		
		#; 指标字label信息
		s label = $e($p(str, "{"2)1* - 1)
		s obj = {}
		s obj.key = metricsName
		s obj.val = value
		
		#; 如果label不为空将label信息转为JSON
		if (label '= "") {
			s tag = {}
			s len = $l(label, ",")
			for i = 1 : 1 : len{
				s item = $p(label, """," ,i)
				s key = $p(item, "="1) 
				s val = $e($p(item, "="2)2*-1)
				d tag.%Set(key, val)
			}
			s obj.tag = tag
		}
		d array.%Push(obj)
	}
	q array
}
  • 调用方法。
/// w ##class(M.ParseMetrics).Main("https://localhost:2443/api/monitor/metrics").%ToJSON()
/// w ##class(M.ParseMetrics).Main("http://localhost:9182/metrics").%ToJSON()
/// w ##class(M.ParseMetrics).Main("http://localhost:57772/api/metrics/prometheus").%ToJSON()
ClassMethod Main(url) As %Status
{
	#; 获取指标接口信息
	s stream = ..GetMetrics(url)
	
	#; 将接口信息转为JSON格式
	s json = ..Metrics2Json(stream)
	q json
}
  • 调用自定义Caché接口
IMP>w ##class(M.ParseMetrics).Main("http://localhost:57772/api/metrics/prometheus").%ToJSON()   

[{"key":"yx_application_errors""val":"0"}{"key":"yx_csp_sessions""val":"1"}{"key":"yx_cache_efficiency""val":"235.85"}{"key":"yx_disk_reads""val":"3316"}{"key":"yx_disk_writes""val":"1881"}{"key":"yx_ecp_app_srv_rate""val":"0"}{"key":"yx_ecp_data_srv_rate""val":"0"}{"key":"yx_glo_refs""val":"1225714"}{"key":"yx_glo_refs_per_sec""val":"439.00"}{"key":"yx_glo_sets""val":"108449"}{"key":"yx_journal_entries""val":"17178"}...
{"key":"yx_database_free""val":".8988""tag":{"id":"DHC-EPRMETADATA"}}{"key":"yx_database_free""val":".45""tag":{"id":"DHC-EPRQUALITYDATA"}}{"key":"yx_database_free""val":".71""tag":{"id":"DHC-EPRRBACINST"}}{"key":"yx_database_free""val":".74""tag":{"id":"DHC-EPRRBACMETA"}}{"key":"yx_database_free""val":".78""tag":{"id":"DHC-HEIS"}}{"key":"yx_database_free""val":".48""tag":{"id":"DHC-HL7"}}{"key":"yx_database_free""val":".9936""tag":{"id":"DHC-HR"}}{"key":"yx_database_free""val":".0345""tag":{"id":"DHC-LISDATA"}}{"key":"yx_database_free""val":".9328""tag":{"id":"DHC-LISSRC"}}{"key":"yx_database_free""val":".9884""tag":{"id":"DHC-LOGS"}}{"key":"yx_database_free""val":".9098""tag":{"id":"DHC-MEDSRC"}}{"key":"yx_database_free""val":".8996""tag":{"id":"DHC-MRQDATA"}}{"key":"yx_database_free""val":".9871""tag":{"id":"DHC-MRQSRC"}}{"key":"yx_database_free""val":".1""tag":{"id":"DHC-MSG"}}{"key":"yx_database_free""val":".0481""tag":{"id":"DHC-ORDDATA"}}{"key":"yx_database_free""val":".0417""tag":{"id":"DHC-ORDINDEX"}}{"key":"yx_database_free""val":".8782""tag":{"id":"PACS"}}{"key":"yx_database_free""val":".6""tag":{"id":"DHC-PISDATA"}}{"key":"yx_database_free""val":".831""tag":{"id":"DHC-PISSRC"}}{"key":"yx_database_free""val":".9548""tag":{"id":"DHC-RIS"}}{"key":"yx_database_free""val":".9615""tag":{"id":"DHC-SYS"}}{"key":"yx_database_free""val":".9218""tag":{"id":"DHC-TEMP"}}{"key":"yx_database_free""val":".8096""tag":{"id":"DHC-DWR"}}{"key":"yx_database_free""val":".039""tag":{"id":"DHC-WORKLOAD"}}{"key":"yx_database_free""val":".1797""tag":{"id":"IMP"}}]     
  • 调用自定义IRIS接口
IMP>w ##class(M.ParseMetrics).Main("https://localhost:2443/api/monitor/metrics").%ToJSON()    

[{"key":"iris_cpu_pct""val":"0""tag":{"id":"CSPSRV"}}{"key":"iris_cpu_pct""val":"0""tag":{"id":"ECPWorker"}}{"key":"iris_cpu_pct""val":"0""tag":{"id":"GARCOL"}}{"key":"iris_cpu_pct""val":"0""tag":{"id":"JRNDMN"}}...
{"key":"iris_wqm_max_work_queue_depth""val":"0""tag":{"id":"SYS"}}{"key":"iris_wqm_waiting_worker_jobs""val":"1""tag":{"id":"SYS"}}]    
  • 调用自定义Exporter接口
IMP>w ##class(M.ParseMetrics).Main("http://localhost:9182/metrics").%ToJSON()
[{"key":"go_gc_duration_seconds","val":"0","tag":{"quantile":"0"}},{"key":"go_gc_duration_seconds","val":"0","tag":{"quantile":"0.25"}},{"key":"go_gc_duration_seconds","val":"0","tag":{"quantile":"0.5"}},{"key":"go_gc_duration_seconds","val":"0","tag":{"quantile":"0.75"}},{"key":"go_gc_duration_seconds","val":"0.0023476","tag":{"quantile":"1"}},{"key":"go_gc_duration_seconds_sum","val":"0.0038789"},{"key":"go_gc_duration_seconds_count","val":"87"},{"key":"go_goroutines","val":"14"},{"key":"go_info","val":"1","tag":
...
{"key":"go_threads","val":"19"},{"key":"process_cpu_seconds_total","val":"2.015625"},{"key":"process_max_fds","val":"1.6777216e+07"},{"key":"process_open_fds","val":"414"},{"key":"process_resident_memory_bytes","val":"3.5504128e+07"},{"key":"process_start_time_seconds","val":"1.67670656e+09"},{"key":"process_virtual_memory_bytes","val":"4.0259584e+07"},]

使用嵌入式Python方式获取系统CPU、内存等

python模块之psutil详解

在讲嵌入式Python之前我们先了解一下psutil

psutil是一个开源切跨平台的库,其提供了便利的函数用来获取才做系统的信息,比如CPU,内存,磁盘,网络等。此外,psutil还可以用来进行进程管理,包括判断进程是否存在、获取进程列表、获取进程详细信息等。而且psutil还提供了许多命令行工具提供的功能,包括:pstoplsofnetstatifconfigwhodfkillfreeniceioniceiostatiotopuptimepidofttytasksetpmap

psutil是一个跨平台的库,在官方网站上查到其支持如下操作系统。

  • Linux
  • Windows
  • OSX
  • FreeBSD
  • OpenBSD
  • NetBSD
  • Sun Solaris
  • AIX
CPU相关
函数描述
psutil.cpu_count()cpu_count(,[logical]):默认返回逻辑CPU的个数,当设置logical的参数为False时,返回物理CPU的个数。
psutil.cpu_percent()cpu_percent(,[percpu],[interval]):返回CPU的利用率,percpuTrue时显示所有物理核心的利用率,interval不为0时,则阻塞时显示interval执行的时间内的平均利用率。
psutil.cpu_times()cpu_times(,[percpu]):以命名元组(namedtuple)的形式返回cpu的时间花费,percpu=True表示获取每个CPU的时间花费。
psutil.cpu_times_percent()cpu_times_percent(,[percpu]):功能和cpu_times大致相同,看字面意思就能知道,该函数返回的是耗时比例。
psutil.cpu_stats()cpu_stats()以命名元组的形式返回CPU的统计信息,包括上下文切换,中断,软中断和系统调用次数。
psutil.cpu_freq()cpu_freq([percpu]):返回cpu频率。
Memory内存相关
函数描述
virtual_memory()以命名元组的形式返回内存使用情况,包括总内存,可用内存,内存利用率,buffercache等。单位为字节。
swap_memory()以命名元组的形式返回swap/memory使用情况,包含swap中页的换入和换出。
Disk相关
函数描述
psutil.disk_io_counters()disk_io_counters([perdisk]):以命名元组的形式返回磁盘io统计信息,包括读、写的次数,读、写的字节数等。 当perdisk的值为True,则分别列出单个磁盘的统计信息(字典:key为磁盘名称,value为统计的namedtuple)。
psutil.disk_partitions()disk_partitions([all=False]):以命名元组的形式返回所有已挂载的磁盘,包含磁盘名称,挂载点,文件系统类型等信息。 当all等于True时,返回包含/proc等特殊文件系统的挂载信息。
psutil.disk_usage()disk_usage(path):以命名元组的形式返回path所在磁盘的使用情况,包括磁盘的容量、已经使用的磁盘容量、磁盘的空间利用率等。
Network相关
函数详情
psutil.net_io_counter([pernic])以命名元组的形式返回当前系统中每块网卡的网络io统计信息,包括收发字节数,收发包的数量、出错的情况和删包情况。当pernicTrue时,则列出所有网卡的统计信息。
psutil.net_connections([kind])以列表的形式返回每个网络连接的详细信息(namedtuple)。命名元组包含fdfamilytypeladdrraddrstatuspid等信息。kind表示过滤的连接类型,支持的值如下:(默认为inet)。
psutil.net_if_addrs()以字典的形式返回网卡的配置信息,包括IP地址和mac地址、子网掩码和广播地址。
psutil.net_if_stats()返回网卡的详细信息,包括是否启动、通信类型、传输速度与mtu
psutil.users()以命名元组的方式返回当前登陆用户的信息,包括用户名,登陆时间,终端,与主机信息。
psutil.boot_time()以时间戳的形式返回系统的启动时间。
Process相关
函数详情
psutil.pids()以列表的形式返回当前正在运行的进程。
psutil.pid_exists(1)判断给点定的pid是否存在。
psutil.process_iter()迭代当前正在运行的进程,返回的是每个进程的Process对象。
psutil.Process()对进程进行封装,可以使用该类的方法获取进行的详细信息,或者给进程发送信号。

通过嵌入式Python调用psutil

这里仅简单介绍个主要方法、其他获取系统资源方法由读者自行实现。

  • 在安装路径C:\InterSystems\IRISHealth\bin,输入cmd,进入命令行控制台输入命令。安装 psutil库。
irispip install --target C:\InterSystems\IRISHealth\mgr\python psutil

在这里插入图片描述

  • 获取服务器CPU使用率
ClassMethod GetSystemCpu() As %String [ Language = python ]
{
	from psutil.__init__ import cpu_percent,virtual_memory
	return cpu_percent(interval=2)
}
USER> w ##class(M.SystemMetrics).GetSystemCpu()
14.59999999999999964

在这里插入图片描述

根据上图可以观察到获取的内容使用 1 - 是 IRIS监控接口、2 - 是M方法实现、 3 - 是任务管理器,三者监控的CPU使用率基本使用是一致的。(因为CPU使用率是瞬态的,所以可以认为是准确的)

  • 获取服务系内存使用状态
ClassMethod GetSystemMemory() As %String [ Language = python ]
{
	from psutil.__init__ import cpu_percent,virtual_memory
	return virtual_memory()[2]
}
USER>w ##class(M.SystemMetrics).GetSystemMemory()
60

在这里插入图片描述

根据上图可以观察到获取的内容使用 1 - 是 360监控、2 - 是任务管理器、 3 - 是M方法实现,三者监控的内存使用是一致的。

使用邮件发送报警信息

这里考虑使用邮件来发送警报信息是因为:

  • 邮件相对其他方式来说比较方便,只管发送,不用管是否接收。
  • IRIS自带发送邮件接口,操作性大。
  • 相比其他方式,例如微信,公众号等,还需要做接口交互。使用邮件相对简单。

那么下一个考虑的问题是通过什么方式来触发监控发邮件呢,笔者考虑以下两点可以触发:

  • 通过挂任务的方式定时轮询。
  • 通过SessionEvent事件来触发。

这里仅提供代码示例,具体使用哪种方式由读者自行决定。

使用M发送邮件发送消息

  • 这里以QQ邮箱例,配置信息与Alertmanager邮箱配置相同
ClassMethod SetMailConfig() As %Net.SMTP
{
	#; 配置smtp服务
	s server = ##class(%Net.SMTP).%New()
	s server.smtpserver = "smtp.qq.com"
	s server.port = 465
	if ($zv [ "IRIS") {
		s server.SSLConfiguration = "ISC.FeatureTracker.SSL.Config"
	} else {
		s server.SSLConfiguration = "WebTerminalSSL"
	}	

	#; 配置邮箱
	s auth = ##class(%Net.Authenticator).%New()
	s auth.UserName = "454115408@qq.com"
	s auth.Password = "xxxxxxxxxxxxxxxx"

	s server.authenticator = auth
	s server.AuthFrom = auth.UserName
	
	q server
}
  • 发送邮件具体方法
ClassMethod SendMailMessage(title, content) As %List
{
	#; 获取配置
	s server  = ..SetMailConfig()
	
	#; 初始化邮件对象
	s msg = ##class(%Net.MailMessage).%New()
	
	#; 添加from - 发送人,to - 接收人,Cc - 抄送人
	s from = server.authenticator.UserName
	s msg.From = from
	d msg.To.Insert("yaoxin@mediway.cn")
	d msg.Cc.Insert("965274651@qq.com")

	#; 填写邮件具体内容
	s msg.Subject = title
	s msg.IsBinary = 0
	s msg.IsHTML = 0
	d msg.TextData.Write(content)

	#; 执行发送
	s sc = server.Send(msg)
	$$$ThrowOnError(sc)
	q server.FailedSend
}
  • 测试邮件方法,发送成功目标邮箱会接收到邮件。
IMP>w ##class(M.Mail).SendMailMessage("yx发的邮件消息头","这是yx发的消息内容content")                                                                           10@%Collection.ListOfDT

在这里插入图片描述

通过配置文件csv文件,来获取维护指标,进行邮件报警。

  • 使用csv文件通过手动的方式来维护需要监控的指标
    • key - 指标名称,这里要与IRIS接口信息的具体指标保持一致。
    • val - 报警的阈值。
    • oper - 操作符。指具体报警时操作符。是大于val时报警,还是小于val时报警,或其他。
    • desc - 指标描述信息。

在这里插入图片描述

  • 读取csv文件将数据转为Json
ClassMethod Csv2Json(filename)
{
	q:('##class(%File).Exists(filename)) $$$NO
	s stream = ##class(%Stream.FileCharacter).%New()
	s stream.Filename = filename
	s array = []
	s keyStr = ""
	while 'stream.AtEnd {
		s str = stream.ReadLine()
		if ($i(count) = 1) {
			s keyStr = str
		}
		s obj = {}	
		s len = $l(str, ",")
		for i = 1 : 1 : len {
			s val = $p(str, ",", i)
			s key = $p(keyStr, ",", i)
			d obj.%Set(key, val)
		}
		d array.%Push(obj)
	}
	q array
}
IMP>w ##class(M.Mail).LoadFile("E:\temp\metrics.csv").%ToJSON()
[{"key":"iris_cpu_usage ","val":"10","oper":">"},{"key":"iris_license_available","val":"290","oper":">"},{"key":"iris_trans_open_count","val":"0","oper":">"},{"key":"memory","val":"40","oper":">"}]
  • 对比维护指标与接口指标,超过阈值发送邮件进行警报。

注:这里双循环,时间复杂O2,数据量大,效率可能会比较低,需要注意下。

ClassMethod Main(url As %String, filename As %String) As %Status
{
	#; 获取接口指标Json
	s irismetrics =  ##class(M.ParseMetrics).Main(url)
	
	#; 获取Csv维护指标Json
	s config = ##class(M.Mail).Csv2Json(filename)
	
	#; 双向对比,维护指标超过阈值发送邮件警报
	for i = 1 : 1 : irismetrics.%Size() - 1{
		s metrics = irismetrics.%Get(i)
		for j = 1 : 1 : config.%Size() - 1{
			s obj = config.%Get(j)
			if (obj.key = metrics.key) {
				if @(metrics.val _ obj.oper _ obj.val) {
					s content = obj.desc _ "警报,超过阈值:" _ obj.val
					d ..SendMailMessage("来自系统的警报",content)
					ret $$$NO
				} 
			}
		}
	}
	
	#; 监控内存使用率,接口中没有监视内存选项所以调用嵌入式接口
	s memory = ..GetSystemMemory()
	if (memory > 30) {
		d ..SendMailMessage("来自系统的警报","内存使用率已经大于" _ 30 _ "")
	}

	ret $$$YES
}
USER>w ##class(M.Mail).Main("https://localhost:2443/api/monitor/metrics", "E:\temp\metrics.csv")
0

在这里插入图片描述

注:这里基本思路已经实现,可以通过挂任务或其他方式来定时轮询。

总结

以上是个人关于监控服务器指标、CPU、内存、警报的一些理解,由于个人能力有限,欢迎大家提出意见,共同交流。

思考

IRIS还提供了alert警报接口,该接口提供alert.log警报日志内容,基于以上方案,思考如何通过M程序进行监控

  • 接口地址:https://localhost:2443/api/monitor/alerts
  • 该接口有警报时会提示报警信息,调用一次后清空。

在这里插入图片描述

  • 如果有警报,警报信息如下:
{"time":"02/19/23-15:49:22:650","severity":2,"message":"Previous system shutdown was abnormal, system forced down or crashed."}

  • /api/monitor/metrics指标含义列表:
指标描述
iris_cpu_pct {id="ProcessType"}IRIS 进程类型的 CPU 使用百分比。 ProcessType 可以是以下任何一项:ECPWorker、ECPCliR、ECPCliW、ECPSrvR、ECPSrvW、LICENSESRV、WDAUX、WRTDMN、JRNDMN、GARCOL、CSPDMN、CSPSRV、ODBCSRC、MirrorMaster、MirrorPri、MirrorBack、MirrorPre、MirrorSvrR、MirrorJrnR、MirrorSK、MirrorComm
iris_cpu_usage操作系统上所有程序的 CPU 使用率百分比
iris_csp_activity {id="IPaddress:port"}Web 网关服务器自启动以来处理的 Web 请求数
iris_csp_actual_connections {id="IPAddress:port"}Web 网关服务器与该服务器的当前连接数
iris_csp_gateway_latency {id="IPaddress:port"}获取 iris_csp_ 指标时从 Web 网关服务器获得响应的时间,以毫秒为单位
iris_csp_in_use_connections {id="IPaddress:port"}正在处理 Web 请求的 Web 网关服务器与此服务器的当前连接数
iris_csp_private_connections {id="IPaddress:port"}为状态感知应用程序保留的 Web 网关服务器与此服务器的当前连接数(保留模式 1
iris_csp_sessions此服务器上当前活动的 Web 会话 ID
iris_cache_efficiency全局引用与物理读写的比率,以百分比表示
iris_db_expansion_size_mb {id="database"}扩展数据库的数量,以兆字节为单位
iris_db_free_space {id="database"}数据库中可用的可用空间,以兆字节为单位(此指标每天仅更新一次,可能不会反映最近的更改。)
iris_db_latency {id="database"}完成从数据库随机读取的时间量,以毫秒为单位
iris_db_max_size_mb {id="database"}`数据库可以增长到的最大大小,以兆字节为单位
iris_db_size_mb {id="database",dir="path"}数据库大小,以兆字节为单位
iris_directory_space {id="database",dir="path"}数据库目录存储卷上的可用空间,以兆字节为单位
iris_disk_percent_full {id="database",dir="path"}数据库目录存储卷上的空间百分比
iris_ecp_connECP 应用程序服务器上的活动客户端连接总数
iris_ecp_conn_max来自此 ECP 应用程序服务器的最大活动客户端连接数
iris_ecp_connectionsECP 应用程序服务器与其配置的 ECP 数据服务器同步时同步的服务器数
iris_ecp_latencyECP 应用服务器和 ECP 数据服务器之间的延迟,以毫秒为单位
iris_ecps_conn每秒与此 ECP 数据服务器的活动客户端连接总数
iris_ecps_conn_max与此 ECP 数据服务器的最大活动客户端连接数
iris_glo_a_seize_per_sec每秒全局资源上的 Aseizes
iris_glo_n_seize_per_sec每秒全局资源上的 Nseizes
iris_glo_ref_per_sec每秒对位于本地数据库上的全局变量的引用数
iris_glo_ref_rem_per_sec每秒对位于远程数据库上的全局变量的引用数
iris_glo_seize_per_sec每秒占用全局资源的次数
iris_glo_update_per_sec每秒对本地数据库上的全局变量进行更新(SETKILL 命令)的次数
iris_glo_update_rem_per_sec每秒对位于远程数据库上的全局变量的更新(SETKILL 命令)数
iris_jrn_block_per_sec每秒写入磁盘的日志块
iris_jrn_free_space {id="JournalType",dir="path"}每个日志目录的存储卷上可用的可用空间,以兆字节为单位。 JournalType 可以是 WIJprimarysecondary
iris_jrn_size {id="JournalType"}每个日志文件的当前大小,以兆字节为单位。 JournalType 可以是 WIJprimarysecondary
iris_license_available当前未使用的许可证数量
iris_license_consumed当前使用的许可证数量
iris_license_percent_used当前使用的许可证的百分比
iris_log_reads_per_sec每秒逻辑读取
iris_obj_a_seize_per_sec每秒对象资源上的 Aseizes
iris_obj_del_per_sec每秒删除的对象数
iris_obj_hit_per_sec进程内存中每秒的对象引用数
iris_obj_load_per_sec每秒从磁盘加载的对象数,不在共享内存中
iris_obj_miss_per_sec每秒在内存中找不到的对象引用数
iris_obj_new_per_sec每秒初始化的对象数
iris_obj_seize_per_sec每秒占用对象资源的次数
iris_page_space_percent_used已用最大分配页面文件空间的百分比
iris_phys_mem_percent_used当前使用的物理内存 (RAM) 的百分比
iris_phys_reads_per_sec每秒从磁盘读取的物理数据库块
iris_phys_writes_per_sec每秒写入磁盘的物理数据库块
iris_process_count活跃的 IRIS 进程总数
iris_rtn_a_seize_per_sec每秒例程资源上的 Aseizes
iris_rtn_call_local_per_sec每秒对位于远程数据库上的全局变量的本地例程调用数
iris_rtn_call_miss_per_sec每秒在内存中找不到的例程调用数
iris_rtn_call_remote_per_sec每秒远程例程调用次数
iris_rtn_load_per_sec每秒从本地加载或保存到磁盘的例程数
iris_rtn_load_rem_per_sec每秒从磁盘远程加载或保存到磁盘的例程数
iris_rtn_seize_per_sec每秒占用例程资源的次数
iris_sam_get_db_sensors_seconds收集 iris_db* 传感器所花费的时间,以秒为单位
iris_sam_get_jrn_sensors_seconds收集 iris_jrn* 传感器所花费的时间,以秒为单位
iris_sam_get_sql_sensors_seconds收集 iris_sql* 传感器所花费的时间,以秒为单位
iris_sam_get_wqm_sensors_seconds收集 iris_wqm* 传感器所花费的时间,以秒为单位
iris_smh_available {id="purpose"}按目的可用的共享内存,以千字节为单位
iris_smh_percent_full {id="purpose"}按目的使用的已分配共享内存的百分比
iris_smh_total为当前实例分配的共享内存,以千字节为单位
iris_smh_total_percent_full当前实例使用的已分配共享内存的百分比
iris_smh_used {id="purpose"}按目的使用的共享内存,以千字节为单位
iris_sql_active_queries {id="namespace"}当前执行的 SQL语句数
iris_sql_active_queries_95_percentile {id="namespace"}对于当前的活动 SQL 语句集,自语句开始执行以来经过的第 95 个百分位数的时间
iris_sql_active_queries_99_percentile {id="namespace"}对于当前活动的 SQL 语句集,自语句开始执行以来经过的第 99 个百分位数的时间
iris_sql_queries_avg_runtime {id="namespace"}平均 SQL 语句运行时间,以秒为单位
iris_sql_queries_avg_runtime_std_dev {id="namespace"}平均 SQL 语句运行时间的标准偏差
iris_sql_queries_per_second {id="namespace"}每秒平均 SQL 语句数
iris_system_alerts自系统启动以来发布到消息日志的警报数
iris_system_alerts_log当前位于警报日志中的警报数
iris_system_alerts_new/api/monitor/alerts 端点上是否有新警报,作为布尔值
iris_system_state表示系统监视器健康状态的数字
iris_trans_open_count当前实例上打开的事务数
iris_trans_open_secs当前实例上打开事务的平均持续时间,以秒为单位
iris_trans_open_secs_max当前实例上当前打开的最长事务的
iris_wd_buffer_redirty写入守护进程在最近一个周期中写入并且也在前一个周期中写入的数据库缓冲区数
iris_wd_buffer_write写入守护进程在其最近周期写入的数据库缓冲区数
iris_wd_cycle_time完成最近的写入守护进程周期所花费的时间量,以毫秒为单位
iris_wd_proc_in_global在最近的写入守护进程周期开始时主动持有全局缓冲区的进程数
iris_wd_size_write写入守护程序在其最近周期写入的数据库缓冲区的大小,以千字节为单位
iris_wd_sleep写入守护进程在其最近的周期开始之前处于非活动状态的时间量,以毫秒为单位
iris_wd_temp_queue写入守护进程在其最近周期开始时使用的内存缓冲区数
iris_wd_temp_write写入守护进程在其最近周期中写入的内存缓冲区数
iris_wdwij_time写入守护进程在其最近的周期内写入 WIJ 文件所花费的时间,以毫秒为单位
iris_wd_write_time写守护进程在其最近的周期内将缓冲区写入数据库所花费的时间,以毫秒为单位
iris_wij_writes_per_secWIJ 每秒物理块写入
iris_wqm_active_worker_jobs {id="category"}未被阻塞的运行逻辑的平均工作者作业数
iris_wqm_commands_per_sec {id="category"}平均每秒在此工作队列管理类别中执行的命令数
iris_wqm_globals_per_sec {id="category"}平均每秒在此工作队列管理类别中运行的全局引用数
iris_wqm_max_active_worker_jobs {id="category"}自上次记录日志条目以来的最大活动工作人员数
iris_wqm_max_work_queue_depth {id="category"}自上次记录以来此工作队列管理类别队列中的最大条目数
iris_wqm_waiting_worker_jobs {id="category"}等待一个组连接并为其工作的空闲工人作业的平均数量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/357802.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软考高级-信息系统管理师之知识管理(最新版)

知识管理 知识与知识管理知识管理常用的方法和工具显性知识的管理隐形知识的管理知识管理的工具学习型组织知识产权保护计算机软件保护条例商标法专利法补充建议学的考点:知识与知识管理 1、知识的分类 知识可分为两类,分别是显性知识与隐性知识。 凡是能以文字与数字来表达…

【C++】关联式容器——map和set的使用

文章目录一、关联式容器二、键值对三、树形结构的关联式容器1.set2.multiset3.map4.multimap四、题目练习一、关联式容器 序列式容器&#x1f4d5;:已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forward_list(C11)等&#xff0c;这些容器统称为…

新能源汽车,有毒

作者| Mr.K 编辑| Emma来源| 技术领导力(ID&#xff1a;jishulingdaoli)新能源汽车到底有多火&#xff0c;生生逼得奥迪某4S店挂出横幅&#xff1a;我们也有纯电新能源&#xff01;老牌名车的辛酸憋屈溢出屏幕。网友神评补刀“这标语给人‘诺基亚也有智能大屏机’的感觉。”一…

【Java基础】变量

Java基础 变量 variable 变量类型 实例变量(非静态字段) Instance Variables (Non-Static Fields) 类的非静态属性 类变量(静态字段) Class Variables (Static Fields) 类的静态属性 局部变量 Local Variables 参数 Parameters 变量命名 大小写敏感 开头&#xff1a;字…

爬虫基本知识的认知(爬虫流程 HTTP构建)| 爬虫理论课,附赠三体案例

爬虫是指通过程序自动化地从互联网上获取数据的过程。 基本的爬虫流程可以概括为以下几个步骤&#xff1a; 发送 HTTP 请求&#xff1a;通过 HTTP 协议向指定的 URL 发送请求&#xff0c;获取对应的 HTML 页面。解析 HTML 页面&#xff1a;使用 HTML 解析器对获取的 HTML 页面…

linux shell 入门学习笔记4 shell运维和编程语言

shell 运维和编程语言 脚本注释 shell脚本中&#xff0c;#后面的内容表示注释内容&#xff0c;一般是给开发者或使用者观看&#xff0c;解释器会忽略此部分内容注释可以单独写一行&#xff0c;也可以跟在文件末尾保持注释的习惯&#xff0c;尽量使用英文 例子&#xff1a; #…

C++类和对象(2)构造、析构函数

类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 class Date{}; 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员 函数。 默认成员函数&#xff1a;用户没有显式实现&…

什么是健康建筑?

WIKIPEDIA健康建筑是指支援建筑和建筑环境中人们&#xff0c;身体、心理和社会健康与福祉的新兴兴趣领域。建筑物可以成为健康和福祉的关键促进者&#xff0c;因为大多数人大部分时间都花在室内。根据全美国人类活动模式调查&#xff0c;美国人「平均 87% 的时间花在封闭的建筑…

redis-如何保证数据库和缓存双写一致性?

前言 数据库和缓存&#xff08;比如&#xff1a;redis&#xff09;双写数据一致性问题&#xff0c;是一个跟开发语言无关的公共问题。尤其在高并发的场景下&#xff0c;这个问题变得更加严重。 我很负责的告诉大家&#xff0c;该问题无论在面试&#xff0c;还是工作中遇到的概率…

windows版Rsync服务端和客户端cwRsync_4.1.0安装测试

下载地址&#xff1a;https://download.csdn.net/download/qq_32421489/87463506 服务端安装&#xff1a; cwRsyncServer&#xff08;服务端&#xff09;配置步骤 1.双击运行wRsyncServer_4.1.0_Installer.exe。 2.这里创建的账户是操作系统的&#xff0c;创建的这个账户是专…

【 RA4M2开发板环境搭建之串口下载1】

【 RA4M2开发板环境搭建1】1. 前言1.1 活动来源1.2 开发环境1.3 RA4M2开发板2. MDK环境准备2.1 keil 5下载安装2.2 安装RA4M2的软件支持包2.3 Renesas Flash Programmer安装3. RA Smart Configurator配置3.1 下载RA Smart Configurator3.2 安装RA Smart Configurator4. 新建RA4…

你是真的“C”——C语言详解求两个正数最小公倍数的3种境界

C语言详解求两个正数最小公倍数的3种境界~&#x1f60e;前言&#x1f64c;必备小知识~&#x1f618;求最小公倍数境界1~ &#x1f60a;求最小公倍数境界2~ &#x1f60a;求最小公倍数境界3~ &#x1f60a;总结撒花&#x1f49e;博客昵称&#xff1a;博客小梦&#x1f60a; 最喜…

[Incognito 4.0] ictf 2023

一周4赛&#xff0c;有点赶不过来呀。只做了一点&#xff0c;队长组队的时候(每次都中间断掉&#xff0c;一大堆写的都得从头来)CryptoAncient这样的第2次见&#xff0c;第1次就不会&#xff0c;这回看了队友wp终于知道是怎么加密的了Templed每个符号可以表示4位10进制数。原题…

〖产品思维训练白宝书 - 核心竞争力篇⑭〗- 产品经理核心竞争力解读之学习能力

大家好&#xff0c;我是 哈士奇 &#xff0c;一位工作了十年的"技术混子"&#xff0c; 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 &#x1f4ac; 人生格言&#xff1a;优于别人,并不高贵,真正的高贵应该是优于过去的自己。&#x1f4ac; &#x1f4e…

路径规划 | 图解跳点搜索JPS算法(附ROS C++/Python/Matlab仿真)

目录0 专栏介绍1 A*算法的弊端2 跳点搜索算法2.1 自然与强制邻点2.2 跳点剪枝策略3 算法仿真与实现3.1 算法流程3.2 ROS C实现3.3 Python实现3.4 Matlab实现0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详细…

2. Unity操作基础知识

1. 创建新项目 双击打开 unity hub管理器&#xff0c;点击左侧栏中的 项目 选项卡&#xff0c;在右上角点击 新项目 按钮&#xff0c;进入项目创建页面&#xff1a; 在项目创建页面中&#xff0c;选择合适的模板&#xff0c;并设置项目名称&#xff0c;选择项目保存位置&…

【郭东白架构课 模块一:生存法则】12|法则五:如何提升一个架构设计的外部适应性?

你好&#xff0c;我是郭东白。 上节课我们讲了外部适应性这个概念&#xff0c;也强调了架构师的职责是通过架构活动为企业不断注入外部适应性&#xff0c;从而帮助企业更好地实现它的战略意图。 那么该怎么注入呢&#xff1f; 上节课在讲影响技术体系外部适应性的因素这部分…

MYSQL---第四次索引视图

学生表&#xff1a;Student (Sno, Sname, Ssex , Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 课程表&#xff1a;Course (Cno, Cname,) 课程号&#xff0c;课程名 Cno为主键 学生选课表&#xff1a;SC (…

AtCoder Beginner Contest 290 A-E F只会n^2

ABC比较简单就不再复述 D - Marking 简要题意 &#xff1a;给你一个长度为nnn的数组,下标为0到n−10 到 n-10到n−1&#xff0c;最初指针位于0,重复执行n-1次操作&#xff0c;每次操作的定义为将当前指针加上ddd&#xff0c;如果该位置为空(未填数),否则我们向右找到第一个为空…

《刀锋》读书笔记

刀锋&#xff08;毛姆长篇作品精选&#xff09;毛姆50个笔记点评认为好看的确是完美的结局。《刀锋》里面的人每个人都以自己的方式生活着。艾略特的势利&#xff0c;拉里的自由&#xff0c;伊莎贝尔的现实&#xff0c;苏珊的清醒&#xff0c;索菲的堕落&#xff0c;至于“我”…