大炮JavaScript内存不足

时间:2019-03-10 12:25:07

标签: node.js heap load-testing v8 artillery

将到达率从10更改为100后,最老的测试无法运行。

Artillery: 1.6.0-27 Artillery Pro: not installed Node.js: v10.15.0 OS: darwin/x64
:test $ artillery run -o report.json artillery.yml
Started phase 0, duration: 10s @ 10:01:42(+0000) 2019-03-10
.
<--- Last few GCs --->

[62621:0x102803200] 9478 ms: Mark-sweep 1392.4 (1401.5) -> 1392.3 (1401.5) MB, 20.1 / 0.0 ms (average mu = 0.439, current mu = 0.002)
     

要求在旧空间中使用最后的GC       [62621:0x102803200] 9498 ms:标记扫描1392.3(1401.5)-> 1392.3(1401.5)MB,20.6 / 0.0 ms(平均mu = 0.277,当前mu = 0.001)   请求在旧空间中使用最后的GC

<--- JS stacktrace --->

==== JS stack trace =========================================

0: ExitFrame [pc: 0x38a6205dbe3d]

Security context: 0x1da57481e6e1
1: byteLength [0x1da5274066f1] [buffer.js:526] [bytecode=0x1da597d26509 offset=126](this=0x1da5d7c5fbc1 <JSFunction
     

缓冲区(sfi = 0x1da573a14251),, string = 0x1da597e082b9,encoding = 0x1da5d92026f1)       2:参数适配器框架:1-> 2       3:setContentLength(aka setContentLength)[0x1da5201841e9] [/ Users //。nv ...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: 0x10003b125 node::Abort() [/Users//.nvm/versions/node/v10.15.0/bin/node]
2: 0x10003b32f node::OnFatalError(char const*, char const*) [/Users//.nvm/versions/node/v10.15.0/bin/node]
3: 0x1001a8e85 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char
     

const *,bool)[/Users//.nvm/versions/node/v10.15.0/bin/node]       4:0x1005742a2 v8 ::内部::堆:: FatalProcessOutOfMemory(char const *)[/Users//.nvm/versions/node/v10.15.0/bin/node]       5:0x10057d7a4 v8 :: internal :: Heap :: AllocateRawWithRetryOrFail(int,v8 :: internal :: AllocationSpace,v8 :: internal :: AllocationAlignment)   [/Users//..nvm/versions/node/v10.15.0/bin/node]       6:0x10054f055 v8 :: internal :: Factory :: NewRawOneByteString(int,v8 :: internal :: PretenureFlag)   [/Users//..nvm/versions/node/v10.15.0/bin/node]       7:0x1006811a8 v8 :: internal :: String :: SlowFlatten(v8 :: internal :: Handlev8 :: internal :: ConsString,   v8 :: internal :: PretenureFlag)   [/Users//..nvm/versions/node/v10.15.0/bin/node]       8:0x1001c6c1d v8 :: String :: Utf8Length()const [/Users//.nvm/versions/node/v10.15.0/bin/node]       9:0x10004eaac node :: Buffer ::((匿名命名空间):: ByteLengthUtf8(v8 :: FunctionCallbackInfov8 :: Value const&)   [/Users//..nvm/versions/node/v10.15.0/bin/node]       10:0x10023170f v8 :: internal :: FunctionCallbackArguments :: Call(v8 :: internal :: CallHandlerInfo *)   [/Users//..nvm/versions/node/v10.15.0/bin/node]       11:0x100230c51 v8 :: internal :: MaybeHandlev8 :: internal :: Object v8 :: internal ::((   名称空间):: HandleApiCallHelper(v8 :: internal :: Isolate *,   v8 :: internal :: Handlev8 :: internal :: HeapObject,   v8 :: internal :: Handlev8 :: internal :: HeapObject,   v8 :: internal :: Handlev8 :: internal :: FunctionTemplateInfo,   v8 :: internal :: Handlev8 :: internal :: Object,   v8 :: internal :: BuiltinArguments)   [/Users//..nvm/versions/node/v10.15.0/bin/node]       12:0x1002302f0 v8 :: internal :: Builtin_Impl_HandleApiCall(v8 :: internal :: BuiltinArguments,   v8 :: internal :: Isolate *)[/Users//.nvm/versions/node/v10.15.0/bin/node]       13:0x38a6205dbe3d       中止陷阱:6

我的测试看起来像这样。

.yml

config:
  target: "<URL_REMOVED"
  processor: "./getData.js"
  phases:
    - duration: 10
      arrivalRate: 100
scenarios:
  - flow:
      - function: "getData"
      - post:
          url: "/api/v2/auth"
          json:
            productId: "56729b6b77c82288f746c0cf"
          capture:
            json: "$.data.token"
            as: "token"
      - post:
          url: "/api/v2/sessions"
          headers:
            Authorization: 'Bearer {{token}}'
          json:
            productId: "56729b6b77c82288f746c0cf"
            jobId: "{{jobId}}"
          capture:
            json: "$.data.session._id"
            as: "sessionId"
      - post:
          url: "/api/v2/sessions/{{sessionId}}/document"
          headers:
            Authorization: "Bearer {{token}}"
          json:
            side: "front"
            payload: "{{frontDocument}}"
      - get:
          url: "/api/v2/sessions/{{sessionId}}/metrics/front"
          headers:
            Authorization: "Bearer {{token}}"
      - get:
          url: "/api/v2/sessions/{{sessionId}}/classification"
          headers:
            Authorization: "Bearer {{token}}"
      - get:
          url: "/api/v2/sessions/{{sessionId}}/end"
          headers:
            Authorization: "Bearer {{token}}"

getData.js

'use strict';
var faker = require('faker');
var FRONT_ID = require("./resources/id/front.json");

module.exports = {
    getData
};

function getData(userContext, events, done) {

    let jobId = faker.random.uuid()
    userContext.vars.jobId = jobId;
    userContext.vars.frontDocument = FRONT_ID.base64;
    return done();
}

1 个答案:

答案 0 :(得分:0)

您的运行火炮的节点nodejs内存不足。其默认限制约为1.4G。

* nix上的大炮可能是从/usr/bin/artillery开始使用npm install -g安装的。

该文件的第一行很有可能是

#!/usr/bin/env node

尝试将其更改为

#!/usr/bin/env node  --max-old-space-size=8192

获得8G的堆空间。但是,不要抓住运行火炮的机器所拥有的物理RAM来获得更多的堆空间,否则您将不堪重负。阅读:how to increase nodejs default memory?

编辑:问题仍然存在:为什么导致您的artillery进程爆满。看起来它在崩溃前已经运行了大约9秒钟。可能是您的被测系统无法以100的到达率跟上您放置在系统上的负载。这可能是因为火炮不断在内存中创建和排队并接收请求,并且它们没有完成,所以它们不要被释放。您的性能日志会为您提供任何提示吗?

负载测试的要点是查找被测系统的断点。您不会通过在船上装十个沙袋,然后说“凉爽”,然后将100个沙袋倒入其中来测试船。船会沉下去。为什么要以这种方式测试服务器?您所学到的是它的容量在10到100之间。取而代之的是,逐个沙袋增加负载,直到系统开始崩溃为止。

这就是为什么火炮(乃至大多数负载测试系统)拥有通向ramp up the load的方式的原因。

为什么不尝试这样的事情?

- duration: 120
  arrivalRate: 10
  name: "Two minutes, ten arrivals/sec"
- duration: 600
  arrivalRate: 10
  rampTo: 100
  name: "Ten minutes, gradual ramp to 100 arrivals/sec"

一旦您知道系统跌落的速度,就可以根据需要进行更详细的测试。并且,如有必要,您可以尝试重新编写代码以使其更快。

此外,通常10秒的测试还不够长,无法收集有价值的数据。您想知道系统在稳定的高负载下的容量。