使用PM2实现高效的应用监控与管理

微信搜索“好朋友乐平”关注公众号。

在这里插入图片描述


1. pm2

PM2 是一个流行的进程管理器,用于 Node.js 应用程序。它支持应用程序的负载均衡、自动重启、日志管理、监控以及多环境管理等功能。PM2让开发者能够以守护进程的方式运行和管理 Node.js 应用,即使在应用崩溃或服务器重启后也能自动重启应用。这使得 PM2非常适合在生产环境中部署 Node.js 应用。除此之外,PM2还支持应用的零停机更新,以及对 Docker 容器的支持。

2. 诞生背景

PM2 的诞生背景主要是为了解决 Node.js 应用程序在生产环境中的运维问题。在 PM2出现之前,Node.js 开发者经常面临如何有效管理和维持应用稳定运行的挑战,特别是在应对应用崩溃、服务器重启或是负载均衡等方面。

PM2的主要目标是提供一个简单而强大的工具,帮助开发者和系统管理员在生产环境中管理和维护 Node.js 应用。它解决的关键问题包括:

  1. 自动重启: 如果 Node.js 应用崩溃或由于某种原因停止,PM2可以自动重启应用,确保服务的持续可用性。
  2. 负载均衡: PM2支持集群模式,能够启动多个应用实例,并在它们之间自动分配负载,提高应用的可伸缩性和可用性。
  3. 无停机更新: PM2允许开发者在不停止当前服务的情况下,更新 Node.js 应用到新的版本,这对于需要24/7运行的服务来说非常重要。
  4. 日志管理: PM2提供了日志管理的功能,使得跟踪和调试生产环境中的应用更为便捷。
  5. 监控: PM2包含了一个监控系统,可以实时查看应用的 CPU 和内存使用情况,帮助开发者优化应用性能。

2. 安装

执行以下命令来全局安装 PM2。全局安装意味着你可以在任何地方运行 PM2命令。

npm install pm2 -g

这条命令会将 PM2安装到你的系统上,-g 参数表示全局安装,这样你就可以在任何目录下使用 PM2命令。

安装完成后,你可以运行以下命令来检查 PM2是否正确安装:

pm2 --version

3. 常用命令

命令描述使用示例及参数
start启动应用pm2 start app.js
pm2 start app.js -i 4 --name myApp
pm2 start app.js --watch
stop停止应用pm2 stop app.js
pm2 stop 0
pm2 stop all
restart重启应用pm2 restart app.js
pm2 restart all
delete删除应用pm2 delete app.js
pm2 delete 0
pm2 delete all
list列出所有应用pm2 list
monit监控应用pm2 monit
logs查看应用日志pm2 logs
pm2 logs app.js
pm2 logs --lines 100
save保存当前应用列表pm2 save
reload重载应用pm2 reload app.js
pm2 reload all
scale调整集群模式下的实例数量pm2 scale app +1
pm2 scale app 4
describe查看应用详细信息pm2 describe 0
update更新 PM2守护进程pm2 update
status查看应用状态pm2 status
flush清空所有日志文件pm2 flush
startup创建开机自启动脚本pm2 startup
unstartup删除开机自启动脚本pm2 unstartup

4. 配置文件

PM2的配置文件通常被称为ecosystem.config.js,这是一个 JavaScript 文件,允许你配置和管理应用程序的多个方面。通过使用配置文件,你可以轻松地指定环境变量、日志文件路径、实例数量等,并且可以一次性启动多个应用。下面详细介绍如何使用 PM2配置文件。

基本结构

PM2的ecosystem.config.js文件基本结构如下:

