多进程使用同一log4j配置导致的日志丢失与覆盖问题

最近接手了一个流传很多手的魔性古早代码,追日志时发现有明显缺失。对log4j不熟,不过可以猜测日志出问题肯定和多进程使用同一个log4j配置有关。经多次排查,终于捋清了其中逻辑。本文对排查过程进行复盘。

 

一、表征

故事背景:项目有多个入口。一边即以持续运行获取消息的后台进程形式运行,一边又作为单次任务调度的普通进程被不断启动并结束退出。也就是说,同一个项目同时运行着多个进程,并且使用着同一个log4j配置。
下面称后台进程为进程A,普通进程为进程B。A在后台持续运行,B多次短暂执行。
|<----------------- A ------------------- ...... 
  |<- B ->|    |<--- B --->|   |<- B ->|

 

起因:进程B的运行效果与预计不符,需排查B的日志定位问题。
神奇的现象:
1)有的B有日志有的没有,没发现明显的出现规律。
2)有的B日志完整,有的不完整。
3)只有近几个小时的B有日志,写进文件的B的日志居然过一段时间会消失。
4)历史日志中,绝大多数日期只有一个B的日志,而个别日志有很多。
 
 

二、内因

每一个A/B的日志指针都分别以append方式打开日志文件,文件指针互相独立,各自向后写。从而导致两个问题:
问题1:因A写的慢、B写的快(业务实际情况),所以每一个B均在文件末尾append,和上一B相邻,而A会逐渐覆盖B的日志,直到开始滚动分页。
 
问题2:当切换到下一自然日0点时,开始滚动分页时,如果此时有B正在运行,则A和B各自有一个指针。
如果A先写,则两次滚动分页后,A往log.yesterday中写,而B往log中写,并在任务完成后释放句柄并退出。新的B继续在log中写。
如果B先写,则两次滚动分页后,A往log中写,B往log.yesterday中写,并在任务完成后释放句柄并退出。新的B继续在log中写。
无论如何,真正的log.yesterday都已经被覆盖。
 
 
 
day1
day2
day3
day4
day5
day6
假设  
A先写
A先写
B先写
B先写
A先写
log
day1的A+B
day2的B
day3的B
day4的A+其他B
day5的A+其他B
day6的B
log.day1
 
day2的A
day2的A
day2的A
day2的A
day2的A
log.day2    
day3的A
day3的A
day3的A
day3的A
log.day3      
day4的第一个B
day4的第一个B
day4的第一个B
log.day4        
day5的第一个B
day5的第一个B
log.day5          
day6的A

 
D日(D <= T-2)的日志只有四种情况:(T日即当前日期)
① 记录了D+1日的第一个B(因为D+1日有B跨天,且B先写)
② 记录了D+1日的所有A(因为D+1日有B跨天,且A先写)
③ 记录了D日的所有A+ 未被覆盖的B(因为D+1日没有B跨天,且D日B先写)
④ 记录了D日的所有的非首个B(因为D+1日没有B跨天,且D日A先写)
 
符合观察到的现象。
done
posted @ 2019-12-02 20:42  沙木鱼  阅读(2113)  评论(2编辑  收藏  举报