文档章节

记nodejs在pm2下使用log4js cluster模式的日志打印丢失问题

唱不完的离歌
 唱不完的离歌
发布于 2018/11/23 15:40
字数 1682
阅读 868
收藏 1

我使用pm2的cluster集群模式管理node服务,使用log4js打印日志。最近公司业务量上升,与此同时问题订单也随之增多。但多次在排查异常订单时找不到订单的正常日志,在基本排除程序本身问题后我将目光投在了日志打印插件log4js身上。

1:这是我目前的log4js的配置

log4js.configure({
    appenders: {
        out: { type: 'stdout' },
        info: {
            type: 'dateFile',
            filename: 'info',
            pattern: '-yyyy-MM-dd.log',
            layout: {
                type: 'pattern',
                pattern: '%d{yyyy-MM-ddThh:mm:ss.SSSO} %p %c - [%m]'
            }
        },
      
    },
    categories: {
        default: { appenders: ['out','info'], level: 'all' },
    },  
    pm2: true,
    disableClustering: true
});

我在网上也找到了很多博客,看到很多人都是这么写的。这么写可以解决cluster集群模式下只有一个进程输出的问题。但是在翻了log4js的源码之后我发现,如果设置了disableClustering为true之后,每个cluster进程都会单独向文件输出日志。

log4js.configure()配置的源码如下:

当你设置了disableClustering为true时log4js会做如上处理。然后当你getLogger时:

 

执行getLogger()函数时,会执行isMaster()方法,判断当前进程是不是主进程。isMaster函数执行时,如果disableClustering为true的话则认为当前进程是主进程。则会将sendLogEventToAppender作为打印日志时的执行函数。真正将日志打印到文件中。这个函数的具体执行大家可以自己去看下源码。里面逻辑很简单,就不再赘述。

这样就会发生多个进程同时向一个文件写入的情况,在某种情况下就会出现日志丢失情况。 我司遇到的问题就是在这种情况下发生的。而且官方文档也有提到这种模式会发生一些莫名其妙的问题(说的应该就是日志丢失吧)。log4js官方文档

好。到了这里,我们的node程序在pm2的cluster模式在使用log4js丢日志的原因基本是确定了。就是disableClustering的锅。那我们就要去解决它,怎么解决?

1:将disableClustering去掉。在配置中将disableClustering去掉之后,运行4个进程后发现,只有一个进程能正常打印日志,其它三个进程日志全部丢失。继续看官方文档发现下面一段话。

在log4js的配置中设置pm2为true时需要下载pm2-intercom参加才能保持日志的正常打印。ok,下载pm2-intercom。使用ab发起10个并发请求,打印结果如下。

ok。看起来一起完美。你以为结束了?当然不可能。

按照当前设置将服务发到测试环境,一跑,同样的代码,同样的设置,同样发起10个请求,只有3个打印出来了。试了好几次都是这样。so,还是在丢日志。

为什么呢?不可能啊!是不是电脑有问题?是不是pm2版本问题?是不是Node版本问题?是不是Log4js版本问题?在各种尝试了n次,将所有环境全部统一之后我发现,还是这样。so,老老实实看源码吧。

前面的一堆就不再说了,直接到关键代码。log4js下打印日志会有可能有两条路径。如下:

pm2下使用cluster模式时,其实所有的进程都是cluster,只有pm2主进程是master进程。但是pm2内部对进程做了标志。例如,启动4个cluster进程,则会有一个标志字段(默认是NODE_APP_INSTANCE)记录它的内部标志, 0、1、2、3。当标志位为0时,log4js就认为它是主进程(通过isPM2Master函数)。则此时master进程负责执行sendLogEventToAppender函数打印日志,cluster进程负责执行workerDispatch将日志发送给主进程(其实这时发送给的是pm2主进程)。

到了这里我们可以看到的结果就是,如果是cluster进程,则日志会发送给master进程,现在让我们来看pm2-intercom插件。我先是在github上找了一下它的源码发现没找到,后来问了log4js的官方人员后得到的结果是源码丢了!源码丢了!丢了! 原因不知道,结果就是找不到了。。issues地址

后来找到了一份貌似是第三方的pm2-intercom源码。pm2-intercom源码 找到源码看了一下。发现pm2-intercom会通过pm2的api连接到pm2,并接收到所有的消息:

上面是pm2官方的文档pm2文档 。pm2-intercom接收消息代码如下:

