关键词:
你听说过打印日志能把系统拖垮的情况吗。
所以项目中一般打印日志会使用异步AsyncAppender打印日志。
那么使用了AsyncAppender,会不会性能就好了,就不会阻塞业务流程了,会不会丢失日志呢,我们来看一下logback的实现。
先看下官方文档的介绍,AsyncAppender 会把处理的事件缓存到一个阻塞队列,默认情况下达到队列容量的80%的时候,会丢弃TRACE, DEBUG and INFO级别的事件,
根据默认配置neverBlock=false,队列也会发生阻塞,所以设置true,虽然完全是非阻塞但会丢失日志,特别是error级别的日志。
我们看下源码如何实现的。
public class AsyncAppender extends AsyncAppenderBase<ILoggingEvent>
boolean includeCallerData = false;
/**
* Events of level TRACE, DEBUG and INFO are deemed to be discardable.
* @param event
* @return true if the event is of level TRACE, DEBUG or INFO false otherwise.
*/
protected boolean isDiscardable(ILoggingEvent event)
Level level = event.getLevel();
return level.toInt() <= Level.INFO_INT;
protected void preprocess(ILoggingEvent eventObject)
eventObject.prepareForDeferredProcessing();
if (includeCallerData)
eventObject.getCallerData();
public boolean isIncludeCallerData()
return includeCallerData;
public void setIncludeCallerData(boolean includeCallerData)
this.includeCallerData = includeCallerData;
根据实现:
protected boolean isDiscardable(ILoggingEvent event)
Level level = event.getLevel();
return level.toInt() <= Level.INFO_INT;
public static final int OFF_INT = Integer.MAX_VALUE;
public static final int ERROR_INT = 40000;
public static final int WARN_INT = 30000;
public static final int INFO_INT = 20000;
public static final int DEBUG_INT = 10000;
public static final int TRACE_INT = 5000;
public static final int ALL_INT = Integer.MIN_VALUE;
TRACE, DEBUG and INFO级别的事件,在容量默认到达80%的时候会丢弃。
事件放入阻塞队列的时候即调用put方法时会判断容量及是否可以丢弃条件的判断,如下:
@Override
protected void append(E eventObject)
if (isQueueBelowDiscardingThreshold() && isDiscardable(eventObject))
return;
preprocess(eventObject);
put(eventObject);
private boolean isQueueBelowDiscardingThreshold()
return (blockingQueue.remainingCapacity() < discardingThreshold);
private void put(E eventObject)
if (neverBlock)
blockingQueue.offer(eventObject);
else
putUninterruptibly(eventObject);
private void putUninterruptibly(E eventObject)
boolean interrupted = false;
try
while (true)
try
blockingQueue.put(eventObject);
break;
catch (InterruptedException e)
interrupted = true;
finally
if (interrupted)
Thread.currentThread().interrupt();
当事件真正放入队列,是调用阻塞方法put,还是非阻塞方法offer,是由neverBlock配置决定的,默认false,会阻塞,所以为了性能,我们可以设置为true,也会丢弃日志。
真正处理队列事件的线程是默无闻的后台(Daemon)消费线程,
Worker worker = new Worker();
worker.setDaemon(true);
worker.setName("AsyncAppender-Worker-" + getName());
// make sure this instance is marked as "started" before staring the worker Thread
super.start();
worker.start()
事件的最终归宿AppenderAttachableImpl<E> aa。
class Worker extends Thread
public void run()
AsyncAppenderBase<E> parent = AsyncAppenderBase.this;
AppenderAttachableImpl<E> aai = parent.aai;
// loop while the parent is started
while (parent.isStarted())
try
E e = parent.blockingQueue.take();
aai.appendLoopOnAppenders(e);
catch (InterruptedException ie)
break;
addInfo("Worker thread will flush remaining events before exiting. ");
for (E e : parent.blockingQueue)
aai.appendLoopOnAppenders(e);
parent.blockingQueue.remove(e);
aai.detachAndStopAllAppenders();
异步打印日志是否非阻塞,是否会丢弃日志,是完全可以配置的,如果可以丢弃,依据日志的报警系统就不太准了,只能靠打点系统在系统内部aop的方式或其他方式打点上报了。
性能优化之异步日志(代码片段)
...ender打印日志。 那么使用了AsyncAppender,会不会性能就好了,就不会阻塞业务流程了,会不会丢失日志呢,我们来看一下logback的实现。 ... 查看详情
android性能优化之使用线程池处理异步任务(代码片段)
说到线程,我想大家都不陌生,因为在开发时候或多或少都会用到线程,而通常创建线程有两种方式:1、继承Thread类2、实现Runnable接口虽说这两种方式都可以创建出一个线程,不过它们之间还是有一点区别的&... 查看详情
mysql性能优化innodb之日志文件(代码片段)
...中,我们着重的介绍了SQL语句执行的一个过程。MySQL性能优化(一)My 查看详情
性能优化之java(android)代码优化
性能优化之Java(Android)代码优化本文为Android性能优化的第三篇——Java(Android)代码优化。主要介绍Java代码中性能优化方式及网络优化,包括缓存、异步、延迟、数据存储、算法、JNI、逻辑等优化方式。(时间仓促,后面还会... 查看详情
性能优化之java(android)代码优化
本文为Android性能优化的第三篇——Java(Android)代码优化。主要介绍Java代码中性能优化方式及网络优化,包括缓存、异步、延迟、数据存储、算法、JNI、逻辑等优化方式。(时间仓促,后面还会继续完善^_*)目前性能优化专题... 查看详情
android性能优化之内存泄漏检测以及内存优化(下)(代码片段)
...析一下Android内存优化的相关内容。 上篇:Android性能优化之内存泄漏检测以及内存优化(上)。 中篇:Android性能优化之内存泄漏检测以及内存优化(中)。 下篇:Android性能优化之内存 查看详情
前端性能优化之请求优化(代码片段)
...体验是一件永无止境的事情,没有最优,只有更优。前端性能优化方向有很多,今天主要讲解在网络请求上的优化。因涉及的优化方向较多,对于具体细节不再赘述。总体按以下三个方向优化:请求数据控制请求体积减少请求尽... 查看详情
聊聊接口性能优化的11个小技巧(代码片段)
和mq。和在代码块上加锁。先看看如何在方法上加锁:和异步调用。慢查询开关slow_query_log_file慢查询日志存放的路径long_query_time超过多少秒才会记录日志通过mysql的set命令可以设置:和预警的功能。架构图如下:我们可以用它监... 查看详情
react性能优化之componentwillreceiveprops&componentdidupdate(代码片段)
使用方法看起来一样:componentWillReceiveProps(nextProps)if(nextProps.count!==this.props.count)//doSomethingcomponentDidUpdate(prevProps)if(prevProps.count!==this.props.count)this.setState(count:this.props.count)区别:生命周期调用时机不同componentWillReceiveProps在组件接受... 查看详情
(转)foundation-性能优化之nsdateformatter(代码片段)
性能优化之NSDateFormatter为什么要优化NSDateFormatter?首先,过度的创建NSDateFormatter用于NSDate与NSString之间转换,会导致App卡顿,打开Profile工具查一下性能,你会发现这种操作占CPU比例是非常高的。据官方说法,创建NSDateFormatter代价... 查看详情
android面试之必问性能优化(代码片段)
...够,因为不管是工作还是面试,都需要开发者懂得大量的性能优化,这对提升应用的体验是非常重要的。对于Android开发来说,性能优化主要围绕如下方面展开:启动优化、渲染优化、内存优化、网络优化、卡顿检测与优化、耗... 查看详情
android性能优化之启动优化(代码片段)
Android性能优化之启动优化1.启动窗口优化Android系统在Activity的窗口尚未启动完成前,会先显示一个启动窗口(StartingWindow),等界面的第一帧渲染完成后再从启动窗口切换到真正的界面显示,启动窗口通常情况... 查看详情
android性能优化之启动优化(代码片段)
Android性能优化之启动优化1.启动窗口优化Android系统在Activity的窗口尚未启动完成前,会先显示一个启动窗口(StartingWindow),等界面的第一帧渲染完成后再从启动窗口切换到真正的界面显示,启动窗口通常情况... 查看详情
android性能优化之内存泄漏检测以及内存优化(中)(代码片段)
...,和Android的内存优化相关内容。 上篇:Android性能优化之内存泄漏检测以及内存优化(上)。 中篇:Android性能优化之内存泄漏检测以及内存优化( 查看详情
sql查询优化(代码片段)
SQL查询优化一、获取有性能问题SQL的三种方法 通过用户反馈获取存在性能问题的SQL 通过慢查询日志获取存在性能问题的SQL 实时获取存在性能问题的SQL二、慢查询日志介绍 1、使用慢查... 查看详情
深入浅出rust异步编程之tokio(代码片段)
...为什么使用rust来进行异步编程。这里tokio官方给出了一个性能测试的对比,可以看到tokio是性能最好,实际上运行这个基准测试的时候,tokio性能更好的2.0版本尚未发布,否则估计性能还有很大提升。因此,我们可以认为需要非... 查看详情
性能优化之惰性函数(代码片段)
我们正常封装一个兼容的绑定事件函数会这样写:functionaddEvent(dom,type,handle)if(dom.addEventListener)dom.addEventListener(type,handle,false)elsedom.attachEvent(‘on‘+type,handle)看起来没什么问题,但是,既然我们封装了这样一个函数,那我们肯定会... 查看详情
近期业务大量突增微服务性能优化总结-3.针对x86云环境改进异步日志等待策略(代码片段)
...块也是一个不小的挑战,这次遇到的核心业务接口的性能瓶颈,并不是单独的一个问题导致的,而是几个问题揉在一起:我们解决一个之后,发上线,之后发现还有另一个的性能瓶颈问题。这也是我经验不... 查看详情