使用Node和Node-gyp的AWS Lambda上的奇怪“内存”行为

我有一个用NodeJS编写的AWS Lambda,调用过程非常简单

NODEJS – > NodeModule(CPP) – > Extern C函数,这个设置是用node-gyp编译的。 您可以通过https://drive.google.com/open?id=0B-2d-CuY5fkwS3lwdE96R1V6NEk查看完整的代码

CPP节点模块调用C中的一个运行循环的函数。 并在C函数范围内增加两个variables,而在C代码的主要范围内增加另一个variables。

当你在本地运行这个代码。 循环递增,两个variables都达到了11,正如预料的那样,你有多less运行它。 但是,当您在AWS Lambda中运行相同的代码时,每次调用都会有某种“内存”。 一般范围内未被重置的variables正在增加,为11,22,33等倍数

重复一次,这从来没有发生在本地,两个variables总是在11.你可以通过运行1.构build节点gyp干净configuration构build2.节点app.js(本地运行)

Index.js适用于AWS Lambda

我真的不能解释这种行为? 是否有某种上下文或Lambda提供的某种“内存”或caching?

我已经为此做了一个开放的API网关。 (随意刷新,看到“记忆”在行动)。

https://koj2yva6z9.execute-api.us-east-1.amazonaws.com/dev/testLambdaCache

这种行为有时不一致,有时计数重置。 或者,您可以通过上传新的AWS lambda代码进行重置。

任何关于这个奇怪的行为的想法是赞赏。

app.js(用于本地testing)

var addon = require('./build/Release/addon'); console.log(addon.testCache()); console.log(" addon method completed"); 

index.js(在lambda中使用)

 console.log('Loading function'); exports.handler = (event, context, callback) => { var addon = require('./build/Release/addon'); var returnvalue=addon.testCache(); console.log(returnvalue); console.log(" addon method completed"); callback(null, "success::"+returnvalue); } 

base.cc(C代码包装)

 #include <node.h> #include <iostream> #include <stdlib.h> #include<string> #include<cstring> using namespace std; extern "C" char* testCache(); namespace demo { using v8::FunctionCallbackInfo; using v8::HandleScope; using v8::Isolate; using v8::Local; using v8::Object; using v8::String; using v8::Value; using v8::Exception; void Method(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); cout << "C++ method started\n"; char *returnStrings=NULL; returnStrings= testCache(); args.GetReturnValue().Set(String::NewFromUtf8(isolate, returnStrings )); } void init(Local<Object> exports) { NODE_SET_METHOD(exports, "testCache", Method); } NODE_MODULE(addon, init) } 

decoder.c(运行循环的c代码)

 int tmpCounter=0; char* testCache() { int counter=0; printf("Local counter --> %d Global Counter --> %d\n",counter,tmpCounter); for(int i=0;i <10; i++) { counter = counter +1; tmpCounter = tmpCounter +1; //sleep(1); } printf("Local counter --> %d Global Counter --> %d\n",counter,tmpCounter); counter=counter+1; tmpCounter=tmpCounter+1; char strCounter[100]; char strTmpCounter[100]; snprintf(strCounter, 16, "%d", counter); snprintf(strTmpCounter, 16, "%d", tmpCounter); char *returnString=NULL; returnString=malloc(1000); strcat(returnString, "Count:"); strcat(returnString, strCounter); strcat(returnString, " TmpCount:"); strcat(returnString, strTmpCounter); strcat(returnString, "\0"); printf("%s\n",returnString); fflush(stdout); return returnString; } 

是否有某种上下文或Lambda提供的某种“内存”或caching?

我不会说它是“可用的”,因为它是可预测的或一致的,因为你不应该围绕它来devise,但是是的,有容器的重用。

要看到这个行动:

创build一个uuid或随机数或类似的东西,并将其存储在您的处理程序之外的全局variables中。 然后,在处理程序中,logging它。 您会看到,相同的进程或进程组(可能由uuid标识)可能会(但不一定)处理后续紧接在一起的请求。

假设你的函数完成了,并且有一段时间过去了,那么你再次调用它。 Lambda可能会重新创build一个新的容器[…]

但是,如果您没有更改代码,并且没有太多时间,Lambda可能会重用以前的容器。 这为双方提供了一些性能优势:Lambda可以跳过nodejs语言初始化,并且可以在代码中跳过初始化。 如果沙盒被重用,那么上次写入到/ tmp的文件将仍然存在。

https://aws.amazon.com/blogs/compute/container-reuse-in-lambda/

所有调用strcattestCache都是UB,因为malloc没有内存。

改变它使用calloc

 returnString=calloc(1, 1000); 

或用sprintf更改第一个

 sprintf(returnString, "Count:"); 

另外strcat(returnString, "\0"); 没用

最后总是检查malloc和朋友返回的值,例如

 if (returnString != NULL) { // OK, MEMORY ALLOCATED } else { // ERROR }