2025上半年,最新 AI实践都在这!20+ 应用案例,任听一场议题就值回票价 了解详情
写点什么

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:251378
用户头像

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

关注

评论

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

一文搞懂指标采集利器 Telegraf

尔达Erda

学习 微服务 开发者 云原生 插件开发

2021 年主要网络安全威胁,及时发现提早规避风险

九河云安全

如何评价Netty封装的io_uring?

BUG侦探

Netty 网络 io_uring

当新零售遇上 Serverless

Serverless Devs

阿里云 Serverless 云原生

28天读完349页,这份阿里面试通关手册,助我闯进字节跳动

Java~~~

Java 面试 算法 多线程 架构师

终于有人把“SpringCloudAlibaba学习笔记”整理出来了

Java 程序员 架构 微服务 计算机

又一里程碑!阿里首推Java技术成长笔记,业内评级“钻石级”

Java~~~

Java redis spring 面试 架构师

二十不惑的年纪,我简直走了狗屎运(4面拿字节跳动offer)

Java~~~

Java 面试 微服务 多线程 架构师

全面到哭!BAT内部Java求职面试宝典,应届生必须人手一份

Java~~~

Java 面试 微服务 多线程 架构师

阿里巴巴大神发布的Java零基础笔记,实战教程多到手软,跪了

Java~~~

Java 面试 微服务 多线程 架构师

经验分享:我是如何拿下微软、滴滴、百度等 20家大厂的 Offer?

Java 程序员 架构 面试 IT

清爽视频编辑器 Tech Support

凌天一击

什么是DPDK?DPDK的原理及学习学习路线总结

Linux服务器开发

Linux服务器开发 DPDK Linux后台开发 网络性能 网络原理

987页的Java面试宝典,看完才发现,应届生求职也没那么难

Java~~~

Java 面试 微服务 多线程 架构师

FastApi-05-请求体-2

Python研究所

FastApi 8月日更

毕业六年本科,去年疫情期间备战二个月,阿里巴巴四面成功!定级 P7

Java 程序员 架构 面试 IT

经过两年努力,我终于进入腾讯(PCG事业群4面总结)

公众号_愿天堂没有BUG

Java 编程 程序员 架构 面试

低代码开发平台的出现会是开发者的威胁吗

雯雯写代码

开发者 低代码 低代码开发平台

新一代设计编排交付套件分享

鲸品堂

交付工具

百分点科技参加MIT数智未来创新峰会 入选产业数字化生态图谱

百分点科技技术团队

读完SpringBoot,Cloud,Nginx与Docker技术,我拿到了阿里offer

公众号_愿天堂没有BUG

Java 编程 程序员 架构 面试

社招三面阿里“落榜”,幸获内推名额,4面揽下美团offer

公众号_愿天堂没有BUG

Java 编程 程序员 架构 面试

【SpringCloud技术专题】「原生态Fegin」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(上)

码界西柚

SpringCloud OpenFegin Fegin 8月日更

使用Micronaut框架构建一个微服务网络.

Java 编程 架构 面试 程序人生

Spring Boot 实战派,让开发像喝水一样简单!

Java 程序员 架构 面试 IT

渣本全力以赴33天,四面阿里妈妈(淘宝联盟),拿下实习岗offer

公众号_愿天堂没有BUG

Java 编程 程序员 架构 面试

凭借一份“面试真经pdf”,我四面字节跳动,拿下1-2级offer

公众号_愿天堂没有BUG

Java 编程 程序员 架构 面试

消息推送技术干货:美团实时消息推送服务的技术演进之路

JackJiang

消息推送 即时通讯 IM push

virtlet是什么?virtlet如何管理虚拟机?

谐云

快照保护是什么意思?快照的原理是什么?

行云管家

镜像 数据保护 快照 数据安全

运维安全第一步,采购堡垒机做好权限控制!

行云管家

堡垒机 安全运维 企业资产 事前授权

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