[云监控]AE3-Script AE3脚本引擎

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云监控,每月短信1000条
云解析 DNS,旗舰版 1个月
简介: 本文介绍了阿里云监控计算引擎 **AE3-Script** 语法。旨在帮助云监控报警用户更高效、更灵活地使用alert,实现所想即所得的报警体验。## 一、为什么需要AE3-Script过去几年间,alert报警表达式引擎经历了两代衍进。 **第一代**,简单二元运算表达式,形如:``$Average >= 3``。该表达式要求必须为二元运算。其形式为: 。聚合方式必须以`$`开头,后

本文介绍了阿里云监控计算引擎 AE3-Script 语法。旨在帮助云监控报警用户更高效、更灵活地使用alert,实现所想即所得的报警体验。

一、为什么需要AE3-Script

过去几年间,alert报警表达式引擎经历了两代衍进。
第一代,简单二元运算表达式,形如:$Average >= 3。该表达式要求必须为二元运算。其形式为:<聚合方式> <二元运算符> <常量阈值>。聚合方式必须以$开头,后跟指标定义里的有效聚合字段名。我们姑且称该形式为简单阈值表达式。由于该表达式为简单二元运算,很容易解析成标准的三段式结构,并映射到界面上相应的输入组件中,见下图。
第一代表达式

第二代,结构化表达式。简单二元阈值表达式很快遇到了问题,无法做同比、环比计算。于是开发人员设计了一套结构化的表达式。设计思路仿照二元运算,使用三个结构化的变量。

序号 变量名 意义
1 statistics 聚合方式,根据指标定义可以取不同的值,如$Average
2 comparisonOperator 运算符,分两类:
第一类:比较运算: >>=<<===!=
第二类:同比、环比:
- GreaterThanLastPeriod(环比)
- GreaterThanLastHour(同比上小时)
- GreaterThanYesterday(同比昨天)
- GreaterThanLastWeek(同比上周)
3 threshold 阈值
_ preCondition 前置条件。符合第一代要求的二元表达式。
该字段为后期『补』加。

结构化后,虽然仍为三段式,但comparisonOperator做了扩展,不再是连接statistics和threshold的简单运算符,增加了同比、环比运算。
值得一提的是,不管是第一代,还是第二代,都是强类型的运算。也就是说如果某statistics的数据是数值,则threshold也必须是数值。
结构表达的好处是非常适合生成简单界面。
第二代表达式
很快新的需求又来了:希望在指标数据达到某个阈值的时候才应用同比环比。该需求对设计的冲击是巨大的,无论如何结构化的三段式也无法满足该需求。不得已,只能在三段式基础上再打个补丁:preCondition,该字段需满足第一代的要求,即简单二元阈值表达式。
但...这个世界不变的是变化。更多的需求接踵而至:

  • 对内存可用空间和cpu的占用率进行组合监控
  • 对CPU使用率进行一个峰值和平均值的组合监控
  • 应用分组中对某特殊实例应用高优先级的排它性阈值
  • ......

等等等等。用户需要对自己数据有更灵活地控制、判断能力。传统的二元式运算在汹涌的新需求面前束手无策。于是有了AE3-Script表达式引擎,把主动权交给用户,让用户通过灵活的Script语言,决定如何使用自己的监控数据。
AE3-Script使用了简单的语法,使得略微懂点编程的人,无需额外学习即可迅速上手。

二、AE3-Script初印象

我们首先通过几个AE3-Script语句,先给大家一个直观的印象。

2.1 应用分组中对某特殊实例应用高优先级的排它性阈值(多阈值)

$Average > ($instanceId == 'i-io8kfvcpp7x5lnyv'? 80: 50)

$符为指标数据的前缀,即$后面的部分会被AE3-Script解释为指标的Key。当实例为i-io8kfvcpp7x5lnyv时,$Average > 80时才报警,其它实例$Average > 50就报警。

2.2 局部黑名单

分组中的某个的实例不参与报警

$instanceId != 'i-io8kfvcpp7x5lnyv' && $Averange > 50

当实例为i-io8kfvcpp7x5lnyv时,返回false,永远不触发报警。为其它实例时则进行阈值判断。

2.3 多指标组合

@cpu_total[60].$Average > 50 && @memory_usage[60].$Average > 80

过去一分钟内cpu平均使用率>50%,并且内存使用率>80%则报警。

2.4 指标延迟上报报警

当心跳超时大于1分钟时,则报警

now() - @heartbeat[60].reportTime > 60_000

reportTime为指标的上报时间,系指标自带字段。now()函数为系统内置函数,返回当前时间的毫秒级UTC时间戳。

三、AE3-Script基本元素

3.1 变量

AE3-Script的变量是大写或小写字母开头,后跟数字、大写字母、小写字母以及下划线_。符合如下正则表达式

[a-zA-Z][_a-zA-Z0-9]*

变量是大小敏感的(大写和小写字符是不同的)。 如AverageinstanceId都是合法变量,而3foo则是非法的。
特殊类型的变量

  • 指标@@开头的变量被认为是指标,指标名为去掉前置@的部分。如@cpu_total表示指标cpu_total,如果没有前置@,则cpu_total仅为普通变量。

    带聚合周期的指标。指标后面跟[]括起来的常量整数。例@cpu_total[60]表示聚合周期为60秒的cpu_total指标。
    有些指标中可能含有非法字符,不能以变量的形式出现,如vm.DiskIORead,可以使用内置函数@(字符串常量)来代替,如@('vm.DiskIORead')[15]

  • 指标成员$。指标含有dimension以及聚合信息。这些信息使用对象成员的语法访问,但成员需要以$开头。如@cpu_total[60].$Average,表示聚合周期为60秒的cpu_total指标的Average数据。

例如: @cpu_total[60] 表示聚合周期为60秒的cpu_total指标。@network_in[60]表示聚合周期为60秒的网络入流量指标。

3.2 数据类型

数据类型 描述 示例
string 单引号或双引号引起的字符串 "hello", 'hello'
number 数值,可以是整数或浮点数<br/>当数值为整数时,可以使用数字分隔符,方便维护和阅读 103, 2.5, .5, 2e+6
1_000_000
array 数组 [1, 2, 3]
map或dict 字典 {"foo":"bar"}
bool 布尔值,取值为true或false
nil nil。空值,无数据

AE3-Script支持动态类型,字符串和数值可以进行数学运算,以及互相比较。

3.3 访问对象成员

使用.语法可以访问对象的成员,[]语法访问array的成员。

students[0].name

map成员概可以使用.,也可以使用[]进行访问。

cpu_total.$Average
// or
cpu_total['$Average']

3.4 运算符

基本运算符

数学运算符 比较运算符 逻辑运算符
+ (加) == (等于) &&and (逻辑与)
- (减) != (不等于) ||or (逻辑或)
* (乘) > (大于) !not (逻辑非)
/ (除) >= (大于等于)
% (取模) < (小于)
** (指数) <= (小于等于)

例子:

$Average > 50 && $instanceId != 'i-not-exist'

类型提升 当数学运算或比较运算符两边不是同一类型时,遵循如下类型提升规则:string => number。bool型不做任何提升,只能进行逻辑运算。

'123' + 321  ==> 123 + '321' ==> 444
'2' * 4 ==> 2 * '4' => 8
8 - '2' ==> '8' - 2 ==> 6
8 ** '2' ==> '8' ** 2 ==> 64
'7' % 2 ==> 7 % '2' ==> 1

字符串操作

  • # (字符串相加)

    'abc' # 'def'

    返回 'abcdef'。当字符串和数值相加时,数值会被转换为字符串

    '123' # 321

    返回123321

字符串和bool值相加

'123' # ' ' # true

返回123 true

  • matches (正则表达匹配)

    判断一个字符串是否不匹配某正则表达式, 使用逻辑非以及matches运算符

    !("hello" matches "^fo.+")

    返回true注意 这里必须使用括号,因为!的优先级比matches要高

  • contains (是否包含子串)

    'abcdef' contains 'cde'

    返回 true

  • startsWith (字符串是否指定前缀)
  • endsWith (字符串是否指定后缀)

