簡體   English   中英

在 AWS Lambda 函數和 AWS API 網關無服務器 API 中使用的 Entity Framework Core 3.1.3 非常慢的第一個查詢

[英]Entity Framework Core 3.1.3 very slow first query used within AWS Lambda Function(s) and AWS API Gateway serverless API

我有一個 AWS API 網關,它代理了幾個 AWS Lambda 功能。 這些函數從 PostgreSQL 數據庫 (AWS Aurora PostgreSQL) 讀取和寫入。 我首先使用 Entity Framework Core Database 連接了數據訪問。 我有一個問題,幾分鍾后我第一次調用我的 API 和 Lambda function 執行第一個查詢通過 EF Core 到數據庫的第一個查詢只占用了 2 秒(只占用了 29 秒)。之后。 只需 200 毫秒。

我知道你在想什么,它是 Lambda 冷啟動。 好吧,我已經排除了這一點,因為如果我取出任何 EF Core 代碼,讓我的 function 返回一個虛擬響應,時間會下降到大約 4 秒響應,然后如果我再次調用 200 毫秒之后。

如果我檢查我的 function 的日志,我還可以看到延遲是在執行第一個 EF Core 查詢時,在此之前的其他事件發生得非常快。 請參閱下面的摘錄。

“找到測試客戶”是從數據庫中返回的第一個查詢數據。 請參閱下面的摘錄:

            using (var loyalty = new loyaltyContext())
            {
                var testArray = new string[]
                    {Customer.CustomerStateReasonCodes.Deceased, 
                        Customer.CustomerStateReasonCodes.Fraud};

                var dupeEmailCustomers = (from c in loyalty.ContactInformation
                        where c.ContactType == "EMAIL"
                        join cu in loyalty.Customer on c.CustomerInternalId equals cu.CustomerInternalId
                        where cu.Status == Customer.CustomerStates.Active
                        select c).AsNoTracking()
                    .Union(from c in loyalty.ContactInformation
                        where c.ContactType == "EMAIL"
                        join cu in loyalty.Customer on c.CustomerInternalId equals cu.CustomerInternalId
                        where cu.Status != Customer.CustomerStates.Active &&
                              testArray.Contains(cu.StatusReason)
                        select c).AsNoTracking();

                foreach (var cust in dupeEmailCustomers)
                {
                    context.Logger.LogLine($"Found test customer {JsonConvert.SerializeObject(cust)}");
                }
            }

這是 Lambda 執行日志:

在此處輸入圖像描述

注意從 9:26 秒到 9:44 秒的跳躍。 這就是到數據庫和返回的旅程。 現在,如果我之后再次調用相同的 API,它會發生在亞秒級。 我假設這是 EF Core。 我的問題是我不確定在 AWS Lambda 的架構中,我如何能夠減少第一個查詢延遲。 我已經為 AWS Lambda 啟用了預置並發,這應該使包含我的代碼的容器實例保持“溫暖”並准備好運行,但它沒有任何區別。

我懷疑這是因為 Lambda 代碼中唯一保持溫暖的部分是在 lambda 處理程序之外運行的東西。 EF Core 查詢僅發生在我的處理程序中,例如在我的:

    public APIGatewayProxyResponse PostCustomerProxyResponse(APIGatewayProxyRequest request, ILambdaContext context)

我相信通過配置並發保持“溫暖”的唯一代碼是構造函數中發生的代碼,例如

public Functions()
{
    _jSchema = new JSchemaGenerator().Generate(typeof(CustomerPayload));
    _systemsManagementClient = new AmazonSimpleSystemsManagementClient(RegionEndpoint.APSoutheast2);

    SecurityKey = PopulateParameter(ParameterPath + Integration + JWT + "/secret", true);
    Issuer = PopulateParameter(ParameterPath + Integration + JWT + "/issuer", false);
    ClaimName = PopulateParameter(ParameterPath + Integration + JWT + "/claim", false);
    ScpiUser = PopulateParameter(ParameterPath + Integration + SCPI + "/user", false);
    ScpiPassword = PopulateParameter(ParameterPath + Integration + SCPI + "/password", true);
    //DbUser = PopulateParameter(ParameterPath + ParameterPathDatabase + "/iamuser", false);
}

我嘗試向構造函數添加一個小型數據庫查詢,基本上是在實體框架中調用 ExecuteRawSQL() 從 PostgreSQL 中“選擇 1”,希望這可以算作第一個查詢,而我的實際 API 調用會更快,但這慘敗。 如果我在 Lambda 構造函數中有此“SELECT 1”代碼,則在嘗試調用該方法時,整個 API 實際上會超時。

我不知所措。 有人可以幫忙嗎? 我正要轉儲 EF Core 並返回到像 SqlKata 這樣的簡單查詢引擎,這將是一種恥辱,因為 EF Core 中的映射和實體使其非常適合使用。 如果有幫助,我將使用 Npgsql.EntityFrameworkCore.PostgreSQL 進行我的 EF Core 連接。

請試試這個...

var dupeEmailCustomers = ( from c in loyalty.ContactInformation
                        join cu in loyalty.Customer on c.CustomerInternalId equals cu.CustomerInternalId
                        where cu.Status == Customer.CustomerStates.Active
                                && c.ContactType == "EMAIL"
                        select c
                        ).AsNoTracking()
                    .Union(
                        from c in loyalty.ContactInformation
                        join cu in loyalty.Customer on c.CustomerInternalId equals cu.CustomerInternalId
                        where c.ContactType == "EMAIL"
                               && cu.Status != Customer.CustomerStates.Active 
                               && testArray.Contains(cu.StatusReason)
                        select c
                        ).AsNoTracking();

分別測試這些時間

    from c in loyalty.ContactInformation
    join cu in loyalty.Customer on c.CustomerInternalId equals cu.CustomerInternalId
    where cu.Status == Customer.CustomerStates.Active
            && c.ContactType == "EMAIL"
    select c

    from c in loyalty.ContactInformation
    join cu in loyalty.Customer on c.CustomerInternalId equals cu.CustomerInternalId
    where c.ContactType == "EMAIL"
           && cu.Status != Customer.CustomerStates.Active 
           && testArray.Contains(cu.StatusReason)
    select c

您可能缺少索引....嘗試在 ContactType 和 Status 上添加索引,並檢查您是否需要在 StatusReason 上添加索引

我遇到了這個確切的問題(因此把我帶到這里)。 我的 lambda 只分配了 128MB 並且需要 17 秒來構建 EF。 在將 memory 增加到 2048MB 時,相同的過程減少到 1 秒。 lambda 實際上只需要 168 MB,但當然,這比原來的 128MB 還要多。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM