node.js - 从子进程到 API 的请求导致 ECONNRESET

标签 node.js express concurrency parallel-processing axios

子进程部分可能相关或不相关,它可能只是并发/并行连接/请求的数量,但它甚至没有那么高(最大 50)。

我的架构是我的主应用程序按照 CRON 计划启动子进程。产生的每个进程都会通过一个独特的体育赛事来关注。 CRON 作业基于此事件的开始时间。如果事件时间相同,则每个子进程的生成间隔 1.2 秒。子进程的数量各不相同,但每次运行的数量不得超过 50。每个子进程都会创建与内部 API 的新连接。内部 API 只有 1 个进程正在运行,据我了解无法与其他机器一起扩展或 fork 子进程(正如建议的 here & here ),作为内部 API,依次调用外部 API,该 API 最初在多次请求后返回 ECONNRESET 。由于我不知道外部 API 的性质,因此我将自己的 API 放在它前面,以确保对外部的所有请求都通过单个连接进行。但是,现在我可以从内部 API 取回 ECONNRESET,即使只有 10 个子进程已启动。

与我的内部 API 的连接保持事件状态,以减少响应时间,并且使用 Axios 的最大套接字数为 1。架构图如下:

enter image description here

子进程按计划轮询内部 API,因此可能(可能)向其发出并行请求。但是,因为这些生成间隔至少为 1.2 秒,所以我认为这会降低并行请求​​的可能性。 Express的处理能力有什么区别parallel请求与处理能力 concurrent要求?据我所知,Express 可以毫无失败地处理 1000 个并发请求。

axios.js(工作人员)

module.exports = axios.create({
     baseURL: process.env.INTERNAL_API_ENDPOINT,
     httpAgent: new http.Agent({
         keepAlive: true,
         maxSockets: 1
     }),
     httpsAgent: new https.Agent({
         keepAlive: true,
         maxSockets: 1
     }),
     timeout: 60000, // 1 min timeout
     auth: {
         username: process.env.INTERNAL_API_USERNAME || 'user',
         password: process.env.INTERNAL_API_PASSWORD || 'pass'
     },
     headers: {
         Connection: 'keep-alive',
         'Content-Type': 'application/json',
         Accept: 'application/json'
     }
})

request.js

const API = require('./axios')

module.exports = async function(params) {
    try {
        return API.get('/api/events', { params })
    } catch(err) {
        throw err
    }
}

event.js(内部 API)

const { Router } = require('express')
const external = require('../client/betting')
const router = Router()

/**
 * GET /api/events
 */
router.get('/events', async (req, res, next) => {
    const { query } = req

    try {
        // Call to External API
        const response = await external.GetEvents(query)

        res.send(response.data)
    } catch (err) {
        next(err)
    }
})

module.exports = router

这个answer表明我的内部 API 可能因请求而过载,因此导致连接丢失。

这里的问题是什么?是我的并行请求导致了 ECONNRESET 吗?在这种情况下,我可以想到 3 种可能的补救措施(真正寻找最佳选择):

  1. 我可以按照建议在内部 API 端对请求进行排队 here
  2. 我可以重构我的代码以不启动子进程,因此只有 1 个进程以及随后 1 个与 API 的连接。这不是可取的,因为这是一个很大的架构变化,但如果这是最好的建议,那就可以了
  3. 有没有办法扩展我的内部 API,让子进程可以共享主进程的 TCP 连接,这样,与外部的连接就只有 1 个?类似于 cluster-client &那里提到的领导者/追随者模式

如果这些都不清楚,那么我可以在需要时提供更清晰的信息:)谢谢!

最佳答案

如果我正确地阅读你的问题,问题是对“外部 API”的严格限制,这是你的应用程序的瓶颈。

这很粗糙,因为您创建的事件可能超出外部 API 可以处理的数量!在某些时候,可以想象外部 api 无法跟上您的负载。

对于初始实现,我将探索您的第一种方法:

I could queue the requests on my internal API side as is suggested here

我会尽可能让内部 API 响应式,以便它从队列或事件流中读取。 enter image description here

在此架构中,您的工作人员将事件排入队列,然后继续。内部 API 监听队列上的事件,它可以一个接一个地拉取单个事件,并且每个事件都会向外部 API 发出请求,或者如果您开始压垮外部 API,您可以开始批量事件(即拉取 100 个事件或某个时间间隔)。

希望外部 API 有足够的能力来处理您的负载,并且您能够批量处理事件。但在某些时候,您的负载可能会超出外部 API 实际能够处理的负载。

关于node.js - 从子进程到 API 的请求导致 ECONNRESET,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60154601/

相关文章:

javascript - 使用 Typescript 或 NodeJS 发出 HTTP 请求

node.js - sendfile 有问题

python-3.x - 如何将对象与可迭代对象一起传递给 executor.map?

Java多线程文件系统树遍历

c++ - 与宽松的原子同步

javascript - 克尼克斯 : How to write ARRAY_AGG in having clause in knex?

node.js - 使用 npm 安装 bcrypt 时出错

node.js - 即使加载了 babel 库,我的 Node 服务器也无法识别 es6 语法

node.js - 当使用 Sequelize.js 创建另一条记录时,如何在数据库中自动创建一条新记录?

javascript - postman 工作但 fetch() 没有。为什么不?