磁盘满了对日志打印(Logback)的影响
背景
我们生产环境有一个服务半夜报警:磁盘剩余空间不足10%,请及时处理。排查后发现是新上线的一个功能,日志打太多导致的,解决方法有很多,就不赘述了。领导担心报警不及时、或者报警遗漏,担心磁盘满了对线上业务有负面影响,甚至不可用,令我研究一下该情况下对服务的影响。
正文
注:我们线上的应用使用Logback日志框架进行打印,所以log4j、log4j2或其它日志框架不在本次研究的范围。
实验研究
实验步骤
- 启动服务,观察各项指标正常(模拟正常工作的服务以及环境状态)
- 将磁盘写满
- 观察应用服务、宿主机各项指标,查看服务响应是否正常(包括功能以及性能)
- 将大文件删除(恢复)
- 重复第3步
实验过程
第1、3、5步重在观测,不赘述。
第2步的模拟磁盘写满,使用linux的fallocate命令。
将磁盘写满的方式如下有几种:
- 自己写文件,写满为止,速度较慢,有开发(写脚本)成本
- 使用dd命令,但是比较慢,取决于磁盘的速度
使用truncate命令,但是该命令操作的结果并不占用实际的磁盘空间- 使用fallocate命令,fallocate -l {size} {fileName},如fallocate -l 20G text1
我选择了方式4,很快就写满了磁盘
验证方式:vim {xxx},进入文件编辑,写入任意内容,保存失败并提示:Can’t open file for writing(No space left on device)
实验结果
- 磁盘写满前、后,应用服务各项指标均正常(功能、性能)
- 磁盘写满后,服务器磁盘空间报警(无可用空间),删除文件后报警恢复
- 磁盘写满后,应用日志停止打印,删除文件后应用日志恢复打印
即,磁盘满了对于使用logback日志框架的应用,并不会造成影响。
实验结果令人诧异,按正常理解,磁盘满了之后再写入,会报No space left on device异常,进而影响到应用程序的功能。
原理分析
logback配置文件里的文件appender如下(RollingFileAppender同理
):
<appender name="FILE" class="ch.qos.logback.core.FileAppender"><file>${LOG_HOME}/${APP_NAME}.log</file><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder>
</appender>
把关注点放到appender即可,因为最终的日志输出是由appender控制的:它控制写在哪个文件里,格式是怎样的,滚动策略又是怎样的。
通过IDEA查看RollingFileAppender
的继承关系如下下示:
将视线聚焦到ch.qos.logback.core.OutputStreamAppender#writeBytes,代码如下:
private void writeBytes(byte[] byteArray) throws IOException {if(byteArray == null || byteArray.length == 0)return;lock.lock();try {this.outputStream.write(byteArray);if (immediateFlush) {this.outputStream.flush();}} finally {lock.unlock();}
}
由上可知,写日志时会加锁,避免资源竞争,然后通过outputStream写出,接着马上刷盘(默认情况)。
这里的outputStream可了不得,是个ResilientFileOutputStream
实例,顾名思议,【弹性的】FileOutputStream。它是个子类,核心逻辑在父类ResilientOutputStreamBase
上,看看write方法:
public void write(byte b[], int off, int len) {if (isPresumedInError()) {if (!recoveryCoordinator.isTooSoon()) {attemptRecovery();}return; // return regardless of the success of the recovery attempt}try {os.write(b, off, len);postSuccessfulWrite();} catch (IOException e) {postIOFailure(e);}
}
这个write方法隐藏着【即使磁盘满了也不影响业务】的秘密!它的核心逻辑是:如果能正常写文件,就写;如果写入失败(出现了IO异常),就抓住异常并切换至失败状态,接下来的一段时间都不再继续写文件,直接返回。
而此处所有的IO异常,就包含了No space left on device,因此,此处便是磁盘满了之后继续日志写入,却不会抛出No space left on device异常进而影响业务的原因。
还有一个问题,待磁盘有剩余空间后,如何恢复日志写入?上面实验结果提到,磁盘写满后,应用日志停止打印,删除文件后应用日志恢复打印。因此必然会有一个策略,能够在磁盘空间恢复后,继续进行日志写入。
再仔细查看看write
方法,方法首先判断当前状态是否为“失败”。若是,接着检查自上次失败至今的时间。如果已经经过了很长时间,就【尝试恢复】。
void attemptRecovery() {try {close();} catch (IOException e) {}addStatusIfCountNotOverLimit(new InfoStatus("Attempting to recover from IO failure on " + getDescription(), this));// subsequent writes must always be in append modetry {os = openNewOutputStream();presumedClean = true;} catch (IOException e) {addStatusIfCountNotOverLimit(new ErrorStatus("Failed to open " + getDescription(), this, e));}
}
尝试恢复的逻辑是:关闭旧文件流并重新打开文件流,将【失败】状态切换至【半恢复】状态,此处并未完全进入【正常】状态,而是立即返回,即是说当次的日志记录请求并不会写文件。
下次的日志写入,才会尝试将日志写入文件
- 若日志成功写入文件,就将状态切换至【正常】状态。
- 若日志写入文件失败,就将状态切换至【失败】状态。
此处的失败以及恢复逻辑非常像Hystrix断路器,即经历一个正常→失败→半通路状态,通过下次请求的结果来决定是恢复正常还是保持失败。
上面提到若经过很长时间,就尝试恢复,这里的【很长时间】其实是一个泛指,它有自己的时间计算逻辑,此处采用了类似于RocketMQ在消费失败时的重试策略,即采用指数退避逻辑来控制重试时间间隔。
每次【半恢复】状态下写文件失败时,会保持【失败】状态,且每一次的失败写入都会指数级延长【失败】状态保持的时间。
public boolean isTooSoon() {long now = getCurrentTime();if (now > next) {next = now + getBackoffCoefficient();return false;} else {return true;}
}
private long getBackoffCoefficient() {long currentCoeff = backOffCoefficient;if (backOffCoefficient < BACKOFF_COEFFICIENT_MAX) {backOffCoefficient *= BACKOFF_MULTIPLIER;}return currentCoeff;
}
backOffCoefficient初始值:20
BACKOFF_COEFFICIENT_MAX:327680
BACKOFF_MULTIPLIER:4
总结
使用Logback日志框架,当磁盘满了后不必惊慌,它不会对应用程序产生太负面影响。仔细考虑,做为一个日志框架本该如此,不能因为写不了日志就抛出异常进而影响应用本身,毕竟,日志终究是个辅助的旁路逻辑,没有它应用也应该work well。
底层知识的掌握有助于迅速理解上层应用。在阅读源码的过程中,我发现了非常熟悉的设计逻辑:即类似于Hystrix的断路器和RocketMQ消费失败重试的策略。由于之前有相关经验,因此我很快就能够理解作者的设计意图。
注:事后我测试了一下Log4j2日志框架,表现也差不多,磁盘满了也不会对应用程序本身产生影响。
相关文章:

磁盘满了对日志打印(Logback)的影响
背景 我们生产环境有一个服务半夜报警:磁盘剩余空间不足10%,请及时处理。排查后发现是新上线的一个功能,日志打太多导致的,解决方法有很多,就不赘述了。领导担心报警不及时、或者报警遗漏,担心磁盘满了对线…...
【算法与数据结构】--算法基础--数据结构概述
一、什么是数据结构 数据结构是一种组织和存储数据的方式,它定义了数据之间的关系、操作和存储方式,以便有效地访问和修改数据。数据结构是计算机科学中的一个重要概念,它为处理和管理数据提供了基本框架。数据结构通常包括以下几个重要方面…...

QECon大会亮相产品,全栈测试平台推荐:RunnerGo
最近在gitee上看见一款获得GVP(最有价值开源项目)的测试平台RunnerGo,看他们官网介绍包含了接口测试、性能测试、自动化测试。知道他们有saas版可以试用,果断使用了一下,对其中场景管理和性能测试印象深刻,…...
前端小案例-图片存放在远端服务器
前端小案例-图片存放在远端服务器 项目背景: 一个智能产业园的小程序由于可以控制很多种设备,可能有灯、空调、窗帘等智能设备。 现在面临以下问题: 需要存放很多设备的图标。设备的图标可能会进行修改。 为了解决上面的问题,…...

【鼠标右键菜单添加用VSCode打开文件或文件夹】
鼠标右键菜单添加用VSCode打开文件或文件夹 演示效果如下: 右击文件 或右击文件夹 或在文件夹内空白处右击 方法一:重装软件 重装软件,安装时勾选如图所示方框(如果登录的有账号保存有配置信息可以选择重装软件,…...

【jvm--堆】
文章目录 1. 堆(Heap)的核心概述2. 图解对象分配过程2.1 Minor GC,MajorGC、Full GC2.1 堆空间分代思想2.3 内存分配策略2.4 TLAB(Thread Local Allocation Buffer)2.5 堆空间的参数设置2.6 逃逸分析2.7 逃逸分析&…...

【数据库——MySQL(实战项目1)】(1)图书借阅系统
目录 1. 简述2. 功能3. 数据库结构设计3.1 绘制 E-R 图3.2 创建数据库3.3 创建表3.4 插入表数据 1. 简述 经过前期的学习,我们已经掌握数据库基础操作,因此是时候来做一个实战项目了——图书借阅系统。对于图书借阅系统,相信大家不难想到至少…...

[GXYCTF 2019]Ping Ping Ping题目解析
本题考察的内容是rce绕过,本事过滤的东西不算多也算是比较好绕过 基础看到这种先ping一下试试看 输入127.0.0.1看看有啥东西 有回显说明可以接着往下做 借用RCE漏洞详解及绕过总结(全面)-CSDN博客这个大佬整理的rce绕过 ;A;B无论真假,A与B都执行&…...

HTTP协议的请求协议和响应协议的组成,HTTP常见的状态信息
HTTP协议 什么是协议 协议实际上是某些人或组织提前制定好的一套规范,大家只要都按照这个规范来就可以做到沟通无障碍 HTTP协议是W3C(万维网联盟组织)制定的一种超文本传输通信协议(发送消息的模板和数据的格式),除了传送字符串,还有声音、视频、图片等流媒体等超文本信息 …...

【LeetCode】剑指 Offer Ⅱ 第6章:栈(6道题) -- Java Version
题库链接:https://leetcode.cn/problem-list/e8X3pBZi/ 类型题目解决方案栈的应用剑指 Offer II 036. 后缀表达式模拟 栈 ⭐剑指 Offer II 037. 小行星碰撞分类讨论 栈 ⭐单调栈剑指 Offer II 038. 每日温度单调栈 ⭐剑指 Offer II 039. 直方图最大矩形面积单调栈…...
vue3的element-plus的el-dialog的样式修改无效问题
问题描述 想要修改element-plus的对话框el-dialog中的样式,发现在页面style的scoped属性下,使用:deep深入选择器进行修改是无效的。(vue2下深度选择器是有效的) //无效 :deep(.el-dialog){background-color: transparent; }解决…...

归纳所猜半结论推出完整结论:CF1592F1
https://www.luogu.com.cn/problem/CF1592F1 场上猜了个结论,感觉只会操作1。然后被样例1hack了。然后就猜如果 ( n , m ) (n,m) (n,m) 为1则翻转4操作,被#14hack了。然后就猜4操作只会进行一次,然后就不知道怎么做下去了。 上面猜的结论都…...

WPFdatagrid结合comboBox
在WPF的DataGrid中希望结合使用ComboBox下拉框,达到下拉选择绑定的效果,在实现的过程中,遇到了一些奇怪的问题,因此记录下来。 网上能够查询到的解决方案: 总共有三种ItemSource常见绑定实现方式: 1.ItemS…...

Markdown类图之继承、实现、关联、依赖、组合、聚合总结(十五)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...

@MultipartConfig注解
前言: 在学习Javaweb的Servlet文件上传和下载的过程中,我们会遇到一个特殊的注解---MultipartConfig。 MultipartConfig的适用情况: 1.文件上传: 当您的应用程序需要接收用户上传的文件时,可以在相应的 Servlet 上使用 Multipart…...

Python并发编程简介
1、Python对并发编程的支持 多线程: threading, 利用CPU和IO可以同时执行的原理,让CPU不会干巴巴等待IO完成多进程: multiprocessing, 利用多核CPU的能力,真正的并行执行任务异步IO: asyncio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行使用Lo…...
WebSocket介绍及部署
WebSocket是一种在单个TCP连接上进行全双工通信的协议,其设计的目的是在Web浏览器和Web服务器之间进行实时通信(实时Web)。 WebSocket协议的优点包括: 1. 更高效的网络利用率:与HTTP相比,WebSocket的握手…...

自动求导,计算图示意图及pytorch实现
pytorch实现 x1 torch.tensor(3.0, requires_gradTrue) y1 torch.tensor(2.0, requires_gradTrue) a x1 ** 2 b 3 * a c b * y1 c.backward() print(x1.grad) print(y1.grad) print(x1.grad 6 * x1 * y1) print(y1.grad 3 * (x1 ** 2))输出为: tensor(36.) …...
睿伴科创上线了
Robotutor睿伴,一个专业的青少儿编程科创教育品牌和科创服务平台。 Robotutor睿伴拥有一个超过5年的青少儿编程科创教育团队,积累了丰富的课程研发,教学服务和赛事辅导经验。并和上海多所知名高校、上海市计算机学会、上海青少年科学社等开展…...
域名抢注和域名注册
随着互联网的发展,域名已经成为了企业和个人在网络上展示自己的重要标志。如何获得一段好记、易拼写、有意义的域名,是很多人都面临的问题。本文将介绍域名抢注和域名注册的相关内容,并推荐ym.qqmu.com这个可靠的域名注册平台。 一、什么是域…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...