module.exports = {apps: [{name: "app1", // 应用程序名称script: "./app.js", // 主脚本路径args: "arg1 arg2", // 传递给脚本的参数instances: 4, // 应用实例数autorestart: true, // 自动重启watch: false, // 监控文件变动max_memory_restart: "1G", // 内存超过1G 重启env: {// 环境变量NODE_ENV: "development",},env_production: {// 生产环境变量NODE_ENV: "production",},},{name: "app2",script: "./app2.js",// 其他配置...},],
};

主要字段解释

  • apps: 一个数组,包含了你要运行的应用的配置对象。
  • name: 应用程序的名称。
  • script: 应用程序的启动脚本或文件。
  • args: 传递给脚本的参数。
  • instances: 启动应用实例的数量。对于无状态的应用,可以设置为max以根据 CPU 核心数量来启动最大实例数。
  • autorestart: 如果应用崩溃或者停止,是否自动重启。
  • watch: 是否启用文件监控和自动重启。
  • max_memory_restart: 当应用超过指定内存量时自动重启。
  • env: 在这个对象中,你可以指定传递给应用的环境变量。这些环境变量在所有环境下都会加载。
  • env_production, env_development: 你可以为不同的环境指定不同的环境变量。

使用配置文件

  1. 启动应用: 使用配置文件启动应用时,运行如下命令:

    pm2 start ecosystem.config.js
    
  2. 指定环境: 如果你有为不同环境定义的变量,可以在启动时指定:

    pm2 start ecosystem.config.js --env production
    

    这将使用env_production中定义的环境变量。

  3. 管理应用: 一旦应用启动,你可以使用 PM2的标准命令来管理它们,例如pm2 stop, pm2 restart, 和pm2 delete

配置文件为应用部署提供了强大而灵活的管理方式,特别是当你需要部署多个应用或需要为应用指定特定的环境变量和配置时。通过精心设计的配置文件,你可以确保应用的部署更加一致和可预测。

5. CLI 实现配置文件效果

如果你不使用配置文件,而是选择直接使用 PM2的 CLI 命令来实现上面提到的功能,可以通过在命令行中添加特定的选项和参数来完成。下面是如何通过 CLI 命令实现配置文件中提到的一些主要功能:

  1. 启动应用并传递参数:

    pm2 start app.js --name "app1" -- arg1=value1 arg2=value2
    

    这里--name "app1"设定了应用的名称,-- arg1 arg2向应用传递了参数。

  2. 指定实例数量:

    pm2 start app.js -i 4
    

    该命令启动了4个应用实例。如果你想要根据 CPU 核心数量来启动最大实例数,可以使用-i max

  3. 启用自动重启:
    自动重启是 PM2的默认行为,无需特别指定。

  4. 启用文件监控:

    pm2 start app.js --watch
    

    这会监控应用目录中文件的变动,并在变动时自动重启应用。

  5. 限制内存重启:

    pm2 start app.js --max-memory-restart 1G
    

    当应用消耗的内存超过1GB 时,PM2将自动重启应用。

  6. 设置环境变量:
    你可以在启动命令中直接设置环境变量:

    NODE_ENV=development pm2 start app.js
    

    或者,为了同时设置多个环境变量,可以使用:

    pm2 start app.js --env NODE_ENV=development,env1=13,env2=32
    
  7. 为生产环境设置环境变量:
    对于生产环境,你可以这样设置:

    NODE_ENV=production pm2 start app.js
    

使用 CLI 命令直接设置这些选项的好处是快速简便,特别是对于一次性或临时的任务。但对于更复杂的部署,或者当你需要在多个环境中维护一致的配置时,使用配置文件将更为有效和易于管理。

6. 监控

PM2提供了一个内置的监控工具,允许你实时查看运行在 PM2下的应用的性能指标,如 CPU 和内存使用情况。这个监控工具可以帮助你了解应用的运行状况,及时发现潜在的问题。

使用 PM2监控命令行工具

  1. 启动监控控制台:
    要查看实时的监控数据,可以在命令行中使用以下命令:
    pm2 monit
    
    这会打开一个交互式的监控控制台,其中展示了所有由 PM2管理的进程的 CPU 和内存使用情况。

使用 PM2 Web 界面

PM2还提供了一个 Web 界面,称为 PM2 Plus,用于更高级的监控和管理功能,包括远程监控和日志管理。不过,这需要在 PM2 Plus 网站上注册并设置 keymetrics 代理。

  1. PM2 Plus:
    • 你可以访问PM2 Plus来获取更多关于这个服务的信息。
    • 它允许你监控关键指标,设置告警,查看日志,和进行实时的问题排查。

自定义指标

PM2还允许你定义自己的指标来监控。你可以在你的应用中集成 PM2的 API 来发送自定义指标,这样就可以在 PM2的监控工具中查看这些指标了。

7. 其它

7.1 负载均衡下的会话管理

在使用 PM2的集群模式运行多个实例的场景下,确保会话(session)一致性是一个重要的考虑点。由于每个实例都是独立运行的,直接在内存中存储会话信息可能会导致会话不一致的问题,因为用户的后续请求可能被路由到不同的实例上,而不同的实例之间无法共享内存中的会话信息。

为了解决这个问题,通常的做法是使用一个中央存储来存储会话信息,这样不同的实例可以共享这些信息。以下是一些常见的解决方案:

  1. 使用 Redis 存储会话: Redis 是一种常用的解决方案,它提供了快速的数据读写并支持数据持久化。使用 Redis 作为会话存储,可以确保不同的实例能够访问和更新同一份会话数据。

  2. 使用数据库存储会话: 另一种常见的方法是将会话存储在数据库中,如 MongoDB 或 MySQL 等。这样可以确保会话信息的一致性,但可能比使用内存存储或 Redis 的性能稍低。

  3. 使用其他共享存储方案: 根据应用的具体需求,还可以考虑使用其他类型的共享存储方案,如 Memcached、Etcd 等。

对于 Node.js 应用,如果你使用 Express 框架,可以利用express-session配合 Redis 等存储的中间件来实现会话的共享。例如,使用connect-redis中间件将会话存储在 Redis 中:

const session = require("express-session");
const RedisStore = require("connect-redis")(session);app.use(session({store: new RedisStore({// Redis 服务器配置host: "localhost",port: 6379,}),secret: "your_secret",resave: false,saveUninitialized: false,})
);

使用这种方式,无论用户的请求被路由到哪个实例,应用都能访问到同一份会话信息,从而避免了会话不一致的问题。确保你的会话存储方案是可伸缩的,并且可以处理你的应用负载。

7.2 异常重启处理

当 PM2重启应用时,确保应用的当前状态完成后再继续,以及在异常重启下恢复重启前的状态,需要在应用层面做一些策略设计。这通常涉及到优雅的关闭处理和持久化状态管理。

优雅的关闭处理
  1. 捕获关闭信号:在 Node.js 应用中,你可以监听如SIGINTSIGTERM这样的信号,这样当 PM2尝试重启应用时,你的代码可以捕获这些信号并执行清理逻辑。

    process.on("SIGINT", function () {console.log("Received SIGINT. Performing graceful shutdown.");gracefulShutdown();
    });function gracefulShutdown() {// 在这里执行清理操作,如关闭数据库连接、完成正在处理的请求等
    }
    
  2. 完成正在处理的请求:在收到关闭信号后,应用应该停止接受新的请求,但同时确保当前正在处理的请求完成。这可能涉及到跟踪所有活跃的请求并等待它们结束。

恢复状态
  1. 状态持久化:为了在重启后恢复状态,应用的关键状态需要持久化,例如存储在数据库或文件系统中。这样,在应用重启后,可以从这些持久化的存储中恢复状态。

  2. 启动时的状态恢复逻辑:应用启动时应该包含逻辑来检查并恢复之前的状态。这可能包括读取数据库中的数据,或从文件系统中恢复信息等。

PM2特定策略
  • 进程守护:PM2会守护你的应用进程,如果应用崩溃或非正常退出,它会自动重启应用。这是通过配置 PM2的restart策略实现的。

  • 零停机重启:使用 PM2的reloadgracefulReload命令可以实现零停机重启,这对于不间断服务的应用特别有用。这些命令会等待新的实例启动并接收连接后,再停止旧的实例。

7.3 SIGINT 信号超时处理

const express = require("express");
const app = express();
const server = app.listen(3000, () =>console.log("Server started on port 3000")
);let activeConnections = new Set();app.get("/", (req, res) => {// 模拟长时间运行的请求const requestId = Date.now();activeConnections.add(requestId);console.log(`Request ${requestId} started`);setTimeout(() => {res.send("Hello World");activeConnections.delete(requestId);console.log(`Request ${requestId} finished`);}, 10000); // 假设请求处理需要10秒
});process.on("SIGINT", () => {console.log("Received SIGINT. Graceful shutdown start.");// 停止服务器接受新的连接server.close(() => {console.log("Server closed. No new connections are accepted.");});// 等待所有活动请求完成const checkActiveConnections = () => {if (activeConnections.size > 0) {console.log(`Waiting for ${activeConnections.size} active connections to finish.`);setTimeout(checkActiveConnections, 1000);} else {console.log("All connections finished. Exiting now.");process.exit(0);}};checkActiveConnections();
});

捕获SIGINT信号后,进程确实有机会执行清理逻辑,但这并不意味着 PM2无法再去主动 kill 进程。当你的应用捕获SIGINT信号并进入清理阶段时,PM2会等待一段时间(默认是1600毫秒),这个时间是可配置的。如果应用在这段时间内没有退出,PM2会发送SIGKILL信号来强制终止进程。

这意味着你的清理逻辑需要在 PM2的超时时间内完成,以确保它能够正常执行并让进程优雅地退出。如果清理逻辑需要的时间超过了 PM2的超时阈值,你可以调整 PM2的配置来增加这个超时时间。

例如,你可以在启动应用时通过--kill-timeout参数来设置这个超时时间:

pm2 start app.js --kill-timeout 3000

这里,--kill-timeout 3000表示 PM2将等待3000毫秒(3秒)给应用足够的时间来处理清理逻辑。如果应用在3秒内没有退出,PM2将使用SIGKILL来强制终止应用。

这个机制确保了你的应用有机会在 PM2重启或停止它之前完成必要的清理工作,同时也保留了 PM2在应用无法正确响应终止信号时强制关闭它的能力。


微信搜索“好朋友乐平”关注公众号。

github原文地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/700951.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot+vue的精准扶贫管理系统(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

中国农业无人机行业市场现状分析与投资前景预测研究报告

全版价格:壹捌零零 报告版本:下单后会更新至最新版本 交货时间:1-2天 第一章农业无人机行业发展综述 第一节农业无人机行业定义及分类 一、农业无人机行业的定义 农业无人机是一种无人驾驶的飞行器来帮助优化农业经营,增加作…

[rust] 11 所有权

文章目录 一 背景二 Stack 和 Heap2.1 Stack2.2 Heap2.3 性能区别2.4 所有权和堆栈 三 所有权原则3.1 变量作用域3.2 String 类型示例 四 变量绑定背后的数据交互4.1 所有权转移4.1.1 基本类型: 拷贝, 不转移所有权4.1.2 分配在 Heap 的类型: 转移所有权 4.2 Clone(深拷贝)4.3 …

C++基础知识(六:继承)

首先我们应该知道C的三大特性就是封装、继承和多态。 此篇文章将详细的讲解继承的作用和使用方法。 继承 一个类,继承另一个已有的类,创建的过程 父类(基类)派生出子类(派生类)的过程 继承提高了代码的复用性 【1】继承的格式 class 类名:父类名 {}; 【…

SpringMVC 学习(三)之 @RequestMapping 注解

目录 1 RequestMapping 注解介绍 2 RequestMapping 注解的位置 3 RequestMapping 注解的 value 属性 4 RequestMapping 注解的 method 属性 5 RequestMapping 注解的 params 属性(了解) 6 RequestMapping 注解的 headers 属性(了解&…

Linux安装jdk、tomcat、MySQL离线安装与启动

一、JDK和Tomcat的安装 1.JDK安装 直接上传到Linux服务器的,上传jdk、tomcat安装包 解压JDK安装包 //解压jdk tar -zxvf jdk-8u151-linux-x64.tar.gz 置环境变量(JAVA_HOME和PATH) vim /etc/profile 在文件末尾添加以下内容: //java environment expo…

osg qt5.15 osg3.6.3 osgEarth3.1 编译爬山

Demo演示:Qt5.15.2OSG3.6.3OsgEarth3.1的QtCreator下的msvc2019x64版本 osgQt编译 步骤一:下载解压 步骤二:CMake配置 步骤三:CMake配置添加osg环境 步骤四:CMake配置添加Qt环境 步骤五:CMake修改CMakeLis…

R语言入门笔记2.6

描述统计 分类数据与顺序数据的图表展示 为了下面代码便于看出颜色参数所对应的值,在这里先集中介绍, col1是黑色,2是粉红,3是绿色,4是天蓝,5是浅蓝,6是紫红,7是黄色,…

Android studio 下的APK打包失败问题解决办法

嗨,各位小伙伴们,我是你们的好朋友咕噜铁蛋!作为移动应用开发者,在使用Android Studio进行APK打包时,有时候可能会遇到各种问题导致打包失败,这给我们的开发工作带来了一定的挑战。今天,我将和大…

欧瑞康真空泵650S干泵SV630罗茨泵WAU251-2001安装调试使用说明

欧瑞康真空泵650S干泵SV630罗茨泵WAU251-2001安装调试使用说明

mysql和sql server 中如何创建和管理用户

阅读本文之前请参阅----MySQL 数据库安装教程详解(linux系统和windows系统) 在MySQL和SQL Server中创建和管理用户的过程有所不同。下面分别介绍这两种数据库系统中用户管理的常见步骤。 MySQL 创建用户 在MySQL中创建用户的语法通常如下…

杰理701N可视化SDK之LED的配置和代码浅析

杰理701N可视化SDK LED的配置 LED硬件配置LED状态配置LED状态情景配置LED在SDK中相关代码 杰理可视化工具中可以配置LED的硬件配置和LED状态配置, 在可视化工具中的LED配置选项中设置 LED硬件配置 硬件配置可设置LED名, 推LED使用的IO口以及LED的点亮方式 SDK发布的标准原理…

02|Using filesort文件排序原理详解

文件排序方式 ● 单路排序&#xff1a;是一次性取出满足条件行的所有字段&#xff0c;然后在sort buffer中进行排序&#xff1b;用trace工具可以看到sort_mode信息里显示< sort_key, additional_fields >或者< sort_key, packed_additional_fields > ● 双路排序&a…

MySQL知识点总结(五)——锁

MySQL知识点总结&#xff08;五&#xff09;——锁 锁分类表锁 & 行锁如何添加表锁&#xff1f;如何添加行锁&#xff1f; 读锁 & 写锁行锁 & 间隙锁&#xff08;gap lock&#xff09;& 临键锁&#xff08;next-key lock&#xff09; 加锁机制分析可重复读隔离…

MATLAB:数组与矩阵

2.1 数组运算 数组运算时MATLAB计算的基础。由于MATLAB面向对象的特性&#xff0c;这种数值数组称为MATLAN最重要的一种内建数据类型&#xff0c;而数组运算就是定义这种数据结果的方法。 2.1.1 数组的创建和操作 在MATLAB中一般使用方括号“[]”、逗号“,”、空格和分号“;…

数据结构与算法相关题解20240225

数据结构与算法相关题解20240225 一、58. 最后一个单词的长度二、48. 旋转图像三、69. x 的平方根四、50. Pow(x, n) 一、58. 最后一个单词的长度 简单 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度…

445. 两数相加 II(Java)

目录 题目描述&#xff1a;输入&#xff1a;输出&#xff1a;代码实现&#xff1a; 题目描述&#xff1a; 给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外&am…

CSP-202209-3-防疫大数据

CSP-202209-3-防疫大数据 解题思路 一、数据结构定义 对于大模拟的题&#xff0c;合适的数据结构选择十分重要&#xff0c;正确的数据结构选择能够有效的提升解题效率 // 漫游消息结构体 struct RoamingData {int date, user, region; };vector<RoamingData> roamin…

汇编反外挂

在软件保护领域&#xff0c;尤其是游戏保护中&#xff0c;反外挂是一个重要的议题。外挂通常指的是一种第三方软件&#xff0c;它可以修改游戏数据、操作游戏内存或提供其他作弊功能&#xff0c;从而给玩家带来不公平的优势。为了打击外挂&#xff0c;游戏开发者会采取一系列措…

web安全学习笔记【16】——信息打点(6)

信息打点-语言框架&开发组件&FastJson&Shiro&Log4j&SpringBoot等[1] #知识点&#xff1a; 1、业务资产-应用类型分类 2、Web单域名获取-接口查询 3、Web子域名获取-解析枚举 4、Web架构资产-平台指纹识别 ------------------------------------ 1、开源-C…