写点什么

AWS Lambda 收集自定义指标 (Metrics) 最佳实践

  • 2019-10-04
  • 本文字数:5056 字

    阅读完需:约 17 分钟

AWS Lambda 收集自定义指标 (Metrics) 最佳实践

前言

AWS Lambda 是非常受欢迎的无服务器运行代码的云服务。我们知道 AWS Lambda 运行所产生的日志(logs)会自动收集到 CloudWatch Logs 中,Lambda 所产生的通用运行指标(metrics) 例如:“调用数”、“持续时间”、“错误”、“并发数”等都会自动收集到 CloudWatch Metrics 中监控。而本文将阐述几种自定义指标的收集方法及其优缺点。


有一些场景是需要收集 AWS Lambda 运行产生的一些数据指标的,例如:用户访问行为相关的数据,某个函数分段的执行时长,某个实时参数等。这些指标与 Lambda 的运行本身无关,所以不像 Lambda“调用数”、“持续时间”这些通用指标会自动反映到 CloudWatch 上。如果是有服务器(例如 Amazon EC2)的常见做法,可以记录到本地文件中,由一个独立 Agent 定时发送到 CloudWatch 上,例如在 EC2 上安装 CloudWatch Agent 去做收集。参见“使用 CloudWatch 代理从 Amazon EC2 实例和本地服务器收集指标和日志”。


而无服务器的 Lambda 虽然有一个本地临时目录(\tmp)可以写入文件,但 Lambda 运行环境是会被暂停或回收的,写本地文件并不可靠,可能会导致数据来不及发送就暂停或丢失了,那这些自定义的 Lambda 运行指标要怎么收集和监控呢?

预备知识

  1. AWS Lambda 已与 CloudWatch Logs 集成,函数所产生的日志会自动收集到 CloudWatch Logs 。输出和查看日志的方法参见 AWS Lambda 文档。不同的开发语言有相应的输出语句,例如以下 Python 语句都能生成日志:


  • print 语句

  • logging 模块中的 Logger 函数(例如,Logger.info 和 logging.Logger.error)

  • 其他语言例如 Node.js 的 console.log(),Java 的 Log4j 2 或 LambdaLogger.log(),Golang 的 log.Print() 都有类似的效果,自动输出日志到 CloudWatch Logs。


  1. 如果是做故障定位和性能优化的,可以采用 AWS X-Ray 方便地跟踪 Lambda 函数运行

  2. 如果你发现需要对 Lambda 函数代码分段运行时间进行很多监控,并进行优化,则建议先重新考虑一下,是否你的 Lambda 函数设计得太大了。单个 Lambda 函数是否包含了过多的业务逻辑?如果是有多个步骤组成的,可以考虑改为多个 Lambda 函数,并使用 AWS Step Function 工作流进行协同。

Lambda 自定义指标的收集和监控

以下列举三种收集 Lambda 自定义指标的方法,分别是


  • 直接发送 CloudWatch PutMetricData API 接口收集

  • 利用 CloudWatch 日志过滤收集

  • 利用 CloudWatch 日志触发 Lambda 来处理和提交 CloudWatch 接口

  • 方法一:直接调用 CloudWatch PutMetricData API

  • CloudWatch 提供了 PutMetricData API,可以在函数代码中直接调用该 API 把指标数据提交到 CloudWatch。



优点:Lambda 函数运行的时候同步请求发送数据,指标最小粒度达到 1 秒。


缺点:同步方式,增加了函数的运行时间。您将在后面的实验结果中看到,例子中每次发送 PutMetricData 的时间约 50ms。时延依赖于 CloudWatch API 的响应速度,如果 CloudWatch API 有异常则直接对主业务逻辑造成影响。


另外要注意,默认的软限制是 PutMetricData 150 transactions per second (TPS),可申请提升。


实现方式,例如以下 Python 编写的 Lambda 示例:


import boto3
CWclient = boto3.client('cloudwatch')

def lambda_handler(event, context):
CWclient.put_metric_data(
Namespace='LambdaCustomMetrics',
MetricData=[
{
'MetricName': 'myPutCustomMetric',
'Value': value,
'StorageResolution': 1
},
]
)
return
复制代码


注意:Lambda 的运行角色需要有 cloudwatch:PutMetricData 执行权限


方法二:通过 CloudWatch Logs Filter 传递指标


如前所述,Lambda 已经集成了 CloudWatch Logs,可以在函数中把需要传递的指标写入日志,并在 CloudWatch Logs 中设置过滤器(Filter)来提取指标。



优点:异步方式,避免了对函数运行时间的影响。 Lambda 写 Log 是后台自动完成无需考虑架构。


缺点:统计结果只精确到分钟。且需要配置管理 Logs Filter 。CloudWatch Logs Filter 每个日志组只能设置 100 个,硬限制,不适合一个 Lambda 有大量个性化指标和粒度为秒的情况。


实现方式,例如以下 Lambda 的 Python 语句将写入日志:


print(‘my_metric_in_log myCustomMetric’, str(value))


然后,在 CloudWatch Logs 控制面板对应 Lambda 的日志组(Log Group)中设置 Filter



设置过滤模版(Filter Pattern),本例中写入的日志是“my_metric_in_log 名字 数值”,所以模版配置成“[p=my_metric_in_log, name, value]”。您可以点击”Test Pattern”测试现有日志的匹配结果。



匹配到关键字 my_metric_in_log 的日志,就会取出值到 value 变量。在下一步中,配置 Metric 值为 $value 变量即可实现从日志中提取指标。考虑到避免空数据的情况,可选设置默认值为 0。



保存了 Filter 的配置后,可以点击您设置的指标名称跳转到对应的监控指标界面。或者点击 Create Alarm 配置告警阀值,并实现联动,例如发送 SNS 通知或者触发 Lambda 做自动化处理。



方法一、二的示例和实验结果对比


我们用一个 Lambda 函数同时做方法一和方法二,我们来对比一下。代码示例如下:


本例中,我们随机生成一个 value 作为要发送的指标数据,每个数据是随机的 1-20 整数。每次发送指标到 CloudWatch PutMetricData API 接口的间隔为 1 秒,并同时写入日志。让 Lambda 运行 600 秒,即我们应该收到 600 次发送指标数据。最后返回统计平均每次 PutMetricData 的时间。


import boto3
import time
import datetime
import random
CWclient = boto3.client('cloudwatch')

def lambda_handler(event, context):
total_detal = 0
for i in range(0, 600):
# caculate put metric time
start = datetime.datetime.now()

# put custom metric
value = random.randint(1, 20)
CWclient.put_metric_data(
Namespace='LambdaCustomMetrics',
MetricData=[
{
'MetricName': 'myPutCustomMetric',
'Value': value,
'StorageResolution': 1
},
]
)
end = datetime.datetime.now()
delta = ((end - start).microseconds) / 1000
total_detal += delta
time.sleep(0.95)
print('my_metric_in_log myCustomMetric', str(value))
return 'avg_detal: '+str(total_detal/600)

复制代码


当我们用 CloudWatch 同时打开 PutMetricData 获得的指标(下图左侧单位,蓝色曲线)和通过 Log Filter 获得的指标(下图右侧单位,橙色曲线)。


  • 统计周期一分钟

  • 选择统计方式为“求和” (Sum),统计周期为 1 分钟。我们会看到两种方式的曲线非常重合,时延和数值的差异并不大,结果如下图:


把统计方式改为“采样数量” (Sample Count),统计周期依然是 1 分钟。两种方式也是一致的,每分钟都收到了 60 次数据。



统计方式改为“平均值” (Average),两种方式结果相近。



  • 统计周期 1 秒

  • 如果把统计周期改为 1 秒,我们再看“求和” Sum、“采样数量” Sample Count 和“平均值” Average 的结果。采用 PutMetricData 收集的数据可以达到秒级的粒度,而采用 Logs Filter 的方式则不能。




我们再看看 PutMetricData 所消耗的时间,在本次测试的这 10 分钟内,每次请求的平均时间接近 50ms。



方法三:CloudWatch Logs 触发 Lambda 做指标提取并提交


