QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

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

发布了 1855 篇内容, 共 122.1 次阅读, 收获喜欢 79 次。

关注

评论

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

行云创新:与德国汽车业交流Catena-X数据空间技术有感

行云创新

平台工程 行云创新 Catena-X 云原生平台工程 数据共享空间

如何撰写How-To文章:7个高效步骤(新手SEOer向导)

九凌网络

Spring到底是如何解决循环依赖问题的?

高端章鱼哥

spring 循环依赖

淘宝API接口申请指南

联讯数据

09 | 队列:队列在线程池等有限资源池中的应用

鲁米

it统一运维平台怎么样?有可以推荐的品牌吗?

行云管家

IT运维 安全运维 统一运维

解密Prompt系列20. LLM Agent之再谈RAG的召回多样性优化

EquatorCoco

人工智能 算法 模型 LLM

inBuilder低代码平台新特性推荐-第十三期

inBuilder低代码平台

开源 低代码

瑞技案例 | 优雅焕新,Neat 重塑法国再保险混合办公体验

Bytebridge

混合办公 Neat 会议室升级 瑞技科技 Bytebridge

大型语言模型在实体关系提取中的应用探索

数由科技

Embedding LLM rag 实体关系识别

浪潮信息存储助力企业智能化变革

财见

.NET8 依赖注入

EquatorCoco

.net 开发 依赖注入

数据的力量:Web3 游戏运营指南

Footprint Analytics

区块链游戏 游戏运营 Web3 游戏

10 | 递归:如何用三行代码找到“最终推荐人”.md

鲁米

C++空类的那点事儿

树上有只程序猿

C++ 空类

商城开发

Geek_8da502

软件测试/人工智能|Python 数据类型解析:探索编程世界的多样性

霍格沃兹测试开发学社

开源大模型与微调策略概览

百度开发者中心

大模型 #人工智能 LLM

大模型训练:预训练模型与数据标准化

百度开发者中心

深度学习 #人工智能 LLM

金融大模型的微调实战

百度开发者中心

金融 大模型 #人工智能

每日一题:LeetCode-76. 最小覆盖子串

Geek_4z9ami

面试 算法 LeetCode 刷题 字符串

盘点那些国际知名的黑客(下篇)

禅道项目管理

互联网 黑客 计算机网络

一种全新的日志异常检测评估框架:LightAD

华为云开发者联盟

人工智能 机器学习 深度学习 华为云 华为云开发者联盟

软件测试/人工智能|Python 数据类型转换解析:理解数据之间的灵活转换

霍格沃兹测试开发学社

苹果万能视频播放器 Elmedia Video Player Pro中文最新版

胖墩儿不胖y

Mac软件 视频播放器 视频播放

LCM:大大加快生成高质量图像的新方法

互联网工科生

图像生成 LCM

软件测试/人工智能|Python 变量解析:从基础概念到内存地址探究

霍格沃兹测试开发学社

VPN证书过期问题梳理

Lane

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