多线程、多进程写同一日志情况下的日志库中 I/O 的选型
来源:互联网 发布:亚瑟士淘宝假货多吗 编辑:程序博客网 时间:2024/05/17 01:46
文件描述符与 inode 相关背景知识
出自《The Linux Programming Interface》
多线程
有上面的背景知识可知,多线程情况下写同一文件用的是同一个【文件偏移量】,因此只要单条写日志操作是原子操作,就不会出现日志混乱的情况。
系统 I/O
系统 I/O write() 不带应用层缓冲(进程级别缓冲),因此只要保证单条日志操作之调用一次 write() 就可以保证多线程是安全的。
标准 I/O
As an example, the POSIX standard requires that C stdio FILE* operations are atomic.(https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_concurrency.html)
待确认:多个线程是否用同一缓冲区?
先假设是(个人认为是,缓冲区应该是全局变量),全进程共享缓冲区,只要单条写日志操作是原子操作,也不会出现日志混乱。
多进程
标准 I/O
如果用标准 I/O, 不管单条写日志操作是不是原子操作,都会出现日志混乱,因为哪个进程先冲刷缓冲区不确定,更不用说【文件偏移量】不同步的问题了。如果没写一条日志就冲刷一次,又会大大降低性能。
系统 I/O
系统 I/O 的缓冲机制是内核级别的,因此只要保证一下两点,就不会日志混乱:1. 单条写日志操作是原子操作;
2. 【设置偏移量+write】 是原子操作。
如何做到【设置偏移量+write】 是原子操作呢?
由上图可知,如果 fd 是从父进程继承过来的,【文件偏移量】是共享的,不用人工干预;
如果进程是毫不关联的或者是分别打开的,那么如何解决【文件偏移量】的问题呢?假设每次 【lseek+write】,这种操作不是原子操作,如何保证【设置偏移量+write】 是原子操作呢?open() 提供了一个 O_APPEND 的 FLAG, 每次直接 write() 都是追加到文件末尾,这样【设置偏移量+write】就是一步完成了。(The Linux Programming Interface)
注意:open() 时如果设置了 O_APPEND, write 前 lseek 是无效的。
更新文件偏移量的内核 bug
Among the APIs subsequently listed are write() and writev(2). And among the effects that should be atomic across threads (and processes) are updates of the file offset. However, on Linux before version 3.14, this was not the case: if two processes that share an open file description (see open(2)) perform a write() (or writev(2)) at the same time, then the I/O operations were not atomic with respect updating the file offset, with the result that the blocks of data output by the two processes might (incorrectly) overlap. This problem was fixed in Linux 3.14.(http://man7.org/linux/man-pages/man2/write.2.html)
共享系统级文件描述符时,【更新偏移量+写】不是原子操作,导致即使共享偏移量也会有问题,kernel 3.14 中才修复。
日志滚动(rotate)——以上说的都是错的
在实际应用中,日志是需要滚动的(rotate),即超过配置的大小就要切换文件或者从头开始写,这样单一的写日志操作原子性已经不能使用多线程或多进程的场景了,还是需要加锁。
在日志滚动场景中,以下几步操作是必须的:
1. 检查日志大小是否超过配置值;
2. 切换日志文件名或移动到文件首部。
此外,write(系统调用)、fwrite(标准I/O)并不保证一次写完用户所有数据(几率比较小,通过返回值也可以判断是否写完)。
- 多线程、多进程写同一日志情况下的日志库中 I/O 的选型
- 多线程、多进程写同一日志情况下的日志库中 I/O 的选型
- 多线程下写日志
- PHP 日志系统的选型
- 统计Linux上进程的I/O情况
- 写日志到专案目录下的txt文件中
- Qt下写日志文件的函数
- windows下写日志文件的代码
- Python 中 logging 日志模块在多进程环境下的使用
- 程序的中写日志文件
- 程序中写日志的作用
- Python脚本中写日志的问题
- 写日志的方法
- 写日志的重要性
- 写日志的宏
- 写日志的功能
- 多线程写到一个日志文件中
- 网络编程 -- 服务器端的多线程、多进程、I/O复用比较
- Oracle(12.1.0.4)企业管理之:私有云的设置和管理(英文版)
- linux查看硬件设备信息
- Stanford机器学习课程笔记——SVM
- 【SzNOI语法百题】【d026】从 n 个数中挑选出最大的数(改)
- Android手机平板两不误,使用Fragment实现兼容手机和平板的程序
- 多线程、多进程写同一日志情况下的日志库中 I/O 的选型
- LeetCode-Palindrome Number
- 【SzNOI语法百题】【d027】水仙花数
- DWR的使用以及DWR中工具JS文件的使用
- ViewPager 和 SlidingPaneLayout 冲突解决办法
- android studio 迁移 eclipse 和 Intellij Idea 项目的注意事项
- Subversion error: Repository moved permanently to please relocate 解决方法
- Linux Shell 基本语法
- Redis常用命令