Logback与Log4j2日志框架性能对比与调优方式

目录
  • 前言
  • 性能测试
    • logback
      • 同步日志
      • 异步日志(队列扩容)
      • 异步日志(半队列扩容)
    • log4j2
      • 同步日志
      • 异步日志(队列扩容)
      • 异步日志(日志淘汰策略)
      • 异步日志(半队列扩容)
      • 异步日志(等待策略)
  • 性能调优
    • 异步日志
      • 日志可靠性
      • Logback
      • Log4j2
    • 日志抛弃策略
      • Log4j2
      • Logback
    • 日志等待策略
      • TimeoutWaitStrategy
      • YieldWaitStrategy
    • 队列容量
      • Logback
      • Log4j2
      • 长度计算公式
    • 消费瓶颈
      • 消费TPS
      • 请求TPS
      • 消费者优化

前言

看到目前线上大多日志框架测评大多从宏观角度,直接对比异步同步的吞吐量,但是没有考量到更深层的淘汰机制、等待策略、队列长度等对性能表现的影响,因此本文将从更多的角度对比及分析两款日志框架的性能表现,通过JProfiler+Jmeter压测及数据采集,从线程占用、锁占用、宏观耗时等多维度可视化数据。

性能测试

logback

同步日志

耗时

未经过任何调优,采用Logback默认配置得出上图,一百万条日志打印耗时(ms),如图:单线程下性能最佳,耗时随线程数增加而下降。

线程占用

单线程

无阻塞状态

多线程

多线程打印日志时,会产生大量线程阻塞,线程越多阻塞状态越多

四线程

八线程

十六线程

锁占用

线程发生多次占用锁的情况。查看Logback源码可得知,检查容量、放入队列、取出队列都需要在取得锁后进行

异步日志(队列扩容)

样本数100万,队列长度110万

耗时

线程占用

单线程

多线程

四线程

八线程

十六线程

锁占用

每次写入队列都需要占用锁,同时Appender从队列取出也需要占用锁

异步日志(半队列扩容)

样本数100万,队列长度50万,不启用抛弃策略

耗时

线程占用

单线程

多线程

写入耗时明显增长,写入过程仍然发生阻塞状态

四线程

八线程

十六线程

锁占用

log4j2

同步日志

样本数100万,Logger到Appender串行执行,输出到文件

耗时

线程占用

线程产生长时间的等待,主要是缓冲环溢出后无法写入,生产者根据等待策略进入等待状态

单线程

单线程生产不需要争抢锁,因此全程无阻塞

多线程

整体来看,阻塞的时间随着线程增多而增多,因此多线程对同步日志影响极大,性能损失严重

四线程

八线程

十六线程

后续监控因阻塞时间太长跳过

锁占用

阻塞在Appender上的输出流上,输出流是在单线程中执行的

异步日志(队列扩容)

样本数100万,队列长度110万,使用Yield等待策略

耗时

单线程占用最高,耗时随线程数增加而缩短,直到线程数超过CPU核数。单线程耗时与logback相当,多线程耗时比logback缩短了2倍

线程占用

单线程与多线程使用都无阻塞状态,保证足够的队列容量,能使日志操作保持高吞吐和低延迟,避免阻塞等待

单线程

多线程

四线程

八线程

使用与宿主机CPU核数相等的线程数,日志写入过程无阻塞、无线程切换

十六线程

异步日志(日志淘汰策略)

样本数100万,队列长度50万,启用抛弃策略

耗时

线程占用

队列长度50万,正常来说应与半队列扩容一样,产生阻塞现象,但启用了日志淘汰策略,无法写入队列的将直接抛弃不阻塞等待

单线程

多线程

四线程

八线程

十六线程

异步日志(半队列扩容)

样本数100万,队列长度50万,使用Yield等待策略

耗时

当队列满后,大幅影响了响应时间,吞吐量依赖Appender的消费性能

线程占用

单线程记录日志时,前半段队列未满时生产线程一直处于工作状态,后半段因消费能力跟不上生产能力,导致队列满载,生产线程开始出现等待状态

