V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
enchilada2020
V2EX  ›  问与答

有关 AWS 的提问,被困住好久,有没有高手救救弟弟

  •  1
     
  •   enchilada2020 · 312 天前 · 974 次点击
    这是一个创建于 312 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    现有几个 Web APP 共用一组 Lambda ,每个 Lambda 还会在同一个 APP 的不同阶段被多次调用

    目的

    根据业务逻辑将 Lambda 调用分成几组,统计每个 Lambda 在各个业务逻辑组内的运行时间Duration),并绘制成图表( Graphed Metrics )。

    WebAPP1 的业务逻辑分成了两组 ABWebAPP2 的业务逻辑分成两组 CDABCD 分别调用了 Lambda1Lambda2,想要按 ABCD 生成 4 个仪表盘( Dashboard ),每个表盘里分别显示 Lambda1Lambda2 在一段时间内的运行时间统计图。

    遇到的问题和目前为止的尝试

    1. Amazon CloudWatch 自带了 Metrics ,但通过免费的 Basic Metrics 得到的 Duration,只能按 Lambda 函数来统计,而无法将同一个函数的 Duration 根据业务逻辑进一步细分,即无法得知每次调用的 Duration 属于哪个业务逻辑组。 -> 于是考虑使用 Custom Metrics
    2. Custom Metrics 可以根据业务逻辑需要定义 Diemensions,但同时也需要自行提供用来统计的 Value。而且 Lambda 的精确运行时间只能在每次调用结束后由 AWS 自动统计得出。因此需要想办法得到 AWS 计算出来的那个 Duration。-> 查了一下似乎没有现成的 API 可用,但 AWS 会在每次调用结束后在 CloudWatch Logs 里留下 log ,里面包含了想要得到的那个 Duration
    3. 进而调查 CloudWatch Logs ,发现可以用 Logs Insights 的 Query 语法来解析 Log 文本,从而得到 AWS 自动生成的 Duration

    于是到此为止的思路是,每个 Lambda 在调用结束前都通过 Log 留下统计需要的信息(业务逻辑组名和函数名),并异步地触发另一个用来统计的 Lambda 。该 Lambda 首先通过 Query 来解析 Log 文本,并通过 RequestId 将业务逻辑信息与 AWS 提供的 Duration 匹配,生成用于 Custom Metics 的统计数据,最后推到 CloudWatch Metrics 上。

    那么问题来了,从 Lambda 留下 log 到可以用 Query 来搜索 CloudWatch Logs 解析 Log 文本,再到取得解析结果,每一个阶段都需要等待一段时间,具体时间尚不明确,目前粗略测试分别是 3 分钟和 5 秒。如果一次 Lambda 调用触发一回对该调用的 Log 解析和 Metrics 数据生成,就要花 3 分多的时间,似乎有些本末倒置了……毕竟处理业务逻辑也不至于用这么久,统计运行时间反倒更耗时就离谱。另外折腾半天走到这里,总感觉自己是在 XY 问题里面兜圈子。

    如果 AWS 能有某种现成功能来解决是再好不过的了,但翻文档看得要吐血也没什么头绪,希望群佬指点迷津:有没有什么其他更好的解法?如果当前思路大体尚可,该如何优化上述问题,还有哪些需要注意的问题?最后,如何从更宏观的视角来掌握 AWS 里的这些东西?

    感谢阅读,先行谢过!

    17 条回复    2023-06-22 17:27:27 +08:00
    enchilada2020
        1
    enchilada2020  
    OP
       311 天前 via Android
    彳亍口巴 似乎这边没什么人用 AWS…
    crazywind
        2
    crazywind  
       311 天前   ❤️ 1
    这种业务对时效性不高,你可以使用 eventbridge 做异步处理
    wantDead
        3
    wantDead  
       311 天前   ❤️ 1
    难道 AWS 不能根据不同的业务参数统计? 例如 WebAPP1 的业务逻辑分成了两组 A 和 B 都调用 Lambda1 。但是 A 和 B 有不同的 tag 。根据 tag 去统计不行吗?
    laxenade
        4
    laxenade  
       311 天前 via Android   ❤️ 1
    有两个方法你可以试试
    1. 给 Log Group 加个 filter ,把 Duration 和其他你想要的东西过滤出来就好了,https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html#matching-terms-events
    2. 给你的 Lambda 加一个 extension ,在 Shutdown 上挂一个钩子,钩子里我记得可以拿到运行时间
    enchilada2020
        5
    enchilada2020  
    OP
       311 天前 via Android
    @crazywind 得 又来个新概念 我再看下哈
    enchilada2020
        6
    enchilada2020  
    OP
       311 天前 via Android
    @wantDead 正是因为不知道怎样将 AWS 默认统计的 Duration 按所谓的 tag 区分 所以才用到 Custom Metrics 呀。。
    enchilada2020
        7
    enchilada2020  
    OP
       311 天前
    @laxenade 第一个我看过,但不确定自己理解的是否正确。试着用了那个 Filter Pattern 给用于统计的 Lambda 加了一个 [CloudWatch Logs Subscription Filter]( https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#LambdaFunctionExample),每个函数的 LogGroup 有匹配 Filter 规则的 Log 则触发 Lambda 。但遇到的问题跟在 Lambda 内直接异步调用统计用 Lambda 是一样的。。
    Extension 我再去了解下哈,感谢提供思路🍻
    forever0y
        8
    forever0y  
       311 天前   ❤️ 1
    去看看 step function ,看看对你有没有帮助。基本的编排它挺好用的,包括 log 的处理
    aws 有架构的课程和考试,在云上搭建基础设施基本上已经是国外的业界标准了。
    laxenade
        9
    laxenade  
       311 天前 via Android   ❤️ 1
    @enchilada2020 不用重新触发 Lambda 。Metric filter 可以直接发布 metrics ,https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CreateMetricFilterProcedure.html
    vmlinz
        10
    vmlinz  
       311 天前 via iPhone   ❤️ 1
    这个问题在文档里面有方案,使用 resource group 给负载打标签分类,比如项目或者部门这样的信息作为分类,lambda 的 metrics 会自动附加这些信息。

    https://docs.aws.amazon.com/lambda/latest/operatorguide/organize-workload.html
    vmlinz
        11
    vmlinz  
       311 天前 via iPhone   ❤️ 1
    https://docs.aws.amazon.com/ARG/latest/userguide/supported-resources.html

    有限制需要使用 cloudformation ,也就是你的部署工具需要操作最终生成的 cloudformation 模版,附加 resource group 。
    enchilada2020
        12
    enchilada2020  
    OP
       311 天前
    @laxenade 又试了一下,好像还是不行,问题在于:
    1. Lambda 调用结束前留下的统计需要的信息(业务逻辑组名和函数名),与 AWS CloudWatch 在调用结束后留下的包含 `Duration` 的 REPORT ,是两行分开的 Log
    2. 无论是基于关键字匹配( match terms )的 Filter Patterns ,还是根据空格分隔取值( extract values from space-delimited ) 的 Metric Filter ,都只能对应某一行 Log ,即只能取到 `Duration` 或者组名和函数名,无法同时获取;另外就算能取到值,还需要进一步根据 RequestId 将两者匹配,这一步似乎也无法用 Filter 做到

    例:

    ```
    2023-06-21T00:00:00.000Z <RequestID> INFO GroupName<GROUP_FOO> FunctionName<FooFunction>

    REPORT RequestId: <RequestID> Duration: 43.26 ms Billed Duration: 44 ms Memory Size: 128 MB Max Memory Used: 58 MB Init Duration: 160.08 ms
    ```

    第一行是我们在 Lambda 里主动留下的,第二行是调用结束后 AWS 自动生成的。
    enchilada2020
        13
    enchilada2020  
    OP
       311 天前
    @vmlinz 这个我也看过,Resource Group 在 Lambda 的 SAM template 里是能用的,但以我的理解,Resource Group 是将互相关联的一类资源通过标签( Tags )分类到一个组里,比如用户注册功能涉及到了 Lambda 、API GateWay 和 RDS 之类的,就给它们打标签分到一个用户注册组里。而我现在的需求是对于同一个 Lambda , 根据请求参数的不同,把其 Metrics 里的 Duration 信息分到不同业务逻辑组里。
    vmlinz
        14
    vmlinz  
       310 天前 via iPhone   ❤️ 1
    好吧,那需要回来再看看你的应用是怎么和 lambda 交互的了。如果你的不同来源只能在应用逻辑里面才能区分,那你可以使用自定义 metrics 把用于区分不同业务逻辑来源的信息 publish 出去,这样 metrics 里面就多出来你自定义的 field ,可以实现分组。

    如果你的调用来源在应用逻辑以外就能区分,比如 resource group 这种,固定好的静态调用关系,那就不需要自定义 metrics 了。
    enchilada2020
        15
    enchilada2020  
    OP
       310 天前
    @vmlinz 只能在应用逻辑里面区分,前端在不同业务阶段给 Lambda 传参,Lambda 通过参数来区分此次调用属于哪个业务逻辑组,最后根据业务逻辑组分类 Duration……我也想到了用自定义 Metrics:

    ```TS
    const input: PutMetricDataInput = {
    Namespace: groupName, // 按业务逻辑组生成 Metrics 的 Namespace
    MetricData: [
    {
    MetricName: 'Duration',
    Dimensions: [
    {
    Name: 'FunctionName',
    Value: funcName, // 按 Lambda 函数名生成 Deimensions
    },
    ],
    Timestamp: new Date(),
    Value: 0, // <- ????? // 需要自行提供 Duration 的值,目前所知只能通过 Log Insighs 的 Query 获取
    Unit: StandardUnit.Milliseconds,
    },
    ],

    };
    ```
    laxenade
        16
    laxenade  
       310 天前 via Android   ❤️ 1
    所以其实为什么不能在 handler 前后加一个 timer ,你要是不加其他乱七八糟的 extension ,你自己测出来的时间和 lambda 给的应该很接近才对。
    enchilada2020
        17
    enchilada2020  
    OP
       309 天前
    @laxenade 自己测的一定是不准的,最后调用`PutMetricDataCommand`的那段 await 用时无法包含在测量结果之内。
    另外说不定哪天脑袋一拍又要改成统计计费时间( Billed Duration )。。

    目前的思路还是调用结束前都通过 Log 留下统计需要的信息,给 Log Group 添加 Subscription Filter ,根据关键字筛选 Log 文本,如果匹配 Pattern 则触发 CloudWatchLogs 事件,进而调用统计用 Lambda 。因为直接能从参数里拿到 Log 内容,就不用再按时间范围查询 Log 再解析了,直接用正则把需要的信息提取出来并根据 `RequestId` 匹配就行。

    很脏很不优雅的做法(从只能解析 Log 开始就感觉不对劲),而且正确性也不知道能不能保证。只是以我对 AWS 有限的了解只能做到这种程度了。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2857 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 07:23 · PVG 15:23 · LAX 00:23 · JFK 03:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.