亚马逊AWS官方博客

Amazon Lambda on ARM 在TCL的实践

什么是 Lambda on ARM

在过去的数十年间服务器主要使用X86_64架构的CPU,鲜有基于其他架构的CPU出现或者占据主要市场份额.不过最近这个局面被打破了,移动互联网的高速发展极大的推动了ARM架构CPU的发展,以往拥有能效比优势的ARM CPU只会在手机和嵌入式设备等对功耗敏感的设备上被使用,现在随着ARM CPU的性能在过去的数年间不断的提升并继续维持相对高的能效比优势,越来越多的领域开始使用ARM CPU,比如个人电脑领域和服务器领域.

亚马逊云科技于2021年9月29日推出了使用ARM提供底层计算能力的Lambda服务,它运行在亚马逊云科技自研的Graviton2上旨在提供好的性能和更低成本.亚马逊云科技官方宣称相比当前的X86_64,运行在 Graviton2上的Lambda能有降低20%的运行成本(GB-s)并实现最多高达19%的性能提升,理论上以往运行在X86_64CPU上的Lambda如果迁移到ARM CPU上能提升最大约34%的效费比.

快速上手体验

TCL鸿鹄实验室海外云团队目前大量使用了Lambda服务,并围绕它建设了的Serverless架构的IoT云平台. 我们的平台为TCL集团在海外的用户提供AIoT服务,覆盖了美国,欧洲,东南亚和印度等主要的国家和地区并计划逐步为更多的国家和地区提供优质的AIoT服务.

基于Lambda和IoTCore的Serverless架构非常适合当下的IoT领域,在Lambda推出运行在ARM CPU上的运行时后,我们第一时间做了早期的试用. 理论上讲,从当前的X86_64架构迁移到ARM64架构是很容易的,假如原先运行的代码是平台无关的,那么你甚至可以直接将架构切换为ARM64而不会出问题,当然在上线前建议做一些必要的兼容性测试和金丝雀部署来保证线上服务的稳定.

我们在Lambda的技术选型上使用的是serverless. 本次验收使用的运行环境如下表:

软件 版本 备注
Python 3 3.8 版本必须不低于 3.8
Serverless 2.62.0 版本必须不低于 2.61.0

本次实验的示意图

serveless.yml调整

从当前的X86_64架构换为ARM64架构是完全开箱即用的,我们只需要新加一个architecture 属性并设置为arm64即可(如果你想要使用X86_64那么可以填x86_64),以前的代码如果是平台无关的话可以完全不做任何改动. 对此Serverless instruction-set-architecture 有详细的说明.

...

provider:
  lambdaHashingVersion: 20201221
  # 服务提供商名称
  name: 
  # CPU架构(x86_64 or arm64)
  # https://www.serverless.com/framework/docs/providers/guide/functions/#instruction-set-architecture
  # https://forum.serverless.com/t/hoping-architecture-arm64-is-available-soon/15997
  architecture: arm64

...

代码样例

这是本次演示的平台无关的Python代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import datetime
import json
import os
import platform
from time import time


class ComputationallyIntensive:
    """
    计算密集型任务

    简单测试X86_64和ARM64在计算密集型任务下的计算性能
    """

    def __init__(self):
        # 随机值,秒级的范围内不同的lambda instance是相同的
        second = datetime.datetime.now().second
        self._number = second

    def fib(self) -> list:
        """
        斐波那契数列
        """
        if self._number == 1:
            return [1]
        if self._number == 2:
            return [1, 1]
        fibs = [1, 1]
        for i in range(2, self._number):
            v = fibs[-1] + fibs[-2]
            fibs.append(v)
        return fibs


def lambda_handler(event, context):
    # 构造返回体数据
    body = {
        "developer": "ThinkTik",
        "echo": "TCL Overseas IoT Team Serverless 演示",
        # Lambda 执行环境
        " EXECUTION ENV": os.environ.get('***_EXECUTION_ENV'),
        # 动态读取CPU架构信息
        "CPU Arch": platform.machine(),
        "timestamp": int(time())
    }

    # 模拟计算密集型的耗时操作
    computationally_intensive = ComputationallyIntensive()
    computationally_intensive.fib()

    # 返回json内容
    return {
        "statusCode": 200,
        "headers": {
            "Content-Type": "application/json"
        },
        "body": json.dumps(body)
    }

