在 Lambda 中使用 MySQL 时如何减少冷启动时间?

How to reduce the cold start time when using MySQL with Lambda?

我正在尝试使用 AWS Lambda、API 网关和 Amazon RDS (MySQL) 通过 Java 部署 REST API。下面是我的 Lambda class

import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.aaaa.beans.AccountingType;
import java.util.ArrayList;
import java.util.List;
import static java.util.Collections.list;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 *
 * @author User
 */
public class GetAllAccountTypesLambda {


   static final String DB_URL = "jdbc:mysql://************";
   static final String USER = "*****";
   static final String PASS = "*****";
   static final String QUERY = "SELECT * from accounting_type";
   static Connection conn = null;
   
   public GetAllAccountTypesLambda()
   {
      
      try {
         Class.forName("com.mysql.jdbc.Driver");  
         conn = DriverManager.getConnection(DB_URL, USER, PASS);
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   public APIGatewayProxyResponseEvent getAllAccountTypes(APIGatewayProxyResponseEvent request)
         throws JsonProcessingException, ClassNotFoundException {
      
      AccountingType acc = new AccountingType();
      ObjectMapper objectMapper = new ObjectMapper();
      List<AccountingType> list = new ArrayList<>();


      try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(QUERY);) {
         // Extract data from result set

         while (rs.next()) {
            // Retrieve by column name
            acc.setIdaccountingType(rs.getInt("idaccounting_Type"));
            acc.setType(rs.getString("type"));

            list.add(acc);
         }
      } catch (SQLException e) {
         e.printStackTrace();
      }

      String writeValueAsString = objectMapper.writeValueAsString(list);
      return new APIGatewayProxyResponseEvent().withStatusCode(200).withBody(writeValueAsString);
   }

}

我的 pom 文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.aaa</groupId>
    <artifactId>aaa-restapi</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <name>aaa REST API</name>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-lambda-java-core</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-lambda-java-events</artifactId>
            <version>3.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.12.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.4</version>
                <configuration></configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

现在,检查从 X Ray 跟踪的加载时间,我们通常称之为 冷启动

看来init进程需要时间。当进一步观察时,我注意到大部分时间都花在 MySQL Connector 尝试初始化上。如果我们删除它,这将在 500 毫秒到 600 毫秒内完成。

如何确保启动速度更快,可能以毫秒为单位?与 MySQL 连接器有关吗?

一般来说,数据库,尤其是 mysql,建立连接的速度很慢。为了提供帮助,AWS 提供了一个单独的 RDS Proxy 服务来维护一个 lambda 可以连接到的连接池。

但是,它只支持数量有限且没有详细记录的数据库 engine/version 组合,并且仅在某些地区。我相信支持 RDS MySQL 5.6 和 5.7,以及相应的 Aurora 版本(虽然不是 Aurora Serverless),但不支持 8 或任何 mariadb 版本。

不要盲目优化冷启动。如果您的 Lambda 将在经常使用的应用程序中使用(例如,每 10 秒超过 1 个请求),冷启动可能只占调用的 0.1%,而其他 99.9% 将由预热处理λ.

如果您的应用程序使用频率不高,您仍然可以通过例如每 5 分钟向 Lambda 发送一次 ping,迫使它保持温暖。

for one way to do it. A Cloud Guru did a more extended version of it (for a javascript Lambda): https://acloudguru.com/blog/engineering/how-to-keep-your-lambda-functions-warm

ping 确实增加了亚马逊对低使用率 Lambda 的间接成本,因为他们必须为它保留 X 小时的内存,而且每次 ping 只能向您收取几秒钟的实际运行时间。但显然,这是他们愿意承担的代价。