javascript - Azure Function 执行速度极慢且不一致

标签 javascript azure azure-sql-database azure-functions

我正在编写一些 Azure Functions 脚本,用于从内部数据库读取和写入内部数据库,并将相关信息显示到网页中。

我注意到加载调用 Azure Function 脚本的网页时 Web UI 极其缓慢甚至超时。经过进一步调查,我意识到以下几点:

  1. Azure Function 脚本有时需要 10 秒到 1 分钟以上才能连接到 SQL 数据库。
  2. 有时脚本会在几毫秒内运行,有时需要 3 分钟以上才能完全运行脚本。

这是我的 Azure 函数脚本:

module.exports = function(context, req) {

context.log("Function Started: " + new Date());

// Import package
const sql = require('mssql');
var _ = require('underscore-node');
var moment = require('moment');
var Promise = require('promise');
// Create a configuration object for our Azure SQL connection parameters
var config = {
    server: "***", // Use your SQL server name
    database: "***", // Database to connect to
    user: "***", // Use your username
    password: "***", // Use your password
    port: ***,
    // Since we're on Windows Azure, we need to set the following options
    options: {
        encrypt: true
    },
    multipleStatements: true,
    parseJSON: true
};
var flagDefinitionId = null;

if (req.query.Id == null || req.query.Id == "" || req.query.Id.length == 0) {
    context.res = {
        // status: 200, /* Defaults to 200 */
        body: "No have flagDefinitionId "
    };
    context.done();
    // return;
}

var listTicketsFlag = [];

flagDefinitionId = req.query.Id;
sql.close();
var DBSchema = "b8akjsms2_st.";
sql.connect(config).then(function() {
    context.log("SQL Connected: " + new Date());

    var getAllEventTicketGoToMarket = new Promise(function(resolve, reject) {
        var queryGetEvent = ";WITH EventLog1 AS(" +
            " SELECT MD1, max([DateTime]) as LTime from " + DBSchema + "EventLog" +
            " where ([Event] = 'Ticket_Go_To_Market' OR [Event] = 'Acknowledge_Timeout')" +
            " group by MD1 )" +
            " SELECT * from ( SELECT EV.MD1 , EV.MD2," +
            " (SELECT COUNT(*) from " + DBSchema + "EventLog where MD1 = EV.MD1 and [Event] = 'Market_Ticket_Clear') as TotalClear" +
            " FROM " + DBSchema + "[Ticket] T" +
            " JOIN (SELECT E.* from " + DBSchema + "EventLog E join EventLog1 E1 on E.MD1 = E1.MD1 and E.[DateTime] = E1.LTime) EV ON T.Id = EV.MD1" +
            " WHERE T.IsInMarket = 1 and EV.MD2 <> ''" +
            " AND T.Id NOT IN (Select TicketId from " + DBSchema + "TicketFlag where FlagDefinitionId = " + flagDefinitionId + ")" +
            " ) R where R.TotalClear > 0";
        context.log("get event log - Ticket_Go_To_Market" + queryGetEvent);
        new sql.Request().query(queryGetEvent, (err, result) => {
            context.log("this is --------> EventLog " + result.recordset.length);
            resolve(result.recordset);
        });
    });

    Promise.all([getAllEventTicketGoToMarket]).then(function(values) {
        var ticketGoToMarket = values[0];
        context.log("this is --------> values: " + values[0].length + " ==+++++==== " + JSON.stringify(values[0], null, 2));

        if (ticketGoToMarket.length != 0) {
            listTicketsFlag = _.filter(ticketGoToMarket, function(num) {
                var countSP = num.MD2.split(',');
                // context.log("countSP =====> " + countSP.length + "num.TotalClear ==>" + num.TotalClear)
                if (num.TotalClear > countSP.length) {
                    return num.MD1;
                }
            });
            // context.log("listTicketsFlag =====> " + JSON.stringify(listTicketsFlag, null, 2));
        }
        insertTicketFlag();

    });

    function insertTicketFlag() {
        context.log("this is ----- ===> Insert:  " + listTicketsFlag);
        // insert
        var insertTicketFlagPromise = new Promise(function(resolve, reject) {

            context.log("listTicketFlag ----- ===> " + listTicketsFlag.length);

            if (listTicketsFlag.length == 0) {
                context.log(" -------------------- No have ticket need FLAG");
                resolve();

            } else {

                // insert new data to TicketFlag FlagTickets
                var listTicketInsert = ""; //convertArrayToSQLString(listTicketsFlag, true, flagDefinitionId);
                var len = listTicketsFlag.length - 1;
                for (var j = 0; j <= len; j++) {
                    listTicketInsert += '(\'' + listTicketsFlag[j] + '\', \'' + flagDefinitionId + '\')';
                    if (j != len) {
                        listTicketInsert += ",";
                    }
                }
                context.log("HERE : " + listTicketInsert);

                var insertQuery = 'Insert into  ' + DBSchema + '[TicketFlag] (TicketId, FlagDefinitionId) values ' + listTicketInsert + '';

                context.log("this is --------> InsertQuery" + insertQuery);

                // return;

                context.log("read data of FlagRule");
                new sql.Request().query(insertQuery, (err, result) => {
                    context.log("this is --------> insertQuery");
                    resolve(result);

                });
            }
        });

        Promise.all([insertTicketFlagPromise]).then(function(values) {
            context.log("DONE ALL");
            sql.close();
            context.done();
        })
    }

}).catch(function(err) {
    console.log(err);
    context.done();
});

};

