玩转 Linux 之:由 Nginx log rotation 聊聊 mv 的妙用

1、Nginx 下如何正确的做日志切分

今天发现有个 Nginx 日志 rotation 出来大小是 0,很奇怪,按公司的业务场景来说,这是不可能的。

瞅了下前同事留下来的 rotation 脚本,看到了这么两行,也是他们当时 rotation 的方案:

cp tracklog.ooxx.com.access.log ${log_date_dir}/tracklog.ooxx.com.access.log.${log_name_date}
> tracklog.ooxx.com.access.log

然后这个脚本会由 crontab 每 10min 定时的调度一次,每次都将日志通过 cp 截取出来,放到以时间后缀命名的文件中去,

然后清空当前文件,如此循环反复。

初看没问题,但仔细想想,这里面会存在丢数据的问题:从 cp 到 > 清空文件这段时间

丢失数据的多少会依赖你业务的并发程度、当时机器负载、cp 文件的大小共同决定。

那这个问题怎么解决呢?

由于 Nginx 自身并没有提供日志管理功能,但是它提供了一个简单的 log rotation 机制:

mv access.log access.log.0
kill -USR1 `cat master.nginx.pid`
sleep 1
gzip access.log.0    # do something with access.log.0

下面我来详细解释下上面 4 行代码的含义:

(1)首先我们不是 cp,而是 mv 当前日志成为一个归档文件(最好加上时间后缀),此时文件 access.log 的 inode 并未改变,对于 Linux 进程来说,mv 并没有使文件发生变化,而进程是按 inode 追踪文件的,而不是文件名。(关于这点请看文末的 Refer(1))。所以直到 mv 完成以及 mv 完成后, nginx 进程会一直继续读写 access.log.0 文件(其实是 access.log,不是吗?)。

(2)Nginx 内部定义了 USR1 信号,这个信号和我们所用的 kill -9 信号类似的地方在于,他们都属于 linux 信号的一种,你可以 kill -l 查看全部信号的定义,各个发行版的定义会有些许差异;不同的地方在于,-9 属于系统级别的,而 USR1 属于应用软件级别的,开发者自定义的,至于程序收到 -USR1 信号后会干什么事,开发者自己说了算,这点和 -9 这种系统级别的信号不同。所以在这里,kill -USR1 不会杀死 Nginx 进程,而 Nginx Master 进程收到  -USR1 信号后,会重新打开名为 access.log 的日志文件,由于 access.log 已经不存在了,那么 access.log 会重新建立一个这样的文件,并开始往里读写数据,也就是说读写从 access.log.0 又切回到 access.log 了,这样新的请求日志会被重新开始记录了,而这个过程是没有任何读写中断,数据丢失的。

或者平滑重启:/usr/sbin/nginx -c /etc/nginx/nginx.conf -s reload

// 运行 nginx -s reload 命令,就会检查磁盘上的配置文件,并给主进程发送一个SIGHUP信号。

// 一旦主进程接受到一个SIGHUP,它会做两件事:

// (1) 重载配置文件、创建一组新的工作进程,新创建的工作进程立即接受连接、处理网络通信( 采用新的配置环境)。

// (2) 通知旧的工作进程优雅地推出,这些工作进程停止接受新连接。一旦当前处理的HTTP请求结束,工作进程会关闭连接。一旦所有连接关闭,工作进程就会退出。

(3)这句的意思是给一定的时间让上一步的读写切换顺利完成,以便可以进行后续的操作,对归档日志进行处理。比如有可能数据还在 nginx 的 buffer 中,没有及时写入  access.log.0 或是系统负载、IO 很高,没有及时响应切换,此时若强行对归档日志  access.log.0 进行处理,则会有数据丢失的风险。

(4)这句代码就是用户后续对归档日志  access.log.0 进行处理了,你可以 gzip、rsync 等等,随你怎么玩吧。

别看这个 rotation 过程只有 4 句简单的代码,但是它里面涉及的知识还是不少的,很多同学貌似都不理解这段过程究竟发生了什么。希望我的这段解说能让你明白这其中的来龙去脉。

