AWS Lambda: The Impact of Reflection and Annotations on AWS Lambda's Performance 📎
Both Lambdas were deployed with the smallest possible amount of RAM (128 MB) and therefore, a fraction of the CPU.
The NoReflection
Lambda invoked the method greetings
directly:
public class NoReflection {
public String onEvent(Map<String, String> event) {
return this.greetings();
}
public String greetings(){
return "hello, no reflection " + System.currentTimeMillis();
}
}
The Reflection
AWS Lambda searched for the method greetings
annotated with:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface InvokeMe {}
...and then invoked the found method via reflection:
import java.lang.reflect.Method;
import java.util.Map;
public class Reflection {
public String onEvent(Map<String, String> event) {
var methods = Reflection.class.getMethods();
for (Method method : methods) {
if(method.getAnnotation(InvokeMe.class) != null){
try {
return (String) method.invoke(this);
} catch (Exception e) {
throw new IllegalStateException("Cannot invoke method",e);
}
}
}
return "no annotated method found";
}
@InvokeMe
public String greetings(){
return "hello, with reflection " + System.currentTimeMillis();
}
}
Spoiler: the direct invocation was faster:
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import software.constructs.Construct;
public class LambdaStack extends Stack {
static int memory = 128;
public LambdaStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
var noReflectionName = "airhacks_lambda_reflection_performance_boundary_NoReflection";
var noReflectionHandler = "airhacks.lambda.reflection.boundary.NoReflection::onEvent";
createFunction(noReflectionName, noReflectionHandler, memory);
var reflectionName = "airhacks_lambda_reflection_performance_boundary_Reflection";
var reflectionHandler = "airhacks.lambda.reflection.boundary.Reflection::onEvent";
createFunction(reflectionName, reflectionHandler, memory);
}
Function createFunction(String functionName,String functionHandler, int memory) {
return Function.Builder.create(this, functionName)
.runtime(Runtime.JAVA_11)
.code(Code.fromAsset("../target/function.jar"))
.handler(functionHandler)
.memorySize(memory)
.functionName(functionName)
.build();
}
}