Azure功能执行速度极慢且不一致

时间:2017-07-03 05:18:56

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

我正在编写一些Azure函数脚本,该脚本可以从内部数据库读取/写入内容,并在网页中显示相关信息。

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

  1. Azure函数脚本有时需要10秒到1分钟以上才能连接到SQL数据库。
  2. 有时脚本会在几毫秒内运行,有时需要3分钟以上才能完全运行脚本。
  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

    如何解决这个缓慢的问题?

1 个答案:

答案 0 :(得分:8)

我们已经注意到了node.js函数。经过大量研究和测试后,我们发现了:

  1. 功能应用程序会进入“冷”状态。五分钟不活动后的状态。当它们走出寒冷状态时,你可以期待长达10秒的节点JavaScript编译/转换成.Net代码,这样它们就可以在更大的Function引擎中本地运行。请注意,我说&#34;功能应用&#34;以上而不仅仅是&#34;功能&#34;

  2. 即使它出现在&#34; hot&#34;状态(即<5分钟空闲时间),有时功能将花费过多的时间来加载外部库

  3. 此次性能影响最大的罪魁祸首是拥有许多小文件的大型外部库。

  4. 那么你可以做些什么来缓解这种情况呢?以下是我们按复杂程度所做的事情:

    1. 设置定时器功能,该功能在不到5分钟的时间范围内执行。我们每四分钟运行一个简单的计时器,需要0到10毫秒之间的任何时间,你可以做一些数学计算,看看这是一种非常便宜的方法,可以使你的功能应用程序保持在热状态。

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

    3. 使用REST API代替SDK,意味着需要零外部库。最大的问题是生成Authorization标头,Azure之间没有关于如何形成Auth标头的标准,并且在大多数情况下,这部分文档几乎没有涵盖,特别是对于node.js.我已经考虑过仅为node.js代码创建一个github存储库,该代码生成各种Azure Auth令牌。

    4. 将您的功能移植到C#(是的,我对此选项不满意 - 我想为我们的产品提供所有JavaScript / TypeScript平台)。仍然,删除交叉编译/转换/无论它应该显着加速。我现在将一个最复杂的函数移植到C#上,以进一步测试这个理论。

    5. 转向应用服务计划似乎与Azure功能的价值相违背。我想要微软处理的无限规模和每次执行成本。应用服务计划迫使我再次考虑CPU和内存以及应用容量。

    6. 我发布的MSDN forums thread请求就我们的问题提供反馈。

相关问题