成员关系运算符

  • in (包含)
  • not in (不包含)

例:配置userId是否在指定的列表中

userId in [44404, 425876]

foo是否是map的key

"foo" in {'foo':1, 'bar': 2}

范围运算

  • .. 两侧必须是数值或字符串

例:

score in 60..100

成绩是否界于60到100之间(含),等价于

60 <= score && score <= 100

有些时候无法在编码期间明确范围的最小或最大值,此时可以通过内置函数range来生成。

  1. range(array) array的长度必须是2
  2. range(min, max)
score in range(min, max)

min和max运行时,由外部输入。

三元运算

  • ?:

效果同C/Java下的三元运算

$Average > 30? "ok": "lower"

3.5 切片(slice)

  • array[:] 冒号两边是半闭半开区间

切片可应用于arraystring。 假设有一个名为arr的array:

arr := [0,1,2,3,4,5]

那么

arr[1:5] ==> [1,2,3,4]
arr[3:] ==> [3,4,5]
arr[:4] ==> [0,1,2,3]
arr[:] ==> [0,1,2,3,4,5]

当用于字符串时,通常用于取子串,假设有一个变量a为'abcdef'

a[:3] ==> 'abc'
a[1:3] ==> 'bc'
a[1:] ==> 'bcdef'
a[:] ==> 'abcdef'

3.6 内置函数

序号 函数 释义
1 len(array|map|string) array、map或字符串的长度
2 now() 返回毫秒级的时间戳(UTC)
3 abs(number) 绝对值,返回浮点数
4 rand() 返回一个介于[0, 1)的浮点数
5 rand(N) 返回一个介于[0, N)的浮点数
6 toLower(string) 字符串转小写
7 toUpper(string) 字符串转大写

四、AE3-Script高级特性

4.1 高级内置函数

序号 函数 释义
1 all([...], closure) 返回true,如果所有的成员均满足条件
2 none([...], closure) 返回true,如果所有的成员均满足条件
3 any([...], closure) 返回true,如果至少有一个成员满足条件
4 one([...], closure) 返回true,如果有且仅有一个成员满足条件
5 filter([...], closure) 通过指定条件过滤array
6 map([...], closure) 将array所有的成员映射到另一个array中
7 count([...], closure) 返回满足条件的成员的数量

闭包(closure)

  • {...} 用于在在遍历中对当前项进行处理。访问当前项时使用#
map([1,2,3], {# * 2})

返回一个array:

[2,4,6]

如果array的项是对象或map,则可以使用省略了#的成员访问语法,此时#.Value 变成 .Value

filter(students, {len(.name) > 3})

4.2 同比、环比

不管是同比,还是环比,都是指的某指标的在某种聚合方式下的数据对比,比如聚合周期为60秒cpu均值环比。因此同比、环比函数具有相同的函数签名:
第一个参数: 指标,如:@cpu_total[60]
第二个参数:聚合方式,字符串, 如:'$Average'
第三个参数:bool,大于上个周期为true, 小于上个周期为false。

序号 函数 释义
1 CompareLastPeriod(指标, 聚合方式, bool) 环比上个周期,例: CompareLastPeriod(@cpu_total[60], '$Average', true)
假设当前的$Average值为A, 上周期的$Average值为B,则第三个参数:
1) 为true时,结果等于(A - B) * 100 / B
2) 为false时,结果等于(B - A) * 100 / B
2 CompareLastHour(指标, 聚合方式, bool) 同比上个小时
3 CompareYesterday(指标, 聚合方式, bool) 同比昨天
4 CompareLastWeek(指标, 聚合方式, bool) 同比上周
5 ComparePast(指标, 聚合方式, bool, seconds) 比较seconds秒之前的数据,该函数实际上同比、环比的完整形式。
上面的四个函数为该函数的简化调用
CompareLastHour(@cpu_total[60], '$Average', true) ==> ComparePast(@cpu_total[60], '$Average', true, 3600)
CompareYesterday(@cpu_total[60], '$Average', true) ==> ComparePast(@cpu_total[60], '$Average', true, 24*60*60)
CompareLastWeek(@cpu_total[60], '$Average', true) ==> ComparePast(@cpu_total[60], '$Average', true, 7*24*60*60)