即把方法一中的主 Lambda 函数中的 PutMetricData 操作剥离成一个独立的提取指标的 Lambda,主 Lambda 像方法二那样把指标写入 Logs ,然后配置 CloudWatch Logs 触发提取指标的 Lambda 从 Logs 中提取并提交 CloudWatch 指标收集



优点:主函数逻辑和提交指标异步解耦,互相不影响。CloudWatch Logs 触发 Lambda 是异步触发,出错会自动重试 2 次。统计精度达到秒级。不受每个 Logs Group 的 Filter 100 个数量的限制,完全自定义,非常灵活。


缺点:架构变复杂了。 Lambda 的并发多了一倍。


实现方式,新建一个从 Logs 中提取指标的 Lambda,配置这个 Lambda 由 CloudWatch Logs 触发,选择主 Lambda 函数的日志组,配置筛选模式(Filter Pattern)跟前面方式二在 CloudWatch Logs 中配置 Filter Pattern 一样的方式。如下图:



编写处理日志的 Lambda 函数。注意 CloudWatch Logs 触发 Lambda 所提交的 event 是经 base64 编码且是压缩的,需解压处理,示例代码如下:


import json
import gzip
import base64
import boto3
CWclient = boto3.client('cloudwatch')

def lambda_handler(event, context):
# TODO implement
payload = gzip.decompress(base64.b64decode(event['awslogs']['data']))
value_list = json.loads(payload)['logEvents']
for i in value_list:
try:
value = int(i['extractedFields']['value'])

# put custom metric
CWclient.put_metric_data(
Namespace='LambdaCustomMetrics',
MetricData=[
{
'MetricName': 'SecondLambdaPutMetric',
'Value': value,
'StorageResolution': 1
},
]
)
except Exception as e:
print(e)
return

复制代码


匹配了 Filter Pattern 所输出的 logEvnets 示例如下:


{
"messageType": "DATA_MESSAGE",
"owner": "31340000000",
"logGroup": "/aws/lambda/putLogsMetrics",
"logStream": "2019/03/29/[$LATEST]a4e25d49479441439bf06f41dfeb339c",
"subscriptionFilters": [
"Lambda_custom_metric_proccess_filter"
],
"logEvents": [
{
"id": "34651910332582237088994078865747388003785804733060153344",
"timestamp": 1553845399519,
"message": "my_metric_in_log myCustomMetric 15\\n",
"extractedFields": {
"p": "my_metric_in_log",
"name": "myCustomMetric",
"value": "15"
}
}
]
}
复制代码


留意这里有个“extractedFields”属性,就是填了筛选模式(Filter Pattern)后系统从 message 中匹配出来的,如果不填 Pattern,则没有“extractedFields”属性,只有前面那个“message”属性。


然后提交 PutMetricData 到 CloudWatch 操作同方法一,此处不再赘述。


由于本例的 Lambda 是每秒发一次数据,所以我们这里用统计的每秒“平均值”展示结果:


左边单位蓝色曲线的是主 Lambda 函数直接 PutMetricData,右边单位橙色曲线的是经过 Log 触发后的 Lambda PutMetricData。数据基本一致,曲线显示延迟了 2 秒左右。



方法三延伸 1:


当然,如果有多个 Lambda 应用,可以共用一个专门的转发指标的 Lambda 。如下图:



方法三延伸 2:


要注意,默认的软限制是 PutMetricData 150 transactions per second (TPS),可申请提升。如果并发较高的,建议用 Kinesis 收集汇聚,然后再发送 CloudWatch Metric 或发送其他指标监控平台。



相关文章:


使用 CloudWatch 代理从 Amazon EC2 实例和本地服务器收集指标和日志


https://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html


AWS Lambda 文档 https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/welcome.html


Amazon CloudWatch 发布自定义指标” 文档”


https://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/monitoring/publishingMetrics.html


AWS Python SDK 文档


https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudwatch.html#CloudWatch.Client.put_metric_data


AWS X-Ray 文档


https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/lambda-x-ray.html


作者介绍:


黄卓斌


