为 Fastify Node js 实现负载保护

Implementing load protection for Fastify Node js

故事:

作为一名开发者,我想为 Fastify 实现负载保护,以防止服务器负载崩溃。

上下文:

对严重的性能问题进行根本原因分析可能需要时间。对于实时部署的项目,值得为服务器或服务添加过载保护。过载保护的想法是监控事件循环延迟(除其他事项外),如果超过阈值则以“503 Service Unavailable”响应。这允许负载均衡器故障转移到其他实例,或者在最坏的情况下意味着用户将不得不刷新。 under-pressure 模块可以为 Fastify 提供最小的开销。

问题:

under-pressure 插件的主要目的是保护服务器免受高负载的影响。我使用 autocannon 创建了一个假负载,服务器突然开始抛出这个错误:

<--- JS stacktrace --->

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

    0: ExitFrame [pc: 00007FF7D342A9AC]
Security context: 0x01b3e02408d1 <JSObject>
    1: _write [000001EBE7CBA7B1] [_stream_transform.js:~169] [pc=000002737CBBD07D](this=0x02fe03573099 <LineStream map = 00000149AA79E209>,0x00f819d83789 <Uint8Array map = 000002F9BBE3F279>,0x00c0496035d9 <String[#6]: buffer>,0x02fe03575639 <JSBoundFunction (BoundTargetFunction 000003C5D37BC781)>)        
    2: ondata [000002FE03577FC9] [_stream_readable.js:~712]...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 00007FF7D28A363F napi_wrap+128063
 2: 00007FF7D2842836 v8::base::CPU::has_sse+35142
 3: 00007FF7D28434F6 v8::base::CPU::has_sse+38406
 4: 00007FF7D3059F4E v8::Isolate::ReportExternalAllocationLimitReached+94
 5: 00007FF7D3042021 v8::SharedArrayBuffer::Externalize+833
 6: 00007FF7D2F0E57C v8::internal::Heap::EphemeronKeyWriteBarrierFromCode+1436
 7: 00007FF7D2F197D0 v8::internal::Heap::ProtectUnprotectedMemoryChunks+1312
 8: 00007FF7D2F162F4 v8::internal::Heap::PageFlagsAreConsistent+3204
 9: 00007FF7D2F0BB13 v8::internal::Heap::CollectGarbage+1283
10: 00007FF7D2F0A184 v8::internal::Heap::AddRetainedMap+2452
11: 00007FF7D2F31E1F v8::internal::Factory::NewRawTwoByteString+95
12: 00007FF7D2F349CB v8::internal::Factory::NewStringFromUtf8+187
13: 00007FF7D305681A v8::String::NewFromUtf8+298
14: 00007FF7D27A9ABF node::tracing::TraceEventHelper::SetAgent+40751
15: 00007FF7D285A46D v8::internal::Malloced::operator delete+1661
16: 00007FF7D342A9AC v8::internal::SetupIsolateDelegate::SetupHeap+45852
17: 000002737CBBD07D

期望值:

非常适合防止负载的 fastify 插件正在破坏 fastify 服务器,需要其他插件或其他方式的帮助来实现负载保护

交叉发布到 Github:https://github.com/fastify/under-pressure/issues/64

正如问题中所指出的,使用的配置禁用了保护。

无论如何,我认为你应该评估它是否是外部API。

如果它是外部的,fastify-rate-limit 将是限制每个租户可以对您的端点执行的每秒请求的理想选择。 这对业务也有好处,因为您可以为每个客户提供不同的阈值。

正如您所指出的,内部 API 可以使用 under-pressure,根据我的经验,最佳配置是:

const v8 = require('v8')

console.log(v8.getHeapStatistics())

fastify.register(require('under-pressure'), {
  maxEventLoopDelay: 200, // are you using sync method?!
  maxHeapUsedBytes: v8.getHeapStatistics().heap_size_limit,
  maxRssBytes: v8.getHeapStatistics().total_available_size
})

这样,插件将适应使用所有 default 或自定义内存设置:

node --max-old-space-size=4096 server.js

请注意,Nodejs 12 使堆 space 适应其运行的系统,如 official post

中所述

This update will configure the JavaScript heap size based on available memory instead of using defaults that were set by V8 for use with browsers. In previous releases, unless configured, V8 defaulted to limiting the max heap size to 700 MB or 1400MB on 32 and 64-bit platforms respectively. Configuring the heap size based on available memory ensures that Node.js does not try to use more memory than is available and terminating when its memory is exhausted. This is particularly useful when processing large data-sets. As before, it will still be possible to set — max-old-space-size to use a different limit if the default is not appropriate for your application.