文初提到的问题到这里算是有了一个简单、完美的解决方案,其实你也可以用一些三方的工具来做 log rotation,比如 logrotate,但是我觉得就我的这个按时间切分日志的需求来说,上面的 4 行代码已足够简洁了,不是么?

2、文初的问题:为什么用 mv 而不是 cp 呢?

其实我在文中已有阐述,如果你还没明白,建议读读这篇《理解 linux inode》,简单的说就是 mv 没有改变源文件的任何内容以及 inode 属性,也没有创建新文件,这样也就没有中断 nginx 进程对日志文件的读写,自然就不会有丢数据的风险了。而 cp 的话,是新建了一个目标空文件,然后去往里拷贝数据,这是需要时间的,而且无法保证对一个正在读写的文件拷贝数据的完整性。当你重定向清空源文件的时候,数据就会不同程度的丢失了。so,这里用 mv 而不是 cp,至此我想你也应当明白 cp 与 mv 的区别了。

3、最后的问题:文件对于进程的 WYSIWYG 问题

我现在有个文件 ooxx.log,每十分钟生成一个,同时有个 agent 监控进程每秒扫描一次,一旦文件出现了,立即开始传输(空文件和重复文件不会传输)。

那么现在的问题是:如何保证 agent 传输文件数据的完整性呢?

有如下几种方案:

(1)你可以创建文件锁 file.lock,生成完文件后删除,同时改 agent 源码,检测锁是否存在 (2)agent 中调用 lsof、fuse 等系统级调用检测是否还有文件句柄、文件锁未释放 (3)agent 编程语言的内置 API,比如排它锁或者锁检测机制 (4)先写 .tmp 文件,然后 mv

(5)...

你会选择哪种方案?同时各种方案它们有什么优劣呢?

这个问题就先暂且留作思考题吧~

4、SIGHUP 信号的意义与作用

刚有同学问我 SIGHUP 和 kill -9 的区别,后者属于强杀进程,可能内存中的进程数据还没持久化就结束进程,带来的危害是数据丢失,有点类似 windows 下面通过任务管理器终止进程。下面具体聊聊 SIGHUP 的问题。

The SIGHUP (“hang-up”) signal is used to report that the user's terminal is disconnected, perhaps because a network or telephone connection was broken.  SIGHUP的含义是连接断开,系统对SIGHUP信号的默认处理是终止收到该信号的进程。所以若程序中没有捕捉该信号(拿 sigaction 或者 signal 函数去注册信号处理器,或者拿 sigprocmask 之类的把信号给屏蔽掉),当收到该信号时,进程就会退出。 初衷是为了在终端挂断时告诉终端控制进程这个事件,而在守护进程中,通常用来重读配置文件。为了避免混淆,更多的情况是使用 SIGUSR1 和 SIGUSR2 来自定义实现不重启、终止进程而重新加载配置,或者其它功能。 因此如果程序中没有捕捉并处理这个信号,系统默认的动作是杀掉进程。大部分 daemon 进程都会捕捉并处理这个信号,重新读入配置文件。其它的程序没有处理,就被杀掉了。 SIGHUP会在以下3种情况下被发送给相应的进程: 1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进程) 2、session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程 3、若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。

4、kill -1,-1 对应的 signal 是 SIGHUP,SIGHUP对daemon是重新读取配置,对普通进程就是杀掉。一般的守护进程都会在收到这个信号时重新加载配置(本质上由开发者决定),因为 SIGHUP 本来的意义对守信进程没有意义(SIGHUP 是当控制终端失去连接时触发的信号,而守护进程没有控制终端,所以根本用不上)。 具体可以参考 nohup(1)

举例说明: 比如用户修改了 apache 配置文件,想不重起 apache 就让配置生效,可以往 apache 进程发一个 HUP 信号:killall -HUP httpd

