Skip to content

日志优化:别让日志拖垮你的系统

日志本身是 IO 操作,大量日志输出会拖慢系统。

曾经遇到过一个案例:接口响应时间 200ms,但其中 180ms 都在写日志。优化日志后,响应时间降到了 30ms。

日志的性能问题

问题影响
同步写入线程阻塞等待 IO
日志量过大磁盘写满
日志对象频繁创建GC 压力
字符串拼接CPU 开销

异步日志

用异步 appender 解耦日志写入和主线程:

xml
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
    <queueSize>512</queueSize>              <!-- 队列大小 -->
    <discardingThreshold>0</discardingThreshold>  <!-- 0 = 队列满就丢弃 -->
    <includeCallerData>true</includeCallerData>  <!-- 保留调用栈信息 -->
    <appender-ref ref="FILE"/>
</appender>

队列满会发生什么?

discardingThreshold=0 意味着队列满了直接丢弃日志,不阻塞主线程。对于 INFO 级别的日志,丢弃是可以接受的;对于 ERROR 日志,建议同步写入。

xml
<!-- ERROR 日志同步,INFO/WARN 用异步 -->
<appender name="SYNC_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logs/error.log</file>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>ERROR</level>
    </filter>
    <!-- ... -->
</appender>

日志滚动策略

控制日志文件大小和保留时间:

xml
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <fileNamePattern>logs/app.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
    <maxFileSize>100MB</maxFileSize>       <!-- 单个文件最大 100MB -->
    <maxHistory>30</maxHistory>            <!-- 保留 30 天 -->
    <totalSizeCap>10GB</totalSizeCap>     <!-- 最多占用 10GB 磁盘 -->
</rollingPolicy>

压缩后的日志(.gz)体积是原始文件的 1/10 左右,可以大幅节省磁盘。

日志采样

高频日志(比如循环中的 debug)可以通过采样减少输出量:

java
public class SamplingDemo {

    private static final Logger log = LoggerFactory.getLogger(SamplingDemo.class);
    private static final int SAMPLE_RATE = 100;
    private static final AtomicInteger counter = new AtomicInteger(0);

    public void logSample(String message) {
        if (counter.incrementAndGet() % SAMPLE_RATE == 0) {
            log.info("采样日志: {}", message);
        }
    }
}

1% 的采样率意味着每秒 1000 条日志只会输出 10 条,在排查问题时足够了。

日志级别动态调整

不需要改代码重启,通过配置调整日志级别:

xml
<!-- logback-spring.xml -->
<springProfile name="dev">
    <root level="DEBUG"/>
</springProfile>
<springProfile name="prod">
    <root level="INFO"/>
</springProfile>

总结

  1. 异步写入:减少 IO 对主线程的影响
  2. 日志压缩.gz 格式节省磁盘空间
  3. 滚动策略:按时间和大小轮转,防止磁盘满
  4. 采样打印:高频日志用采样减少输出量
  5. 级别区分:ERROR 同步,DEBUG/INFO 异步

日志优化是性价比最高的性能优化之一,改动小,效果立竿见影。

基于 VitePress 构建