日志对服务性能有很大影响,由于要写磁盘,且是写同一份文件,因此会有临界资源竞争,再高并发情况下,对性能影响十分明显,但日志又是必不可少的,在追求单机QPS的情况下,可以考虑以下两种方案:
1.异步日志
异步日志可以最低程度减轻日志对性能的影响,但也有一定风险,如果服务down掉了,错误栈还没有来得及被写入,那就尴尬了,另外还有几个其他方面的问题:
一是异步日志的情况下,有单次处理和批量处理两种方案,如果采用批量处理,最好对单条日志长度进行限制,适当丢弃过长的日志,避免批量处理时占满内存;
此外,需要合理预估生产速度,以便布置合适的消费者进行消费;
对于队列的选择也有一定要求,如果选择阻塞队列,仍然会影响性能,可以考虑使用无锁队列,log4j2中提供了无锁的Disruptor Ring Buffer来优化缓冲队列的性能方案,并且它解决了伪共享问题带来的性能影响。
在生产者快于消费者,或消费者快于生产者,即填满了Ring Buffer或Ring Buffer为空时,需要进行等待,等待策略有以下几种:
BlockWaiting:默认的策略,阻塞等待,但效率低下,占用CPU最少。
SleepingWaiting:占用CPU较多,适合异步写日志,处理延迟高,因为要睡眠。
YieldingWaiting:占用CPU较多,适合开启了超线程模式,释放CPU并服务其他线程。
BusySpinWaiting:轮询,占用CPU较多,适合未开启超线程模式,独占CPU。
2.同步与异步相结合
虽然性能有所下降,但同步与异步相结合的方式可以有效避免异步得不到错误栈的问题,重要的ERROR日志仍然采用同步方式,其他日志可酌情使用异步。
幸运的是,Log4j2对异步已经有了较好的支持,在性能上也比log4j1x高很多,可以方便的在xml中配置同步与异步策略。