Azure Function执行速度极慢且不一致 [英] Azure Function execution speed is extremely slow and inconsistent

查看:112
本文介绍了Azure Function执行速度极慢且不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一些Azure函数脚本,该脚本可读取内部数据库或从内部数据库读取数据并将其显示在网页中.

I am writing few Azure Functions script that reads and write from/to an internal database and display relevant information into a webpage.

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

I noticed extreme slowness or even timeout in the web UI when loading the web page which calls the Azure Function script. After further investigation, I realized that the following:

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

这是我的Azure函数脚本:

Here is my Azure Function script:

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();
});

};

如何解决此缓慢问题?

推荐答案

我们在node.js函数中也注意到了这一点.经过大量的研究和测试,我们发现了以下内容:

We have noticed this as well with our node.js Functions. After a lot of research and testing here is what we've found:

  1. Function Apps闲置五分钟后进入冷"状态.当它们脱离冷态时,您可以期望最多10秒钟的时间来完成将节点JavaScript编译/转换为.Net代码的过程,以便它们可以在更大的Function引擎中本地运行.请注意,我在上面说的是"Function App",而不仅仅是"Function"

  1. Function Apps go into a "cold" state after five minutes of inactivity. When they come out of the cold state you can expect up to 10 seconds of what seems to be compilation/transpilation of node JavaScript into .Net code so they can run natively inside the greater Function engine. Note that I said "Function App" above and not merely "Function"

即使它处于热"状态(即小于5分钟的空闲时间),在某些情况下,函数也会花费过多的时间来加载外部库

Even if it's in a "hot" state (i.e. < 5 minutes idle time), there are occasions that the Function will take an excessive amount of time to load external libraries

导致性能下降的最大原因是较大的外部库,其中包含许多小文件.

The biggest culprit in this performance hit is larger external libraries with many small files.

那么您可以采取什么措施来缓解这种情况?以下是我们按照复杂度顺序进行的操作:

So what can you do to alleviate this? Here is what we have done in order of complexity:

  1. 设置计时器功能,该功能在少于5分钟的时间范围内执行.我们每隔四分钟运行一个简单的计时器,耗时在0ms到10ms之间,您可以进行数学计算,这是使Function App保持高温状态的一种非常廉价的方法.

  1. Set up a timer Function that executes in a time frame less than 5 minutes. We run a simple timer every four minutes that takes anywhere between 0ms and 10ms and you can do the math to see that's a VERY cheap way to keep your Function App in a hot state.

使用 Functions-Pack 软件包合并所有外部库成一个文件.重新编译或转译此Function或发生任何不可思议的事情时,它变得更快,因为它不需要查找数十或数百个文件.

Use the Functions-Pack package to consolidate all of your external libraries into a single file. When the Function is re-compiled or transpiled or whatever magic happens back there it gets much faster as it doesn't have to seek dozens or hundreds of files.

使用REST API代替SDK,意味着需要零个外部库.最大的问题是生成Authorization标头,Azure中没有关于如何形成Auth标头的标准,并且在大多数情况下,尤其是使用node.js时,几乎没有涵盖这部分文档.我曾考虑过要纯粹为生成各种Azure Auth令牌的node.js代码启动github存储库.

Using REST API's instead of SDK's means zero external libraries are required. The big issue with that is generating the Authorization headers, there is no standard across Azure for how to form an Auth header and this part of their docs is barely covered in most cases, especially with node.js. I've thought about starting a github repository purely for node.js code that generates various Azure Auth tokens.

将您的函数移植到C#(是的,我也不满意此选项-我想要我们产品的所有JavaScript/TypeScript平台).尽管如此,删除交叉编译/转译/所有文件,应该可以大大加快速度.我现在将我们最复杂的函数之一移植到C#上,以进一步检验该理论.

Port your Functions to C# (yeah, I'm not happy with this option either - I want an all JavaScript/TypeScript platform for our product). Still, remove the cross-compilation/transpilation/whatever and it's supposed to speed up dramatically. I'm porting one of our most complex Functions over to C# now to further test this theory.

移至App Service计划似乎与Azure Functions的价值背道而驰.我想要Microsoft处理的无限规模和每次执行的费用. App Service计划迫使我重新考虑CPU和内存以及App Capacity.

Moving to an App Service Plan seems counter-intuitive to the value of Azure Functions. I want unlimited scale that Microsoft handles and a per-execution cost. App Service plan forces me to think about CPU's and memory and App Capacity again.

这是

Here is an MSDN forums thread that I posted requesting feedback on our issues.

这篇关于Azure Function执行速度极慢且不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