一、第三方依赖升级的痛点与测试必要性
很多开发者写AWS Lambda函数时,都会用现成的第三方依赖来省事儿——比如用axios发请求、用lodash处理数组、用uuid生成唯一ID。但这些依赖不是一成不变的,开发者时不时就得升级版本:要么是旧版本有安全漏洞(比如之前lodash的原型污染漏洞),要么是新版本加了好用的功能,要么是旧版本不再维护了。
但升级依赖最怕的是什么?是“升级完函数跑崩了”。比如你升级了axios,结果函数里发请求的逻辑报错;或者升级了lodash,数组处理的结果和之前完全不一样。更坑的是,很多人升级完只测自己本地的函数,没测真实Lambda环境的情况,结果上线后才发现问题,影响业务。所以,一套靠谱的兼容性测试方案,是升级依赖前必须做的事。
二、兼容性测试的核心原则
做测试不能瞎测,得有原则,不然测了也白测。
2.1 最小变更原则
升级依赖时,别一次性升好几个,最好一个一个来。比如你要升级axios和lodash,先只升级axios,测完没问题,再升级lodash。这样如果出问题,你能立刻定位是哪个依赖的锅,不会像一锅粥似的乱。
2.2 真实环境模拟原则
本地环境和Lambda环境不一样,比如Lambda的运行时版本(比如Node.js 18.x、Python 3.10)、内存配置、权限都可能影响函数运行。所以测试不能只在本地测,得尽可能模拟真实的Lambda环境,或者直接在Lambda的测试环境测。
2.3 业务逻辑优先原则
测试不是测依赖本身,是测你的函数依赖升级后,业务逻辑能不能正常跑。比如你的函数是用来处理用户订单的,升级依赖后,得测订单能不能正常生成、能不能正确发送通知,而不是只测依赖的某个函数能不能调用。
三、具体测试方案与示例
这里我们用Node.js技术栈来做完整示例,所有代码都符合要求。
3.1 准备测试环境
首先,你得有两个Lambda函数:一个是生产环境的旧版本函数(已经上线,业务正常),一个是测试环境的新版本函数(升级了依赖)。或者你也可以用AWS SAM(Serverless Application Model)来管理函数,这样能方便地部署和测试。
先安装AWS CLI和AWS SAM CLI,这两个工具是管理Lambda的基础:
# 安装AWS CLI(已安装可跳过)
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
# 安装AWS SAM CLI(已安装可跳过)
pip install aws-sam-cli
然后初始化一个SAM项目,用来管理Lambda函数:
# 初始化SAM项目,选择Node.js 18.x运行时
sam init --runtime nodejs18.x --name lambda-dependency-test --no-interactive
进入项目目录,你会看到一个hello-world函数,我们修改它的代码,加上一个第三方依赖,比如lodash,用来做数组去重:
// src/hello-world/app.js
const _ = require('lodash');
exports.lambdaHandler = async (event, context) => {
try {
// 模拟业务逻辑:处理用户输入的数组,去重后返回
const inputArray = event.inputArray || [1, 2, 2, 3, 3, 3];
const uniqueArray = _.uniq(inputArray);
return {
statusCode: 200,
body: JSON.stringify({
message: '处理成功',
uniqueArray: uniqueArray
})
};
} catch (err) {
return {
statusCode: 500,
body: JSON.stringify({
error: err.message
})
};
}
};
然后安装lodash的旧版本(比如4.17.15),用来模拟生产环境的依赖:
# 进入函数目录
cd src/hello-world
# 安装旧版本lodash
npm install lodash@4.17.15
# 安装完成后,回到项目根目录
cd ../..
3.2 升级依赖并测试
现在我们要升级lodash到新版本(比如4.17.21),然后做兼容性测试。
第一步,升级依赖:
# 进入函数目录
cd src/hello-world
# 升级lodash到指定新版本
npm install lodash@4.17.21
# 回到项目根目录
cd ../..
第二步,部署测试版本的函数。这里我们用SAM的部署命令,先配置一个测试环境的部署:
# 配置SAM部署的参数,测试环境的函数名称可以加-test后缀
sam deploy --guided
# 按照提示输入:
# Stack Name: lambda-dependency-test-stack
# AWS Region: 选你函数所在的区域,比如us-east-1
# HelloWorldFunctionName: lambda-dependency-test-function-test
# 其他选项默认,输入Y确认
部署完成后,你会得到测试函数的ARN(Amazon Resource Name),接下来做测试。
3.3 功能测试
功能测试是最基础的,就是测函数的输入输出是否符合预期。我们用AWS CLI来调用测试函数,传入和生产环境一样的输入,看输出是否一致。
首先,先调用生产环境的旧版本函数,拿到预期输出:
# 调用生产环境的函数,输入测试数组[1,2,2,3,3,3]
aws lambda invoke --function-name lambda-dependency-test-function --payload '{"inputArray": [1,2,2,3,3,3]}' --cli-binary-format raw-in-base64-out old-output.json
# 查看旧版本的输出
cat old-output.json
# 预期输出:{"statusCode":200,"body":"{\"message\":\"处理成功\",\"uniqueArray\":[1,2,3]}"}
然后调用测试环境的新版本函数,拿到实际输出:
# 调用测试环境的函数,输入和旧版本完全一样
aws lambda invoke --function-name lambda-dependency-test-function-test --payload '{"inputArray": [1,2,2,3,3,3]}' --cli-binary-format raw-in-base64-out new-output.json
# 查看新版本的输出
cat new-output.json
# 预期和旧版本的输出完全一致
如果输出一致,说明基础的功能没问题;如果不一致,就得检查新版本lodash的uniq函数有没有变化。
3.4 集成测试
很多函数不是单独工作的,会和其他AWS服务交互,比如S3、DynamoDB、API Gateway。集成测试就是测升级依赖后,函数和这些服务的交互是否正常。
比如我们的函数如果是API Gateway的后端,当用户通过API Gateway调用函数时,能不能正常拿到结果?
先找到API Gateway的API ID,然后用curl调用API:
# 调用API Gateway,传入测试参数
curl -X POST https://<API_ID>.execute-api.<REGION>.amazonaws.com/Prod/hello --data '{"inputArray": [1,2,2,3,3,3]}'
# 预期返回和之前的函数输出一致
如果返回正常,说明集成没问题;如果返回500错误,就得检查函数和API Gateway的交互有没有问题,或者函数内部的依赖升级后有没有影响和其他服务的交互。
3.5 性能测试
升级依赖可能会影响函数的性能,比如新版本的依赖比旧版本慢,或者占用更多内存。性能测试就是测函数的响应时间、内存占用、并发能力是否符合要求。
我们可以用AWS Lambda的内置监控工具,或者用AWS CLI来获取函数的性能指标。
首先,先调用测试函数多次,产生足够的监控数据:
# 循环调用测试函数10次,产生监控数据
for i in {1..10}; do aws lambda invoke --function-name lambda-dependency-test-function-test --payload '{"inputArray": [1,2,2,3,3,3]}' --cli-binary-format raw-in-base64-out temp.json; done
然后获取函数的性能指标,比如平均响应时间:
# 获取过去5分钟内函数的平均响应时间(单位:毫秒)
aws cloudwatch get-metric-statistics --namespace AWS/Lambda --metric-name Duration --statistics Average --period 300 --start-time $(date -u -d '5 minutes ago' +%Y-%m-%dT%H:%M:%S) --end-time $(date -u +%Y-%m-%dT%H:%M:%S) --dimensions Name=FunctionName,Value=lambda-dependency-test-function-test
对比旧版本函数的平均响应时间,如果新版本的响应时间超过旧版本的10%,就得考虑是不是新版本的依赖导致的性能问题。
四、测试方案的应用场景、优缺点与注意事项
4.1 应用场景
这个方案适合所有用Node.js写AWS Lambda函数的开发者,不管是个人项目还是企业项目。特别是以下场景:
- 依赖有安全漏洞,必须升级的情况;
- 新版本依赖有重要功能,需要使用的情况;
- 旧版本依赖不再维护,必须升级的情况;
- 函数对业务影响大,升级后不能出问题的情况。
4.2 技术优缺点
优点:
- 测试流程清晰,从功能到集成再到性能,覆盖全面;
- 用SAM和AWS CLI,操作简单,不需要额外的复杂工具;
- 可以模拟真实环境,测试结果更可靠;
- 最小变更原则,容易定位问题。
缺点:
- 对于依赖很多的函数,测试时间会比较长;
- 性能测试需要产生足够的监控数据,操作稍微麻烦;
- 如果函数和很多服务集成,集成测试的工作量会比较大。
4.3 注意事项
- 测试环境的配置要和生产环境完全一致,包括运行时版本、内存配置、权限、环境变量等;
- 升级依赖前,要先看依赖的更新日志,了解新版本的变化,比如有没有不兼容的修改;
- 测试用例要覆盖所有可能的输入,包括边界情况(比如空数组、特殊字符等);
- 如果测试出问题,要及时回滚依赖版本,不要硬上;
- 测试完成后,要把测试过程和结果记录下来,方便以后参考。
五、文章总结
升级AWS Lambda的第三方依赖不是小事,一不小心就会导致函数出问题。一套完整的兼容性测试方案,能帮你避免很多麻烦。我们从测试的核心原则出发,结合Node.js的示例,详细讲解了功能测试、集成测试、性能测试的具体步骤,还分析了方案的应用场景、优缺点和注意事项。
总的来说,升级依赖前,一定要做好测试:先一个一个升级,再测功能,再测集成,最后测性能。只有所有测试都通过了,才能把新版本的函数部署到生产环境。这样既能用上新版本依赖的好处,又能保证函数的稳定性,不会影响业务。
评论
围绕“AWS Lambda依赖更新:第三方依赖升级时的函数兼容性测试方案”参与讨论