单线程

等待的时间比多线程少,是因为单线程下日志生产速度慢,同时日志也在倍消费

多线程

前一段时间可以维持高性能工作,但后面队列满后开始发送等待,导致耗时延长

四线程

八线程

十六线程

锁占用

并未发现日志记录过程中发生锁占用

异步日志(等待策略)

样本数100万,队列长度50万,使用Timeout等待策略

耗时

线程占用

未产生阻塞状态

单线程

多线程

因Timeout等待策略使用了锁,因此产生一定的阻塞

四线程

八线程

十六线程

锁占用

使用Timeout等待策略时,放入队列前会取锁,进行消费者线程唤醒动作

性能调优

异步日志

无论是logback还是log4j2,使用异步日志可以大幅提高日志操作耗时,间接提高业务方整体耗时

日志可靠性

异步日志无法保证日志可靠性,系统意外关闭会丢失队列中的日志,因此要求高可靠的日志,应该选择数据库或者MQ来保证

Logback

通过

<appender name="async-log-all" class="ch.qos.logback.classic.AsyncAppender">

设置

Log4j2

通过

System.setProperty("Log4jContextSelector", "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector")

设置

日志抛弃策略

将溢出队列的日志抛弃,保持稳定的响应速度。对业务方来说能保持良好、稳定的日志服务,但需要容忍一定的日志丢

Log4j2

通过

System.setProperty("log4j2.AsyncQueueFullPolicy","Discard")

设置

Logback

通过&lt;discardingThreshold&gt;指定抛弃日志的阈值

抛弃边界

当队列剩余容量小于阈值后,将抛弃ERROR以下的日志

禁用抛弃策略

设置为0则表示不抛弃,业务线程等待队列空间可用后写入

默认阈值

默认阈值为队列长度的20%,队列长度100阈值为20

日志等待策略

Log4j2独有的特性,指定队列满时,生产者进行等待的行为,需要在不开启抛弃策略下进行

TimeoutWaitStrategy

Log4j2默认的等待策略,通过Object.wait等待队列腾空。在放入队列时会加锁,不推荐使用。

YieldWaitStrategy

通过

System.setProperty("log4j2.asyncLoggerWaitStrategy","Yield")

设置。通过System.yield()等待队列腾空,比Timeout等待策略更高效,比Busy等待策略更节能

队列容量

由性能测试可知,不适用日志抛弃策略下,队列满载后生产线程将阻塞等待队列腾空,直接影响业务方的效率

Logback

通过<queueSize>指定队列长度,Logback固定使用ArrayBlockingQueue作为队列

Log4j2

通过

System.setProperty("log4j2.asyncLoggerRingBufferSize","x")

指定

二次方长度

RingBuffer内部计算位置时通过二进制方式计算,使用二的指数长度可以提高计算速度

长度计算公式

暂未找到统一标准的计算公式,本人觉得可以通过(日志峰值TPS#消费TPS)*15*60来计算

承载容量

这个公式的含义是:应用15分钟以峰值去生产的日志可以全部被队列容纳

成本

从成本的角度看,队列不应该无限量地预估,在保证系统不受到容量影响下,尽可能地使用小的长度,节省内存开支

响应时间

一般应用不应该长时间在峰值运行,如果出现长时间在峰值运行,则应该进行水平拓展分散请求压力。因此容纳15分钟之内的峰值,可以有足够时间让运维响应,进行水平拓展分散压力。

消费瓶颈

日志消费TPS由Appender消费效率决定,当日志TPS超过消费TPS时,日志将开始在队列中堆积

消费TPS

某个Appender在一秒内消费的日志数量,举FileAppender为例,每条日志消费花费100微妙(性能好的主机可以到60),一秒可以消费1万条日志,即消费TPS为1万

请求TPS

一般Web应用不会承载超过消费TPS的流量。假设每个请求打印五条日志,则需要5000以上的TPS才能产生日志堆积

消费者优化

日志TPS长时间(15min+)超过消费TPS的场景下,应该对消费能力进行优化,使用轻量级的Appedner、简单的Layout、日志抛弃策略、过滤器、业务方规范等方面进行优化

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • SpringBoot2 集成log4j2日志框架的实现

    前言 Log4j2是 Log4j 的进化版本,并提供了许多 Logback 可用的改进,同时解决了 Logback 体系结构中的一些固有问题.而且日志处理中我们会用到kafka作为日志管道.而kafka客户端依赖与Logback的兼容不是很完美,你可以选择排除依赖冲突或者使用Log4j2 . <!-- more --> 排除Logback依赖 Spring Boot 2.x默认使用Logback日志框架,要使用 Log4j2必须先排除 Logback. <dependency> &

  • 浅谈spring boot 集成 log4j 解决与logback冲突的问题

    现在很流行springboot的开发,小编闲来无事也学了学,开发过程中遇见了log4j日志的一个小小问题,特此记载. 首先在pox.xml中引入对应的maven依赖: <!-- 引入log4j--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency&g

  • Springboot整合log4j2日志全解总结

    在项目推进中,如果说第一件事是搭Spring框架的话,那么第二件事情就是在Sring基础上搭建日志框架,我想很多人都知道日志对于一个项目的重要性,尤其是线上Web项目,因为日志可能是我们了解应用如何执行的唯一方式. 在18年大环境下,更多的企业使用Springboot和Springcloud来搭建他们的企业微服务项目 ,此篇文章是博主在实践中用Springboot整合log4j2日志的总结. 常用日志框架 java.util.logging:是JDK在1.4版本中引入的Java原生日志框架 Lo

  • 如何将应用的log4j替换成logback详解

    前言 最近考虑到log4j很久不更新.性能相对弱,以及一些项目本身的原因,经过较为谨慎的考虑,决定改用logback.如果你已经对log4j很熟悉,你也可以很快上手logback.如果你喜欢使用log4j,你也许会迷上使用logback.迁移还是比较顺利的,花了1个小时左右就搞定了,做个简单的笔记. 方法如下 (1) 首先去掉所有log4j相关的依赖,主要有: <dependency> <groupId>log4j</groupId> <artifactId>

  • 基于logback 实现springboot超级详细的日志配置

    前言 java web 下有好几种日志框架,比如:logback,log4j,log4j2(slj4f 并不是一种日志框架,它相当于定义了规范,实现了这个规范的日志框架就能够用 slj4f 调用).其中性能最高的应该使 logback 了,而且 springboot 默认使用的也是 logback 日志,所以本篇将会详细的讲解 logback 的日志配置方案. 本篇主要内容如下: •logback 配置文件的构成 •如何将日志输出到文件 •如何按时间,按大小切分日志 •如何将让一个日志文件中只有

  • Logback与Log4j2日志框架性能对比与调优方式

    目录 前言 性能测试 logback 同步日志 异步日志(队列扩容) 异步日志(半队列扩容) log4j2 同步日志 异步日志(队列扩容) 异步日志(日志淘汰策略) 异步日志(半队列扩容) 异步日志(等待策略) 性能调优 异步日志 日志可靠性 Logback Log4j2 日志抛弃策略 Log4j2 Logback 日志等待策略 TimeoutWaitStrategy YieldWaitStrategy 队列容量 Logback Log4j2 长度计算公式 消费瓶颈 消费TPS 请求TPS 消费

  • springboot log4j2日志框架整合与使用过程解析

    目录 一.引入maven依赖 二.添加配置文件log4j2-spring.xml 三.自定义配置文件 四.测试一下 一.引入maven依赖 Spring Boot默认使用LogBack,但是我们没有看到显示依赖的jar包,其实是因为所在的jar包spring-boot-starter-logging都是作为spring-boot-starter-web或者spring-boot-starter依赖的一部分.如果这里要使用Log4j2,需要从spring-boot-starter-web中去掉sp

  • mysql 性能的检查和调优方法

    在遇到严重性能问题时,一般都有这么几种可能:1.索引没有建好; 2.sql写法过于复杂; 3.配置错误; 4.机器实在负荷不了; 1.索引没有建好 如果看到mysql消耗的cpu很大,可以用mysql的client工具来检查. 在linux下执行 /usr/local/mysql/bin/mysql -hlocalhost -uroot -p 输入密码,如果没有密码,则不用-p参数就可以进到客户端界面中. 看看当前的运行情况 show full processlist 可以多运行几次 这个命令可

  • Java接口测试之日志框架Logback的具体使用

    目录 一.引言 二.前言 三.LogBack.Slf4j和Log4j之间的关系 四.默认日志Logback 五.配置详解 1.添加日志依赖 2.配置文件 六.多环境日志输出 七.单元测试 八.工程目录 九.总结 一.引言 对于一个成熟的接口测试框架,日志管理这个是必不可少的.在开发和调试阶段,日志可以帮助我们更快的定位问题:而在测试的运维过程中,日志系统又可以帮助我们记录大部分的异常信息,通 二.前言 Spring Boot 在所有内部日志中使用Commons Logging,但是默认配置也提供

  • Spring5新功能日志框架Log4j2整合示例

    目录 Spring5整合Log4j2日志框架 一.引入依赖 二.创建Log4j2 配置文件 三.手动进行单独的输出 Spring5整合Log4j2日志框架 本次系列的学习是基于 spring5 ,也就是最新的版本. spring5 的整个代码都是基于 java8 的,自身作了不少的优化,比如许多不建议使用的类和方法已经在代码库中删除. 此外,spring5 框架自带了通用的日志封装,但是我们依然可以整合其他的日志框架使用,比如 Log4j.不过在 spring5 中移除了 Log4jConfig

  • Spring AOP日志框架实现过程图解

    AOP日志框架实现 JDK动态代理实现日志框架 首先,在项目包com.ay.test 下创建业务接口类BusinessClassService,具体代码如下: BusinessC lassService 业务接口类可以理解为日常开发业务创建的接口类, 接口中有一个简 单的方法doSomeThing .然后,开发业务类的实现类BusinessClassServiceImpl,具体代码如下: 实现类BusinessClassServicelmpl 实现了BusinessClassServ ice 接

  • Java日志框架之logback使用详解

    为什么使用logback 记得前几年工作的时候,公司使用的日志框架还是log4j,大约从16年中到现在,不管是我参与的别人已经搭建好的项目还是我自己主导的项目,日志框架基本都换成了logback,总结一下,logback大约有以下的一些优点: 内核重写.测试充分.初始化内存加载更小,这一切让logback性能和log4j相比有诸多倍的提升 logback非常自然地直接实现了slf4j,这个严格来说算不上优点,只是这样,再理解slf4j的前提下会很容易理解logback,也同时很容易用其他日志框架

  • springboot使用log4j2异步日志提升性能的实现方式

    目录 一.引入disruptor 二. 全局异步模式 三.异步/同步混合模式 同步日志的业务流程处理和日志打印是在同一个线程,日志打印的过程实际上是写文件IO的过程,这个过程是相对耗时的,并且会阻塞主线程的执行,只有日志打印完成后才会继续执行业务处理代码.如果日志量比较大,会影响主业务流程的处理效率.异步日志实现方式:将日志存入一个单独的队列中,有一个单独的线程从队列中获取日志并写入磁盘文件. 日志放入队列的耗时,肯定比磁盘写IO文件耗时要少的多得多,所以对主业务流程影响极小. 一个单独的线程进

  • SpringBoot logback日志框架使用过程解析

    一.基本知识说明 SpringBoot默认使用logback作为日志框架 ,所以引入起步依赖后就可以直接使用logback,不需要其他依赖. SpringBoot会默认加载classpath:logback.xml或者classpath:logback-spring.xml 作为日志的配置文件,在springboot项目中可以直接把日志配置文件放在resources目录下. 简单使用时也可以不使用日志配置文件,将日志相关的配置直接放在application.yml中,如下 #日志设置 loggi

随机推荐