当你完成了serveless.yml的调整后,就可以直接发布了.

效果如下:

改动前使用x86_64接口返回值

改动后使用ARM64接口返回值

压力测试和效费比分析

为了保证X86和ARM64运行环境都能平均的分摊jmeter发过

来的大量的请求,我们使用Aliases对2个版本做了50:50的流量均衡负载.此外内存等其他配置2个版本是完全一样的.

经过一段时间的压测,我们可以在cloudwatch上看到运行指标,图中蓝色代表ARM64(85版本),红色色代表x86(84版本). 统计学的角度来看我们可以观察到ARM64的平均处理时间是低于X86的,也就是相同的请求ARM64会在更短的时间完成处理的更快.

Lambda On ARM的优势

Lambda是一种无服务器的计算服务,您只需按使用量付费. 亚马逊云科技根据您函数的请求数量和持续时间,以及代码执行花费的时间向您收费.

相比X86_64版本的Lambda新推出的ARM64有如下的优势:

  • 对于平台无关的代码,ARM64版本的Lambda可以有最高19%的性能提升.这意味着相同的代码切换为ARM64后会程序会运行的更快,花费的运行时长更短
  • 对于单位运行时间(GB-s),ARM64的费用更加便宜,相比X86_64低约20%. 具体请看Lambda price

亚马逊云科技官方宣称是最大34%,具体数据取决于代码实际的运行情况.以本次的例子计算,请求的单位平均运行时长缩短到以前的91%(1.399/1.527),如果一份代码从X86迁移到ARM会节省费用1-(1-0.2)*0.91=0.272也就是27.2%,所以一般而言运行在ARM上的Lambda有更好的效费比.

从X86_64迁移到ARM

经过我们实际的部署演示和优势分析,从X86_64迁移到ARM64我们只需要付出极小的DevOps成本就可以节省大量的费用,同时降低单次请求的时长也提供了更好的用户体验.

除了上面的优势,我们在迁移的过程中需要注意下面的几个关键点:

  1. Lamdba对语言的支持情况,可能部分语言暂时还不支持运行在ARM CPU上或者某些语言的低版本不会被支持
  2. 公司CI/CD基础设施是否满足同时进行X86_64和ARM的部署能力.
  3. 项目中用到的代码和程序的兼容性
    • 需要检查当前Lambda Layer中引用的第三方组件或者自定义组件是否是CPU指令集无关的或者是否可以提供ARM版本
    • 需要检查业务代码是否是是否是CPU指令集无关的,如果依赖X86_64指令集那么可能你需要调整自己的代码

在做好了全部的评估后,我们需要在上下前做好如下几点:

  • 全面而完善的测试:及时发现原先的代码在ARM64上出现的运行问题
  • 阶段性的有计划切换:有规划的金丝雀发布和A/B版本间的流量规划
    • A/B版本间的流量规划: 在ARM64正式使用的早期阶段,建议一段时间内同时提供X86_64和ARM64版本并同时在正式环境运行,将线上流量以某种规则(例如alias routing configuration)分配到相同逻辑但是不同CPU架构的2个版本上.例如80%的流量流向X86_64,剩余的20%流向ARM64,在数周或者数月的观察后可以逐渐的提升ARM64的流量占比
    • 金丝雀发布: 在X86_64切换为ARM的发布过程中,使用金丝雀发布. 线上的流量以一定的速度逐渐小批量的切换到ARM64上来,如果发现了错误就逐渐的回退到X86_64上.
  • 持续的监控: 在ARM64版本的服务上线后,需要通过持续的监控/链路追踪系统监视平台的运行情况. 检查是否有运行异常,对比X86_64后ARM64版本的服务是否代码运行效率更高了而不是变得更差.

参考:

本篇作者

汪建业

汪建业,亚马逊云科技解决方案架构师,负责基于亚马逊云科技云计算方案架构的咨询和设计,同时致力于 亚马逊云科技 IoT 和大数据服务在国内和全球企业客户的应用和推广。十余年分布式应用、大数据的分布式处理经验。

罗新宇

TCL 鸿鹄实验室 海外IoT云端开发工程师;相信技术的力量,致力于Serverless在云原生架构中的应用。