五、脚本的背后

一个格式正确的脚本,在规则加载时会经历四个阶段,并最终生成AE3-Script字节码。

  • 变量补齐
  • metric提取
  • 性能优化
  • 编译

5.1 变量补齐

AE3-Script使用关于指标变量的约定:

  1. @开头的变量表示指标。如@cpu_total,表示cpu_total指标。
  2. 指标常量整数下标表示聚合周期。如@cpu_total[60],表示聚合周期为60秒的cpu_total。注意下标一定是常量,且为整数。
  3. $开头的变量表示指标下的key。如@cpu_total[60].$Average,表示聚合周期为60秒的cpu_total的Average字段。

简单阈值表达式阶段书写的表达式是这样的

$Average >= 30

仅有一个statistics,没有指明是哪个指标。这样的好处是书写简洁,坏处是单看脚本本身,不知道是使用哪个指标。为此AE3-Script需要为其补全指标信息,形成完整的、信息明确的、不需额外信息的变量: @cpu_total[60].$Average
补全方式是使用报警规则配置的『全局』metricName信息。如果脚本中的变量已经是一个完整的形式,则脚本没任何变化。
补全后的表达式是完全自洽的,行为明确的,不再需要其它信息。

5.2 metric提取

由于脚本补全后的信息是完整的,因此在脚本解析阶段可以完整的提取出指标列表。从而指导AE3(报警引擎)去拉取相应的数据。metric的提取主要有两方面:
当前metric 当前metric是指脚本运行时需要的『即时』数据。如@cpu_total[60].$Average表示运行时拉取最新的聚合周期为60秒的cpu_total指标,我要用它的Average字段做阈值判断。
历史metric 做同比、环比计算时,我们需要历史数据,比如一小时前的数据。AE3-Script解析引擎通过解析同比函数,从而确定需要拉取的历史数据。如 同比一小时:

CompareLastHour(@cpu_total[60], '$Maximum', true)

这个表达式除了需要cpu_total的即时数据,还需要1小时前的数据,AE3-Script解析引擎可以有效解析该信息。

(@cpu_total[15].$Average >= 50) && (CompareLastPeriod(@memory_usedutilization[60], "$Average", true) > 30)

以上表达式会被提取出3个指标:

@cpu_total[15] 的即时数据
@memory_usedutilization[60] 的即时数据
@memory_usedutilization[60] 一小时前的数据

5.3 性能优化

AE3-Script引擎做了一系列的优化,以提高与报警引擎的交互效率,和脚本运行速度。交互效率如虚拟机复用、常量函数、interface代替反射等。运行速度优化,包含但不限于常量折叠、数组map,指标加速等。

  1. 常量折叠。对于可以在编译期间计算出结果的数学表达式,会在该阶段直接计算出结果。 -(3+6)**2会被编译器直接计算为-81
  2. 数组map。当我们需要判断某个变量的值是否出现在数组中时(in操作),编译器会将数量优化为map,然后再做in运算。

    name in ['foo', 'bar', 'zen']

将被优化为

name in {'foo': true, 'bar': true, 'zen': true}
  1. 指标加速。标准的指标表达式需要经过两级运算才能访问到数据。@cpu_total[60]第一级访问cpu_total,第二级访问下标为60的数据。编译器在编译时会直接优化为单一变量@cpu_total#60,直接访问相关数据。

5.4 编译

经过以上步骤后,AE3-Script编译器最终将脚本编译为字节码,并在AE3-Script虚拟机中安全地运行。

