@Override protectedvoidsubAppend(E event){ // The roll-over check must precede actual writing. This is the // only correct behavior for time driven triggers.
// We need to synchronize on triggeringPolicy so that only one rollover // occurs at a time synchronized (triggeringPolicy) { if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) { rollover(); } } super.subAppend(event); }
/** * All synchronization in this class is done via the lock object. */ protected LogbackLock lock = new LogbackLock();
protectedvoidsubAppend(E event){ if (!isStarted()) { return; } try { // this step avoids LBCLASSIC-139 if (event instanceof DeferredProcessingAware) { ((DeferredProcessingAware) event).prepareForDeferredProcessing(); } // the synchronization prevents the OutputStream from being closed while we // are writing. It also prevents multiple threads from entering the same // converter. Converters assume that they are in a synchronized block. synchronized (lock) { writeOut(event); } } catch (IOException ioe) { // as soon as an exception occurs, move to non-started state // and add a single ErrorStatus to the SM. this.started = false; addStatus(new ErrorStatus("IO failure in appender", this, ioe)); } } // 通過(guò) encode進(jìn)行日志序列化,格式化寫入 protectedvoidwriteOut(E event)throws IOException { this.encoder.doEncode(event); }
if (discardingThreshold == UNDEFINED) discardingThreshold = queueSize / 5; addInfo("Setting discardingThreshold to " + discardingThreshold); worker.setDaemon(true); worker.setName("AsyncAppender-Worker-" + worker.getName()); // make sure this instance is marked as "started" before staring the worker Thread super.start(); worker.start(); }
// loop while the parent is started while (parent.isStarted()) { try { // 從隊(duì)列中獲取數(shù)據(jù),其實(shí)就是消費(fèi)者 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); }
異步寫在JVM突然crash的時(shí)候有丟失數(shù)據(jù)的風(fēng)險(xiǎn),但是性能很高,原因在于避免了直接寫磁盤帶來(lái)的性能消耗。但是需要注意的是多線程操作同一個(gè)阻塞隊(duì)列也會(huì)因?yàn)殒i爭(zhēng)搶的問(wèn)題影響性能。 a. 不同的模塊配置不同的日志文件和Appender,能減少鎖爭(zhēng)搶的問(wèn)題。 b. 減少不必要的日志輸出。 c. 增加阻塞隊(duì)列的大小,在neverBlock=false的情況下避免線程等待問(wèn)題。 d. 多個(gè)Appender(SiftingAppender),底層還是寫同一個(gè)文件。好處是減少了多線程在阻塞隊(duì)列上的鎖競(jìng)爭(zhēng)問(wèn)題。