通过打印日志发现,所有cluster进程发送的消息都会被pm2-intercom接收。然后通过pm2-intercom转发出去。如下:

然后我发现在执行async.forEachLimit函数往别的进程广播时因为设置了4,所有最后执行下来。只会想pm2 list列表中的前4个进程推送消息,所有往后的进程都接收不到。 此时! 终于找到了为什么我在本地调试时为什么能接收到消息,而到了测试环境就不行。因为测试环境跑了很多服务。我的程序远在4之外。

此时,问题的原因已经找到了。通过在async.forEachLimit函数里面加上next()函数执行,发现果然所有的进程都能接收到消息。测试环境也已经可以接收到消息。

但是,这种方式有几个弊端:

1:所有的进程都能接收到消息,所有的主进程都会打印日志,所有可能你的日志会在不同的程序之间串。

2:往所有的进程发送日志,很没有效率。

所以最好可以根据自己的需求往特定的进程发送消息。

如你有一个进程专门记录日志,则可以都往那一个上面发。或者每个程序的master进程记录日志,则可以使用packet中的name来进行区分做分发。具体的实现可以自行定义。

至此,多进程打印日志的问题算是找到了。我也将修改代码发布到线上观察后续的结果。希望能解决问题。哈哈。

谨以此篇记录我踩的这些坑,如有错漏欢迎指教。

© 著作权归作者所有

唱不完的离歌

唱不完的离歌

粉丝 4
博文 1
码字总数 1682
作品 0
松江
程序员
私信 提问
使用pm2管理nodejs应用

PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and......

鱼煎
2019/01/22
48
0
Nodejs教程30(完结):PM2入门

阅读更多系列文章请访问我的GitHub博客,示例代码请访问这里。 PM2简介 PM2是常用的node进程管理工具,它可以提供node.js应用管理,如自动重载、性能监控、负载均衡等。同类工具有Superviso...

LeeChen
2019/04/11
0
0
生产级部署 Python 脚本,崩溃可自启!

今天介绍一个生产级的流程管理工具 PM2,通常我们说到 PM2 的时候,都是在说如何部署 Node.js 程序,但是实际上 PM2 很强大,不仅仅可以用来管理 Node.js,它还可以用来管理 Python、PHP、R...

承香墨影
2018/10/29
0
0
[译] 在生产环境运行 PM2 & Node.js

原文:medium.com/hackernoon/… 维护你的代码库并保持其相关性确有难度;但与之相比我们会发现,维护一个应用时最大的挑战来自于保持其存活和运行。不仅如此,随着 Node.js 变成大部分后端 ...

江米小枣tonylua
01/14
0
0
使用pm2 管理你的node项目

主要特性: 内建负载均衡(使用Node cluster 集群模块) 后台运行 0秒停机重载,我理解大概意思是维护升级的时候不需要停机. 具有Ubuntu和CentOS 的启动脚本 停止不稳定的进程(避免无限循环...

造化玉碟
2015/07/30
1.7K
0

没有更多内容

加载失败,请刷新页面

加载更多

Hadoop入门

概述 Hadoop是一个由Apache基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。Hadoop实现了一个分布式文...

阿dai学长
40分钟前
34
0
Go Web 编程之 数据库

概述 数据库用来存储数据。只要不是玩具项目,每个项目都需要用到数据库。现在用的最多的还是 MySQL,PostgreSQL的使用也在快速增长中。 在 Web 开发中,数据库也是必须的。本文将介绍如何在...

darjunlee
今天
79
0
spring-boot-maven-plugin not found的解决方案。

通过IDE创建一个springboot项目, <plugin> <groupId>org.springframework.boot</groupId>//这行红色 <artifactId>spring-boot-maven-plugin</artifactId>//这行红色</plugin> 提示sprin......

一片云里的天空
今天
92
0
OSChina 周三乱弹 —— 我可能是个憨憨

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @宇辰OSC :分享Hare Je的单曲《Alan Walker-Faded(Hare Je remix)》: #今日歌曲推荐# 可以放松大脑的一首纯音乐 《Alan Walker-Faded(Har...

小小编辑
今天
644
6
搞定SpringBoot多数据源(3):参数化变更源

春节将至,今天放假了,在此祝小伙伴们新春大吉,身体健康,思路清晰,永远无BUG! 一句话概括:参数化变更源意思是根据参数动态添加数据源以及切换数据源,解决不确定数据源的问题。 1. 引言...

mason技术记录
昨天
99
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部