磁盘满了对日志打印(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这个可靠的域名注册平台。 一、什么是域…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...
PH热榜 | 2025-06-08
1. Thiings 标语:一套超过1900个免费AI生成的3D图标集合 介绍:Thiings是一个不断扩展的免费AI生成3D图标库,目前已有超过1900个图标。你可以按照主题浏览,生成自己的图标,或者下载整个图标集。所有图标都可以在个人或…...