相关实践学习
基于云监控实现的监控系统
通过阿里云云监控功能给非阿里云主机安装监控插件,从而实现对非阿里云主机的各项指标进行监控和管理,在配置报警规则和报警人的情况下,能对特定的场景做出报警反应通知到报警人的手机上。
目录
相关文章
|
监控 Java C++
[云监控]AE3-Script脚本引擎进阶
在上一篇[《[云监控]AE3-Script AE3脚本引擎》](https://ata.alibaba-inc.com/articles/217887)中介绍了AE3-Script的基本特性。本篇将继续介绍该脚本的一些更加深入的用法。 ## 一、动态算术运算 AE3-Script是一种动态类型的语言,字符串(string)、数值(number)和布尔值(bool)都可以进行数学运算。运算时字符串和
168 0
[云监控]AE3-Script脚本引擎进阶
|
5月前
|
存储 传感器 监控
云监控:引领未来监控技术的新篇章
传统监控系统需要投入大量的人力物力进行建设和维护,而云监控则通过云计算平台的按需付费特性降低了建设和维护成本。用户只需根据实际需求购买相应的服务和资源即可实现监控功能,无需担心设备升级、维护等问题。
|
7月前
|
弹性计算 监控 安全
【阿里云弹性计算】ECS实例监控与告警系统构建:利用阿里云监控服务保障稳定性
【5月更文挑战第23天】在数字化时代,阿里云弹性计算服务(ECS)为业务连续性提供保障。通过阿里云监控服务,用户可实时监控ECS实例的CPU、内存、磁盘I/O和网络流量等指标。启用监控,创建自定义视图集中显示关键指标,并设置告警规则(如CPU使用率超80%),结合多种通知方式确保及时响应。定期维护和优化告警策略,利用健康诊断工具,能提升服务高可用性和稳定性,确保云服务的卓越性能。
268 1
|
弹性计算 运维 监控
基于云监控实现的监控系统
通过阿里云云监控功能给非阿里云主机安装监控插件,从而实现对非阿里云主机的各项指标进行监控和管理,在配置报警规则和报警人的情况下,能对特定的场景做出报警反应通知到报警人的手机上。
|
SQL 消息中间件 分布式计算
基于阿里云 CloudMonitor云监控自定义监控大盘对 EMR 自定义监控实践
本文旨在分享 EMR 平台大数据服务基于阿里云 CloudMonitor 的监控实践,给客户提供除了 EMR 平台默认监控以外,自建监控方式,适用于统一多个阿里云服务的监控监控场景。
837 2
基于阿里云 CloudMonitor云监控自定义监控大盘对 EMR 自定义监控实践
|
弹性计算 监控 应用服务中间件
云监控之自定义监控
云监控之自定义监控
|
数据采集 Prometheus 监控
使用云监控来监控线下IDC(及其它云)的Mongodb,Redis,Mysql等中间件
背景当前很多用户的服务部署在混合环境中,比如同时使用多个云厂商,或者云加线下IDC等。而对于线下IDC的监控主要是使用开源的系统来自建。带来的问题就是需要花费较大精力来维护自建监控系统并且和云上的监控数据也无法打通。针对这种混合云环境,云监控推出了企业版监控服务,可以实现在阿里云上对下线IDC或其它云服务上部署的中间件进行监控。线下IDC中间件监控实现在云监控上对下线IDC的中间件进行监控,主要实
636 9
使用云监控来监控线下IDC(及其它云)的Mongodb,Redis,Mysql等中间件
|
监控 负载均衡 网络协议
云监控-主机监控功能介绍|学习笔记
快速学习云监控-主机监控功能介绍
262 0
云监控-主机监控功能介绍|学习笔记
|
弹性计算 监控 开发者
云监控-创建 Dashboard 监控大盘|学习笔记
快速学习云监控-创建 Dashboard 监控大盘
236 0
云监控-创建 Dashboard 监控大盘|学习笔记
|
弹性计算 监控 开发者
云监控-创建Dashboard监控大盘|学习笔记
快速学习云监控-创建Dashboard监控大盘
251 0
云监控-创建Dashboard监控大盘|学习笔记