

# Maximizar a performance do SnapStart do Lambda
<a name="snapstart-best-practices"></a>

**Topics**
+ [Ajuste de performance](#snapstart-tuning)
+ [Práticas recomendadas de rede](#snapstart-networking)

## Ajuste de performance
<a name="snapstart-tuning"></a>

Para maximizar os benefícios do SnapStart, considere as recomendações de otimização de código a seguir para seu runtime.

**nota**  
O SnapStart funciona melhor quando usado com invocações de funções em escala. As funções que são invocadas com pouca frequência podem não ter as mesmas melhorias de performance.

### Java
<a name="snapstart-tuning-java"></a>

Para maximizar os benefícios do SnapStart, recomendamos carregar previamente as dependências e inicializar os recursos que contribuem para a latência de startup em seu código de inicialização, em vez de no manipulador de função. Isso remove a latência associada ao carregamento pesado de classes do caminho de invocação, otimizando a performance de startup com o SnapStart.

Se não for possível carregar previamente as dependências ou os recursos durante a inicialização, recomendamos carregá-los previamente com invocações fictícias. Para fazer isso, atualize o código do manipulador de função, conforme mostrado no exemplo a seguir da [função “pet store”](https://github.com/awslabs/aws-serverless-java-container/tree/main/samples/spring/pet-store) no repositório GitHub do AWS Labs.

```
private static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
  static {
      try {
          handler = SpringLambdaContainerHandler.getAwsProxyHandler(PetStoreSpringAppConfig.class);

          // Use the onStartup method of the handler to register the custom filter
          handler.onStartup(servletContext -> {
              FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
              registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
          });

          // Send a fake Amazon API Gateway request to the handler to load classes ahead of time
          ApiGatewayRequestIdentity identity = new ApiGatewayRequestIdentity();
          identity.setApiKey("foo");
          identity.setAccountId("foo");
          identity.setAccessKey("foo");

          AwsProxyRequestContext reqCtx = new AwsProxyRequestContext();
          reqCtx.setPath("/pets");
          reqCtx.setStage("default");
          reqCtx.setAuthorizer(null);
          reqCtx.setIdentity(identity);

          AwsProxyRequest req = new AwsProxyRequest();
          req.setHttpMethod("GET");
          req.setPath("/pets");
          req.setBody("");
          req.setRequestContext(reqCtx);

          Context ctx = new TestContext();
          handler.proxy(req, ctx);


      } catch (ContainerInitializationException e) {
          // if we fail here. We re-throw the exception to force another cold start
          e.printStackTrace();
          throw new RuntimeException("Could not initialize Spring framework", e);
      }
  }
```

### Python
<a name="snapstart-tuning-python"></a>

Para maximizar os benefícios do SnapStart, concentre-se na organização eficiente do código e no gerenciamento de recursos em suas funções do Python. Como diretriz geral, execute tarefas computacionais pesadas durante a [fase de inicialização](lambda-runtime-environment.md#runtimes-lifecycle-ib). Essa abordagem remove as operações demoradas do caminho de invocação, melhorando a performance geral da função. Para implementar essa estratégia de forma eficaz, recomendamos as seguintes práticas recomendadas:
+ Importe dependências fora do manipulador de função.
+ Crie instâncias `boto3` fora do manipulador.
+ Inicialize recursos ou configurações estáticas antes que o manipulador seja invocado.
+ Considere usar um [hook de runtime](snapstart-runtime-hooks-python.md) antes do snapshot para tarefas que consomem muitos recursos, como baixar arquivos externos, pré-carregar estruturas como o Django ou carregar modelos de machine learning.

**Example : otimizar a função Python para o SnapStart**  

```
# Import all dependencies outside of Lambda handler
from snapshot_restore_py import register_before_snapshot
import boto3
import pandas
import pydantic

# Create S3 and SSM clients outside of Lambda handler
s3_client = boto3.client("s3")

# Register the function to be called before snapshot
@register_before_snapshot
def download_llm_models():
    # Download an object from S3 and save to tmp
    # This files will persist in this snapshot
    with open('/tmp/FILE_NAME', 'wb') as f:
        s3_client.download_fileobj('amzn-s3-demo-bucket', 'OBJECT_NAME', f)
    ...

def lambda_handler(event, context):
    ...
```

### .NET
<a name="snapstart-tuning-dotnet"></a>

Para reduzir a compilação just-in-time (JIT) e o tempo de carregamento do assembly, considere invocar seu manipulador de funções de um [hook de runtime](snapstart-runtime-hooks-dotnet.md) `RegisterBeforeCheckpoint`. Devido à forma como funciona a compilação em camadas do .NET, você terá ótimos resultados invocando o manipulador várias vezes, conforme mostrado no exemplo a seguir.

**Importante**  
Certifique-se de que a invocação da função fictícia não produza efeitos colaterais indesejados, como iniciar transações comerciais.

**Example**  

```
public class Function
{
    public Function()
    {
        Amazon.Lambda.Core.SnapshotRestore.RegisterBeforeSnapshot(FunctionWarmup);
    }

    // Warmup method that calls the function handler before snapshot to warm up the .NET code and runtime.
    // This speeds up future cold starts after restoring from a snapshot.

    private async ValueTask FunctionWarmup()
    {
        var request = new APIGatewayProxyRequest
        {
            Path = "/heathcheck",
            HttpMethod = "GET"
        };

        for (var i = 0; i < 10; i++)
        {
            await FunctionHandler(request, null);
        }
    }

    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        //
        // Process HTTP request
        // 

        var response = new APIGatewayProxyResponse
        {
            StatusCode = 200
        };
        
        return await Task.FromResult(response);
    }
}
```

## Práticas recomendadas de rede
<a name="snapstart-networking"></a>

O estado das conexões que a função estabelece durante a fase de inicialização não é garantido quando o Lambda retoma a função de um snapshot. Na maioria dos casos, as conexões de rede que um SDK da AWS estabelece são retomadas automaticamente. Para outras conexões, recomendamos as práticas recomendadas a seguir.

**Restabelecer as conexões de rede**  
Sempre restabeleça as conexões de rede quando a função for retomada de um snapshot. Recomendamos restabelecer as conexões de rede no manipulador de função. Como alternativa, você pode usar um [hook de runtime](snapstart-runtime-hooks.md) after-restore.

**Não usar o nome do host como um identificador exclusivo do ambiente de execução**  
Recomendamos não usar o `hostname` para identificar o ambiente de execução como um nó ou um contêiner exclusivo em suas aplicações. Com o SnapStart, um único snapshot é usado como o estado inicial para diversos ambientes de execução. Todos os ambientes de execução retornam o mesmo valor `hostname` para `InetAddress.getLocalHost()` (Java), `socket.gethostname()` (Python) e `Dns.GetHostName()` (.NET). Para aplicações que requerem uma identidade de ambiente de execução ou um valor do `hostname` exclusivo, recomendamos gerar um ID exclusivo no manipulador de função. Como alternativa, use um [hook de runtime](snapstart-runtime-hooks.md) after-restore para gerar um ID exclusivo e, em seguida, use o ID exclusivo como identificador para o ambiente de execução.

**Evitar vincular conexões a portas de origem fixas**  
Recomendamos evitar vincular conexões de rede a portas de origem fixas. As conexões são restabelecidas quando uma função é retomada de um snapshot, e as conexões de rede vinculadas a uma porta de origem fixa podem apresentar falhas.

**Evitar usar o cache do DNS Java**  
As funções do Lambda já armazenam as respostas de DNS em cache. Se você usar outro cache DNS com o SnapStart, poderá experimentar tempos limite de conexão quando a função for retomada de um snapshot.

A classe `java.util.logging.Logger` pode habilitar indiretamente o cache do DNS da JVM. Para substituir as configurações padrão, defina [networkaddress.cache.ttl](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/net/InetAddress.html#inetaddress-caching-heading) como 0 antes de inicializar o `logger`. Exemplo:

```
public class MyHandler {
  // first set TTL property
  static{
   java.security.Security.setProperty("networkaddress.cache.ttl" , "0");
  }
 // then instantiate logger
  var logger = org.apache.logging.log4j.LogManager.getLogger(MyHandler.class);
}
```

Para evitar falhas `UnknownHostException` no runtime do Java 11, recomendamos definir `networkaddress.cache.negative.ttl` como 0. Em runtimes do Java 17 e versões posteriores, essa etapa não é necessária. Você pode definir essa propriedade para uma função do Lambda com a variável de ambiente `AWS_LAMBDA_JAVA_NETWORKADDRESS_CACHE_NEGATIVE_TTL=0`.

Desabilitar o cache do DNS da JVM não desabilita o cache do DNS gerenciado do Lambda.