enter image description here

enter image description here

如何解决这个缓慢问题?

最佳答案

我们在 Node.js 函数中也注意到了这一点。经过大量研究和测试,我们发现:

  1. 功能应用在五分钟不活动后会进入“冷”状态。当它们脱离冷状态时,您可以期待长达 10 秒的时间,将节点 JavaScript 编译/转换为 .Net 代码,以便它们可以在更大的 Function 引擎内 native 运行。请注意,我上面说的是“函数应用”,而不仅仅是“函数”

  2. 即使处于“热”状态(即 < 5 分钟空闲时间),该函数有时也会花费过多时间来加载外部库

  3. 造成性能下降的最大原因是包含许多小文件的较大外部库。

那么你可以采取什么措施来缓解这种情况呢?以下是我们按复杂程度排列的工作:

  1. 设置一个定时器函数,在小于 5 分钟的时间范围内执行。我们每四分钟运行一个简单的计时器,所需时间在 0 毫秒到 10 毫秒之间,您可以计算一下,发现这是使您的函数应用程序保持在热状态的一种非常便宜的方法。

  2. 使用Functions-Pack包将所有外部库合并到一个文件中。当函数被重新编译或转译或发生任何魔法时,它会变得更快,因为它不必寻找数十或数百个文件。

  3. 使用 REST API 而不是 SDK 意味着需要零个外部库。最大的问题是生成授权 header ,Azure 中没有关于如何形成 Auth header 的标准,并且在大多数情况下,他们的文档的这一部分几乎没有涵盖,尤其是使用 Node.js。我考虑过创建一个纯粹用于生成各种 Azure Auth token 的 Node.js 代码的 github 存储库。

  4. 将您的函数移植到 C#(是的,我对这个选项也不满意 - 我希望我们的产品有一个全 JavaScript/TypeScript 平台)。不过,删除交叉编译/转译/其他任何东西,它应该会显着加快速度。我现在将最复杂的函数之一移植到 C# 中,以进一步测试这一理论。

  5. 转向应用服务计划似乎与 Azure Functions 的值(value)背道而驰。我想要 Microsoft 处理的无限规模和每次执行成本。应用服务计划迫使我再次考虑 CPU、内存和应用容量。

这是一个MSDN forums thread我发布请求对我们的问题提供反馈。

关于javascript - Azure Function 执行速度极慢且不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44878247/

相关文章:

azure - Application Insights 数据采样

azure - 从 Asp.Net MVC azure 网站运行 WebJob

entity-framework - 是否可以将 Entity Framework 与 Windows Azure 开发存储服务一起使用?

javascript - 在 jQuery 中,prepend() 如何作用于 children() 函数?

javascript - 如何立即开始 setInterval 循环?

azure - 如何更改 Azure SDK 2.5 中每个服务配置的诊断存储位置

来自 SSIS 包的 Azure SQL Active Directory 交互式身份验证

javascript - 如何从firebase存储中获取所有下载网址?

javascript - 我可以在 Javascript 中集成音乐键吗

Azure数据工厂: copying data from CosmosDB to SQL Database fails with "range-indexed" error