或者 inetd 配置文件是 /etc/inetd.conf, 如果想inetd 去重读文件系统的话,可以给它发一个SIGHUP 信号。 再例如, 当你ssh到一台机器, 然后开个vim, 当你关闭这个 ssh 会话的时候 vim 就会收到 SIGHUP 信号,然后 vim 就会被终止。

参考:https://www.freebsd.org/doc/zh_CN/books/handbook/basics-daemons.html

http://httpd.apache.org/docs/2.2/stopping.html

Refer:

1、理解 linux inode

http://hi.baidu.com/leejun_2005/item/7893859e427ec9d91f427182

2、Nginx wiki:Log Rotation

http://wiki.nginx.org/LogRotation

3、How To Configure Logging and Log Rotation in Nginx on an Ubuntu VPS

https://www.digitalocean.com/community/articles/how-to-configure-logging-and-log-rotation-in-nginx-on-an-ubuntu-vps

4、linux 系统监控、诊断工具之 lsof 用法简介

http://my.oschina.net/leejun2005/blog/153584

5、python 在删除文件的时候检测该文件是否被其他线程或者进程占用?

http://segmentfault.com/q/1010000000367133

6、Linux 文件系统的实现

http://segmentfault.com/a/1190000000419225

7、进程间共享inode相互影响简单分析 

http://blog.sina.com.cn/s/blog_e59371cc0102ux75.html

8、被遗忘的Logrotate

http://blogread.cn/it/article/6354?f=wb

9、linux下cp,mv进行动态库覆盖问题分析

http://blogread.cn/it/article/6809?f=wb

10、Rotating MySQL slow logs safely

https://www.percona.com/blog/2013/04/18/rotating-mysql-slow-logs-safely/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

Windows PowerShell 工具

如果尚未开始使用 Windows PowerShell,很可能您很快就会用到它。Windows PowerShell 将成为 Windows Se...

30190
来自专栏Debian社区

改善Debian Linux软件包管理的七款工具

如果你运行Debian或它的衍生版本之一(比如Linux Mint或Ubuntu),迟早会遇到apt-get和dpkg,它们是主要的软件包管理命令。然而,这些只...

22030
来自专栏容器云生态

Openstack平台搭建之第一天 基于RDO方式搭建

openstck基于web方式的rdo部署 If you have any question ,please contact me by weichuangxx...

351100
来自专栏JMCui

Hybris安装和各个Extention简单介绍

前言:突然想好好梳理一下这几个月所学的内容了,顺便让自己的知识有一个系统的框架。这种安装仅仅适用于开发环境,不适于生产环境。 一、  安装JDK 请安装最新的O...

547110
来自专栏Java架构沉思录

10分钟了解ZooKeeper

ZooKeeper是一个开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。

12320
来自专栏Java架构师历程

ZooKeeper基本原理

ZooKeeper是一个开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。

18650
来自专栏F-Stack的专栏

F-Stack Q&A 第一期

Q1:F-Stack有中断模式吗,有计划支持吗?在计算密集型的应用中,轮询模式会占用更多的CPU资源? A1:F-Stack暂时只支持轮询模式,后续会支持中断+...

78850
来自专栏PPV课数据科学社区

大数据系列(4)——Hadoop集群VSFTP和SecureCRT安装配置

前言 经过前三篇文章的介绍,已经通过VMware安装了Hadoop的集群环境,当然,我相信安装的过程肯定遇到或多或少的问题,这些都需要自己解决,解决的过程就是学...

34540
来自专栏安全领域

使用JavaScript开发物联网设备也会非常安全

本文将引导你完成一个练习,向你展示如何在 IoTivity 安全框架上使用 Java 对 OCF 设备进行快速原型设计。

521100
来自专栏FreeBuf

使用SCCM和Viewfinity进行提权实验

如今越来越多的公司开始限制用户以本地管理员的身份来运行软件,随之带来的问题是,如何允许用户执行某些管理行为,例如安装已批准的软件。市场上有一些工具旨在解决这个问...

13200

扫码关注云+社区

领取腾讯云代金券