取代传统log4j/SLF4J日志库,Zerolog是JVM更快地超低开销日志记录 - codeburst


本文将探讨Zerolog(缩写为Zlg)—一种对性能敏感的Java应用程序的超低开销日志记录外观。Zlg的目标是双重的-

  1. 超低开销,可抑制日志记录。换句话说,在禁用该级别的日志记录时调用日志记录方法的成本可以忽略不计。此外,可以以将这些成本降低到绝对零的方式来调用Zlg。
  2. 毫不妥协的代码覆盖率。抑制日志记录不应影响语句和分支机构的覆盖范围指标。日志条目是与其他任何语句一样的语句-如果值得编写,则值得测试。

总而言之,这些目标使Zlg适用于超高性能,低延迟应用程序和高安全性环境。
i7–4770 Haswell CPU 上进行的JMH基准测试,注意:运行是在运行JDK 10的CentOS 7上进行的,下面是纳秒级别测试:

当代的日志库(例如SLF4J和Log4j 2.x)非常棒,对于99%的每秒执行数百或数千次操作且通常以毫秒为单位的响应的常规应用程序,它们已绰绰有余。坦率地说,现代微服务架构中的网络调用和I / O数量超过了记录调用和任何其他低级检测的数量级。从工程意义上讲,在毫秒级的世界中提取纳秒级的性能等同于自我毁坏。因此,本文并不适合所有人,也不适合大多数人。

日志使用
与SLF4J类似:

public final class SysOutLoggingSample {
  private static final Zlg zlg = Zlg.forDeclaringClass().get();  
  
  public static void open(String address, 
                          int port, double timeoutSeconds) {
    zlg.i("Hello world");
    zlg.i(
"Pi is %.2f", z -> z.arg(Math.PI));
    zlg.i(
"Connecting to %s:%d [timeout: %.1f sec]"
          z -> z.arg(address).arg(port).arg(timeoutSeconds));    
    try {
      openSocket(address, port, timeoutSeconds);
    } catch (IOException e) {
      zlg.w(
"Error connecting to %s:%d"
            z -> z.arg(address).arg(port).tag(
"I/O").threw(e));
    }
  }
}

Zlg日志级别与SLF4J(以及大多数其他记录器)相当吻合。Zlg引入了新的日志级别LogLevel.CONF-逻辑上位于DEBUG和之间INFO。从JUL(java.util.logging)中轻松借来的CONF用于记录初始化和配置参数,当您的应用程序为用户提供各种配置选项时很有用。
注意:在那些不直接支持的记录器中被规范地映射到。 CONFINFOCONF
内置的日志级别,从最低到最高:TRACE,DEBUG,CONF,INFO,WARN,ERROR和OFF。

为什么Zerolog这么快?
什么传统的日志这么慢?典型的SLF4J语句(其他记录器大多在同一条船上)如下所示:

logger.trace(“ float:{},double:{},int:{},long:{}”,
             f,d,i,l);

这种方法存在三个问题,每个问题都会消耗大量的性能。

  1. 使用varargs传递参数。记录器通常超过2到4个(取决于API设计者的慷慨程度)格式化参数,记录器将提供基于varargs的API来容纳任意数量的参数。Varargs只是语法糖。性能影响在于阵列分配。此外,在优化之前进行的任何转义分析都将得出结论,可以在方法调用范围之外使用数组,因此将无法进行堆栈分配-将会​​进行完整的堆分配。
  2. 原始类型的包装。格式参数是的Object类型或vararg数组Object。将原始类型传递给API将导致自动包装。autobox自动包装缓存通常很小。只有相对少数的原始类型会被嵌入。甚至被中断的原始类型仍然需要新分支空间,需要通过偏移量算术和数组查找来解决。(有关Integer.valueOf(int)如何在JDK中实现的信息,请参见。)
  3. 垃圾收集。这是#1和#2的进一步症状;varargs和(非interned)自动包装最终都将在堆上分配对象,而不管是否启用了日志记录(除非伴随有“ guard”分支);从紧密循环中进行日志记录时,分配率特别高。这会对应用程序吞吐量和延迟产生负面影响。

更多点击标题见原文