本文介绍单实例多并发的背景信息、优势、适用场景以及设置多并发的影响。

背景信息

函数计算按实例占用时长计费。假设访问数据库需要10秒,那么当并发的3个请求分别在3个实例内被处理后,3个实例总的执行时长是30秒。如果能让这3个请求在同一个实例内并发处理,这样实例的占用时间为10秒。为了帮助您节省实例资源费用,函数计算支持单实例多并发功能。函数计算允许您为函数设置一个实例并发度(InstanceConcurrency),即单个函数实例可以同时处理多少个请求。下面示意图可以看出单并发和多并发的区别。 instanceconcurrency

假设同时有3个请求需要处理,当实例并发度设置为1时,函数计算需要创建3个实例来处理这3个请求,每个实例分别处理1个请求;当实例并发度设置为10时(即1个实例可以同时处理10个请求),函数计算只需要创建1个实例就能处理这3个请求。

说明 默认情况下,函数的实例并发度为1,也就是一个实例内同时只会处理一个请求。当您设置了实例并发度大于1后,函数计算在弹性伸缩时,会尽可能地充分利用一个实例的并发度后再创建新的实例。

单实例多并发优势

  • 减少执行时长,节省费用。

    例如,偏I/O的函数可以在一个实例内并发处理,减少实例数从而减少总的执行时长。

  • 请求之间可以共享状态。

    多个请求可以在一个实例内共用数据库连接池,从而减少和数据库之间的连接数。

  • 降低冷启动概率。

    由于多个请求可以在一个实例内处理,创建新实例的次数会变少,冷启动概率降低。

  • 减少占用VPC IP

    在相同负载下,单实例多并发可以降低总的实例数,从而减少VPC IP的占用。

单实例多并发应用场景

并不是所有的函数都适合开启单实例多并发功能。该功能的适用性如下。
场景 适用性 理由
函数中有较多时间在等待下游服务的响应 适用 等待响应一般不消耗资源,在一个实例内并发处理可以节省费用。
函数中有共享状态且不能并发访问 不适用 例如全局变量,多请求并发执行修改共享状态可能会导致错误。
单个请求的执行要消耗大量CPU及内存资源 不适用 多请求并发执行会造成资源争抢,可能会导致内存不足(OOM)或者延时增加。

设置单实例多并发的影响

设置了单实例多并发(InstanceConcurrency > 1)之后,与单并发(InstanceConcurrency = 1)有以下几个方面的区别:

  • 计费
    • 单实例单并发
      函数实例在同一时间只能处理1个请求,1个请求处理完了再处理下一个请求。计费时长从处理第一个请求开始,到最后一个请求结束为止。 instanceconcurrency=1
    • 单实例多并发

      多个请求在一个实例并发处理时,以实例的实际占用时间作为计费的执行时长,即从第一个请求开始,到最后一个请求结束期间的时长。

      instanceconcurrency

    更多计费详情请参见计费说明

  • 并发度流控

    函数计算一个地域(Region)中按量实例数的上限默认值为300,一个地域可以同时处理的最大请求数为“300 × InstanceConcurrency”。例如,设置InstanceConcurrency = 10时,则一个地域最多允许同时处理3000个并发请求。当并发请求数超过函数计算可以处理的最大请求数时,会收到流控错误(ResourceExhausted)提示。

    说明 如果您想要扩大一个地域的按量实例数上限,请 联系我们
  • 日志
    • 在单并发模式下,在调用函数时指定HTTP头X-Fc-Log-Type: Tail,函数计算会在响应头X-Fc-Log-Result中包含本次调用所产生的函数日志。在多并发模式下,由于多个请求并发执行,无法获取某个特定请求的日志,响应头中不再包含本次调用的函数日志。
    • 针对Node.js Runtime,原来的日志方式是使用console.info()函数,该方式会把当前请求的Request ID包含在日志内容中。当多请求在同一个实例并发处理时,当前请求可能有很多个,继续使用console.info()打印日志会导致Request ID错乱,Request ID都会变成req 2。打印日志示例如下。
      2019-11-06T14:23:37.587Z req1 [info] logger begin
      2019-11-06T14:23:37.587Z req1 [info] ctxlogger begin
      2019-11-06T14:23:37.587Z req2 [info] logger begin
      2019-11-06T14:23:37.587Z req2 [info] ctxlogger begin
      2019-11-06T14:23:40.587Z req1 [info] ctxlogger end
      2019-11-06T14:23:40.587Z req2 [info] ctxlogger end
      2019-11-06T14:23:37.587Z req2 [info] logger end
      2019-11-06T14:23:37.587Z req2 [info] logger end                    
      此时应该使用 context.logger.info()函数打印日志,该方式仍保留了请求的独立Resquest ID。代码示例如下。
      exports.handler = (event, context, callback) => {
          console.info('logger begin');
          context.logger.info('ctxlogger begin');
      
          setTimeout(function() {
              context.logger.info('ctxlogger end');
              console.info('logger end');
              callback(null, 'hello world');
          }, 3000);
      };                   
  • 错误处理

    多个请求在一个实例并发处理时,由于一个请求处理不当导致进程退出或者崩溃,会导致正在并发处理的其他请求也收到错误信息。这要求您在编写函数时,尽量捕获请求级别的异常,不影响其他请求。Node.js代码示例如下。

    exports.handler = (event, context, callback) => {
        try {
            JSON.parse(event);
        } catch (ex) {
            callback(ex);
        }
    
        callback(null, 'hello world');
    };                    
  • 共享变量

    多个请求在一个实例并发处理时,同时修改一个共享的变量,可能会导致错误。这要求您在编写函数时,对于非线程安全的变量修改要进行互斥保护。Java代码示例如下。

    public class App implements StreamRequestHandler
    {
        private static int counter = 0;
    
        @Override
        public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
            synchronized (this) {
                counter = counter + 1;
            }
            outputStream.write(new String("hello world").getBytes());
        }
    }                    
  • 监控指标
    设置函数的实例并发度后,在相同的负载下,可以在控制台的实例数监控图中看到函数的实例数有明显地减少。 实例数据监控图

使用限制

限制项 描述
支持的Runtime
  • Node.js Runtime
  • Java Runtime
  • Custom Runtime
实例并发度取值范围 1~100
调用响应中的函数日志(X-Fc-Log-Result) InstanceConcurrency > 1时不支持

更多信息

设置单实例并发度