在今天的文章中,我们将探讨使用 3 种不同的架构发送应用的日子到 Elasticsearch。我们将详述它们的优缺点。更多关于日志架构的介绍,请参考 “Elastic:开发者上手指南” 中的 “Elastic Stack 架构” 部分。
介绍
采用 Elastic Stack,应用程序日志发送到 Elasticsearch 有三种不同架构,每种架构各有优缺点:
- 应用程序 -> Filebeat -> Logstash -> Elasticsearch
- 应用程序 -> Filebeat -> Elasticsearch
- 应用程序 (Java) + Logstash-logback-encoder -> Logstash -> Elasticsearch
虽然可能还有其他发送日志的方法,但根据我的经验,将这些方法结合起来可以满足任何业务需求。
1)Application -> Filebeat -> Logstash -> Elasticsearch
这是将日志发送到 Elasticsearch 的标准方法,因为它为你提供了很多控制权。 你甚至可以更改将日志发送到另一个 Logstash 或 Elasticsearch 服务器的路径。 这是示例 filebeat.yml 配置文件:
filebeat.inputs:
- type: log
paths:
- "myapp.log"
output.logstash:
hosts: ["192.168.1.1:4561"]
以及用于接收 Filebeat 日志的 logstash.conf 文件:
input {
beats {
port => "4561"
host => "0.0.0.0"
}
}
filter { }
output {
elasticsearch {
hosts => ["0.0.0.0:9200"]
index => "app-logs-%{+YYYY.MM.dd}"
}
}
这种架构的优点是:
- 控制:你对日志采用的路径有很多控制权。我们可以在 Filebeat 中使用 Beat processors 来对数据进行处理,也可以使用 Logstash 丰富的过滤器来对数据进行加工。Logstash 可以对数据的摄入进行缓冲,并使用永久行队列对数据进行至少一次的发送。
- 无需修改代码:你无需更改应用程序代码即可发送日志。
这种架构的缺点是:
- 性能问题:存储日志涉及多个步骤,这会影响性能。
- 磁盘加载:应用程序将日志写入文件,Filebeat 读取该文件。 当应用程序实例数量增加时,这可能会导致磁盘负载过重。
2)Application -> Filebeat -> Elasticsearch
使用这种方法,你可以从日志发送路径中消除 Logstash,并将日志直接发送到 Elasticsearch。 如果你的日志是 JSON 格式并且已清理,则此方法效果很好。
下面是一个示例 filebeat.yml 配置文件,它读取日志文件并将它们发送到 Elasticsearch:
filebeat.inputs:
- type: log
paths:
- "myapp.log"
output.elasticsearch:
hosts: ["http://192.168.1.1:9200"]
这种方法的优点:
- 提高性能:通过消除 Logstash,你可以减少日志发送路径中的一个步骤。
- 无需修改代码:你无需更改应用程序代码即可发送日志。
这种方法缺点:
- 对日志修改的控制有限:Logstash 提供了许多工具,用于在将日志存储到 Elasticsearch 之前解析和清理日志。 没有它,你对日志修改的控制就会减少。
3)Application (Java) + Logstash-logback-encoder -> Logstash -> Elasticsearch
如果你有 Java 应用程序,则可以使用这种方法将日志直接发送到 Logstash,而无需任何解释器。 确实可以在不需要 Filebeat 或其他节拍的情况下发送日志。
为了能够将日志发送到 Logstash,你需要配置您的 Java 应用程序。 首先,将此依赖项添加到你的 pom.xml 文件中:
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.3</version>
<scope>runtime</scope>
</dependency>
然后你需要像这样向你的 logback.xml 文件添加一个新的附加程序
<property name="STACK_TRACE_COUNT" value="15"/>
<property name="CLASS_NAME_LENGTH" value="40"/>
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>192.168.1.1:4560</destination>
<addDefaultStatusListener>false</addDefaultStatusListener>
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<pattern>
<pattern>{"app_name": "myapp", "app_version":"1.0.0", "hostname": "${HOSTNAME}"}</pattern>
</pattern>
<mdc/>
<timestamp/>
<message/>
<threadName/>
<logLevel/>
<callerData/>
<stackTrace>
<throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter">
<maxDepthPerThrowable>${STACK_TRACE_COUNT}</maxDepthPerThrowable>
<shortenedClassNameLength>${CLASS_NAME_LENGTH}</shortenedClassNameLength>
<rootCauseFirst>true</rootCauseFirst>
</throwableConverter>
</stackTrace>
</providers>
</encoder>
</appender>
<root level="${ROOT_LEVEL}">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="LOGSTASH"/>
</root>
我们使用 LogstashTcpSocketAppender 类而不是 UDP 类,因为我需要确保在将日志发送到 Logstash 的过程中不会丢失任何日志。 但是,如果你不关心这种级别的可靠性,则可以使用 UDP。
另一方面,Logstash 应该配置为接收日志,并将它们存储在 Elasticsearch 等位置。 这是我当前使用的示例 Logstash 配置:
input {
tcp {
port => 4560
codec => json_lines
}
}
filter { }
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "operationlog-%{app_name}-%{+YYYY-MM-dd}"
}
}
这个方法的优点:
- 性能提升:通过将日志直接发送到 Logstash 而不是将它们存储在磁盘上,这种方法与以前的方法相比具有更少的开销。
这个方法的缺点:
- 限制:logstash-logback-encoder 只能与 Java 应用程序一起使用。
- 代码修改要求:要使用这种方法,你需要修改应用程序代码。
针对 Python 应用,你可以参考文章 “Elasticsearch:运用 Python 实时通过 Logstash 写入日志到 Elasticsearch”
其它方法
- 当然除了上面的方法之外,我们还可以直接使用 Logstash 来收集日志。请详细阅读文章 “Logstash:如何使用 Elasticsearch,Logstash 和 Kibana 管理 Apache 日志”。它的优点是可以使用 Logstash 所带来的强大的过滤器来对数据进行处理。在实际的使用中,我们甚至可以搭配 kafka 来对数据进行缓存。更多架构方面的知识,请阅读 “Elastic:开发者上手指南” 中的 “Elastic Stack 架构” 部分。
- 在最新的 Elastic Stack 发布中,我们更倾向于使用 Elastic Agent 来收集指标及日志信息。详细阅读,请参阅 “Observability:运用 Fleet 来轻松地导入 Nginx 日志及指标”。
结论
你可以将上述所有方法组合到一个架构中,如下所示:
如果要从 Java 应用程序发送日志,可以使用 logstash-logback-encoder 将它们直接发送到 Logstash,而无需将它们存储在磁盘上。
清理 Python 或 NodeJS 应用日志路径中的数据,可以结合使用 Filebeat 和 Logstash。 但是,如果你的数据已经是 JSON 格式,则无需使用 Logstash。 你只需将日志发送到 Filebeat,然后 Filebeat 会将它们存储在 Elasticsearch 中。
特别指出:针对日志中的数据处理,除了使用 Filebeat 中的 processors 以及 Logstash 中的过滤器,我们还可以使用 Elasticsearch 摄入节点所提供的 ingest pipeline 来对数据进行清洗。
更多阅读:Beats:Elastic Beats 介绍 及和 Logstash 的比较