简体   繁体   English

需要帮助在节点中使用 express 识别 memory 泄漏

[英]Need help identifying memory leak using express in node

The problem问题

I have a Node application running in ECS that seems to be leaking memory, as the memory is constantly growing and dropping at every deploy.我有一个在 ECS 中运行的 Node 应用程序,它似乎正在泄漏 memory,因为 memory 在每次部署时都在不断增长和下降。

I made a heapdump and imported it in Chrome DevTools, trying to make some sense of it.我做了一个堆转储并将其导入 Chrome DevTools,试图理解它。

Heapdump堆转储

There seems to be several 100 000 strings looking like this.似乎有几个 100 000 个字符串看起来像这样。 The syntax looks like the express res.cookie syntax I have in my middleware, and also of course in the login route.语法看起来像我在中间件中使用的 express res.cookie 语法,当然在登录路由中也是如此。 The middleware I have that is checking if the user has a valid cookie, and refreshing it if valid.我拥有的中间件正在检查用户是否有有效的 cookie,如果有效则刷新它。 Since it would be running more often I think it makes sense if the middleware is the culprit, but I still can't make any sense of why it is leaking.由于它会更频繁地运行,我认为如果中间件是罪魁祸首是有道理的,但我仍然无法理解它为什么泄漏。 对象

The possible culprit?可能的罪魁祸首? Middleware.ts中间件.ts

import * as jwt from 'jsonwebtoken';
import issueJWT from 'utils/functions/IssueToken';
import { getRepository, getConnection } from 'typeorm';
import User from 'entity/organization/User';
import { ApiResult } from 'utils/classes/ApiResult';

interface ICookie {
    name: string;
    payload: string;
}

interface ICookieRouterConnections {
    routeName: string;
    cookieName: string;
}

const authenticate = async (req, res, next) => {
    const userRepository = getRepository(User);
    const { authorization, cookie } = req.headers;
    let requestToken: ICookie = { name: '', payload: '' };

    // These are the tokens that can be issued with their corresponding routes
    const portalCookieNames: ICookieRouterConnections[] = [
        {
            routeName: 'admin',
            cookieName: process.env.JWT_ADMIN,
        },
        {
            routeName: 'customer',
            cookieName: process.env.JWT_CUSTOMER,
        },
    ];

    // Find the router the user is trying to access
    const requestedRouterName = req.path
        .split('/')
        .splice(1, 1)
        .shift();

    function throwError(statusObj: { message: string; code: string; statusCode: number }) {
        const apiResult = new ApiResult();
        apiResult.addError({
            message: statusObj.message,
            code: statusObj.code,
            request: req,
        });
        res.status(statusObj.statusCode);
        res.send(apiResult);
    }

    // Gets the value of a cookie by the cookie name
    const getCookie = (cookieName: string): ICookie => {
        const returnObject = {
            name: cookieName,
            payload: cookie
                .split(`${cookieName}=`)
                .pop()
                .split(';')
                .shift(),
        };
        return returnObject;
    };

    const routerCookieName = portalCookieNames.find(obj => obj.routeName === requestedRouterName).cookieName;

    if (!authorization && !cookie) {
        throwError({ message: 'Token not provided', statusCode: 401, code: 'tokenNotProvided' });
        return;
    }

    // If there is authorization header, use that
    if (authorization) {
        requestToken.name = routerCookieName;
        requestToken.payload = authorization.replace('Bearer ', '');
    } else {
        // If not use the JWT from the cookie based on which router the user is trying to access
        requestToken = getCookie(routerCookieName);
    }

    if (requestToken) {
        // Validate the token
        jwt.verify(requestToken.payload, process.env.APP_SECRET, async (err, decoded) => {
            if (err) {
                throwError({ message: err, statusCode: 401, code: 'internalError' });
            } else {
                const user = await userRepository.findOne({ where: { id: decoded.userId } });

                if (!user.isDeactivated) {
                    req.user = user;
                    // Issue a new token if the cookie provided was valid
                    res.cookie(requestToken.name, issueJWT(user), {
                        httpOnly: false,
                        expires: new Date(Date.now() + 24 * 3600000),
                        domain: process.env.COOKIE_DOMAIN,
                    });
                    next();
                }
            }
        });
    } else {
        throwError({ message: 'Invalid token', statusCode: 401, code: 'invalidTokenProvided' });
    }
};

export default authenticate;


I think Bergi pointed me in the right direction.我认为 Bergi 为我指明了正确的方向。

This was a package "express-session" that was loaded in the router.这是一个加载在路由器中的 package“快速会话”。 Seems like the default memory store is leaky and shouldn't be used in production.似乎默认的 memory 存储有泄漏,不应在生产中使用。

From the npmjs repository从 npmjs 存储库

Warning The default server-side session storage, MemoryStore, is purposely not designed for a production environment.警告 默认的服务器端 session 存储 MemoryStore 故意不是为生产环境设计的。 It will leak memory under most conditions, does not scale past a single process, and is meant for debugging and developing.在大多数情况下,它会泄漏 memory,不会扩展到单个进程,并且用于调试和开发。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM