前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >玩转 Linux 之:由 Nginx log rotation 聊聊 mv 的妙用

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

作者头像
用户1177713
发布2018-02-24 15:53:39
1.5K0
发布2018-02-24 15:53:39
举报
文章被收录于专栏:数据之美数据之美

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

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

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

代码语言:javascript
复制
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 机制:

代码语言:javascript
复制
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

代码语言:javascript
复制
// 运行 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/

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、Nginx 下如何正确的做日志切分
  • 2、文初的问题:为什么用 mv 而不是 cp 呢?
  • 3、最后的问题:文件对于进程的 WYSIWYG 问题
  • 4、SIGHUP 信号的意义与作用
  • Refer:
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档