AWS 解决方案架构师,拥有 20 年移动互联网、大型企业复杂应用系统架构和设计经验。擅长分布式和高可用软件系统设计,微服务与无服务器架构设计,移动互联网应用和大数据分析解决方案。加入亚马逊前,曾任职移动互联网公司 CTO,还曾任职华为、诺基亚等,以及长期驻访美国、印度等从事合作项目开发。


本文转载自 AWS 技术博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/aws-lambda-collect-new-metrics-best-cases/


2019-10-04 20:251475
用户头像

发布了 1929 篇内容, 共 155.6 次阅读, 收获喜欢 81 次。

关注

评论

发布
暂无评论
发现更多内容

How to solve the different brightness of LED display colors

Dylan

LED LED display

帮助文档在软件中的存在价值是什么?

小炮

物联网低代码平台如何添加报警配置?

AIRIOT

物联网 低代码开发 低代码平台

justcows奶牛理财dapp系统开发

开发微hkkf5566

数据智能基础设施升级窗口将至?看九章云极 DingoDB 如何击破数据痛点

九章云极DataCanvas

人工智能 数据库 数据 数据智能

从 keynote 大神到语雀画图大神,她是怎么做到的?

编辑器 思维导图 文档管理 企业知识管理

【Java Web 系列】Session的原理分析和使用细节

倔强的牛角

Java javaWeb session 6月月更

API工具--Apifox和Postman对比(区别)

Liam

Java 后端 Postman API API接口管理

天翼云数据中台通过“数字政府智慧中台”评估

极客天地

深度合作 | TDengine + 华为云 Stack 强强联合打造高效物联网时序数据处理解决方案

TDengine

数据库 tdengine 时序数据库

InfoQ 极客传媒 15 周年庆征文|Spring Cloud netflix概览及架构设计

No Silver Bullet

架构 6月月更 InfoQ极客传媒15周年庆 Spring Cloud netflix

2022年中国社区团购发展新动向

易观分析

社区团购

云GPU的618,拿捏了

恒源云

人工智能 深度学习 GPU服务器

十分钟带你入门Docker容器引擎

百思不得小赵

云原生 Docker 镜像 6月月更

从行业角度看,数仓领域的未来是什么?

字节跳动数据平台

字节跳动 数据仓库 OLAP

web前端培训VUE开发者需要知道哪些实用技术点

@零度

Vue 前端开发

KubeVela 1.4:让应用交付更安全、上手更简单、过程更透明

孙健波

Kubernetes OAM KubeVela 云原生应用 K8s 多集群管理

【云计算】云计算平台是什么意思?可以划分为哪三类?

行云管家

云计算 云服务 私有云 云平台 云计算平台

保险APP适老化服务评测框架 发布

易观分析

保险

融云首席科学家任杰:数字游民和意识体,疫情将如何影响人类社会进化

融云 RongCloud

二级等保要求几年做一次测评?测评项目有多少项?

行云管家

等级保护 等保测评 二级等保 等保二级

量化夹子机器人系统开发逻辑分析

开发微hkkf5566

Nginx 配置和性能调优

CRMEB

TiDB 6.0 实战分享丨内存悲观锁原理浅析与实践

PingCAP

分布式数据库 TiDB

直播app源码,充值提现模板的设计看似简单却不简单

开源直播系统源码

软件开发 直播源码 app定制开发

【LeetCode】找到一个数字的 K 美丽值Java题解

Albert

LeetCode 6月月更

IT采购专家指导 联想百应618 IT运维软硬服一站集采

极客天地

Go语言入门基础之库源码文件

Damon

6月月更

Wallys/Routerboard/DR344/WiFi/AR9344 FCC/CE/IC

wallys-wifi6

AR9344 802.11a

服务网格项目Aeraki Mesh正式进入CNCF沙箱

York

开源 云原生 istio Service Mesh 服务网格 cncf

IDM短信发送接口设计说明

agileai

数据安全 集成底座 企业服务总线 统一身份管理平台 主数据管理平台

AWS Lambda 收集自定义指标 (Metrics) 最佳实践_语言 & 开发_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章