使用 Elastic Stack 探索日志记录策略
由吉多莉娜科塔撰写 最初于 2021 年 6 月 9 日发布_ 使用 Elastic 堆栈开发日志摄取策略时要考虑的设计选项和权衡 想象一下,您的团队负责关键业务 IT 服务。假设您运营共享 DevOps 平台,该平台使您公司的开发人员能够推出新功能和修补程序。想想版本控制系统、CI/CD 工具、部署环境等等。这些服务可以在多个环境中运行,并且它们的数量和类型会随着时间而改变(例如,通过将合同测试
由吉多莉娜科塔撰写
最初于 2021 年 6 月 9 日发布_
使用 Elastic 堆栈开发日志摄取策略时要考虑的设计选项和权衡
想象一下,您的团队负责关键业务 IT 服务。假设您运营共享 DevOps 平台,该平台使您公司的开发人员能够推出新功能和修补程序。想想版本控制系统、CI/CD 工具、部署环境等等。这些服务可以在多个环境中运行,并且它们的数量和类型会随着时间而改变(例如,通过将合同测试集成添加到您的 CI/CD 中)。您日常工作的一部分是密切关注这些服务,监控它们的性能,检测异常情况,并在一切都起火时快速进行根本原因分析。 Elastic Stack 为所有这些活动提供了统一的解决方案。如下图所示,Beats 模块可以收集主机上的日志和指标,并将它们发送到 Logstash,在那里进行解析、清理和丰富。然后,Logstash 在 Elasticsearch 搜索和分析引擎中索引(保留)处理过的数据,您的团队可以使用 Kibana UI 查询这些数据。
所以,就是这样,对吧?会出什么问题?很多。在之前的系列博文中,我们已经讨论了在 Kibana 中分析日志时的常见问题以及可能的解决方案。处理丢失的日志条目、糟糕的搜索性能和可用性等问题。这一次,我想退后一步,解决相关但不同的挑战,重点关注我们如何为我们的日志创建和配置 Elasticsearch 索引。我们将在我们的用例场景中进入 DevOps 团队的位置,并在选择日志索引策略时揭示资源效率、可靠性和可维护性之间的权衡。例如,我们如何在不陷入配置地狱的情况下为数十个日志源实施不同的保留策略?我们以最少的工作量容纳新日志源的策略有多灵活?什么数量和大小的索引将优化摄取吞吐量、磁盘利用率和分析性能?
这篇博文将介绍两种日志索引策略,并根据可维护性和效率标准对其进行评估。正如我们将看到的,这些策略都不会完全令人满意,但它们将为第三个日志索引策略建立案例......但我将作为第二个结论性博客文章留下悬念。
追逐正确的日志索引策略
我们选择 Elastic Stack 来集中记录在多个环境中运行的异构服务组。我们设置了Filebeatsshippers 将日志流发送到 Logstash 服务器,在该服务器上我们配置管道以将各种日志格式标准化为更一致的结构以增强相关性(请参阅Elastic Common Schema以获得灵感)。特别是,每个已处理的日志事件都将有一个用于服务名称的字段和另一个用于环境的字段。最后,Logstash 管道使用Elasticsearch 输出插件将处理后的日志作为 JSON 文档传送到 Elasticsearch 集群中的指定索引。
在这篇博文的上下文中,日志索引策略由 (i) 一个 index 名称模式,(ii) 一个 别名 用于匹配相同名称模式的所有索引(也称为 backing indices),以及(iii) 日志轮换政策。质量策略易于实施和维护,适应服务环境的变化,并有效地使用 Elasticsearch 资源(磁盘、CPU、内存)。
S1:按环境分组 - 按年龄和大小轮换
核心思想是按环境对服务进行分组,并将它们的日志写入同一个索引_alias_。看看下面的图表。在左侧,我们看到了由 Logstash 从 Jenkins 和 Nginx 生产日志转换而来的 JSON 文档。请注意,这些文档有一些公共字段,特别是host.env
,即服务运行环境的名称。目标索引别名(“logs-prod-2021”)及其支持索引的表示在图表的右侧。当您写入别名时,您写入唯一允许写入的后备索引,以避免不一致和重复。相反,当您从别名中读取时,您会从所有支持索引中读取。
在我们的提议中,后备索引的_index name pattern_有四个部分,由破折号(“-”)分隔:描述域的前缀(“logs”)、传入文档中设置的环境名称、当前年份以明确时间维度,最后是执行日志轮换的零填充增量数字。例如,生成的名称为logs-prod-2021-000001
、logs-prod-2020-002035
、logs-stg-2021-000048
。
日志索引策略所需的最后一条信息是_rotation policy_。 Elasticsearch 提供了一个称为rollover的功能,它在满足指定条件时为目标别名创建一个新的后备索引。可用的翻转条件基于索引年龄、大小、文档数量或这三者的组合。新后备索引的名称是名称模式最后一部分的单位增量 - 例如,logs-prod-2021-000001
->logs-prod-2021-000002
。为了自动翻转,我们可以创建一个索引生命周期管理(ILM) 策略来告诉 Elasticsearch 哪些操作在索引生命周期的每个阶段执行。查看 Elastic 文档中的教程:使用 ILM自动翻转以了解更多详细信息。
回到我们的第一个日志索引策略,我们希望在以下情况下轮换日志索引:
-
超过三个月,因为它们不再被主动搜索并且可以移动到性能较低的节点,或者
-
大于 50GB。
实施细节
应用索引策略 S1 的步骤如下:
- 在 Elasticsearch 中创建 ILM 策略 (“ilm_s1”) 以指定所需的翻转条件。
PUT es_hostname:9200/_ilm/policy/ilm_s1
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_primary_shard_size": "50GB",
"max_age": "3M"
}
}
}
}
}
}
进入全屏模式 退出全屏模式
- 配置 Logstash 管道的 Elasticsearch 输出插件以 (i) 应用上述 ILM 策略,(ii) 定义索引别名和 (iii) 索引名称模式。例如,对于生产日志:
elasticsearch {
hosts => ["es_hostname"]
...
ilm_rollover_alias => "logs-prod"
ilm_pattern => "{now/y}-000001"
ilm_policy => "ilm_s1"
}
进入全屏模式 退出全屏模式
因为ilm_rollover_alias
不支持动态变量替换(即能够将诸如host.env
之类的字段的动态值设置为字符串模板的能力),所以我们必须为每个已知环境创建一个输出配置并使用 IF- 控制它们的应用ELSE 语句。
`output {
if [host.env] == "prod" {
elasticsearch {
ilm_rollover_alias => "logs-prod"
...
}
} else if [host.env] == "stg" {
elasticsearch {
ilm_rollover_alias => "logs-stg"
...
}
} else ...
}`
进入全屏模式 退出全屏模式
不理想,对吧?
评估
日志索引策略 S1 的优点:
-
直接实施。
-
支持复杂的日志轮换策略,这要归功于 Elasticsearch 输出插件和 ILM 之间的集成。
-
少量索引和活动分片(CPU 压力低)。
缺点:
-
索引映射爆炸的风险,因为具有不同架构的日志存储在同一个索引中。这将导致更大的内存和磁盘占用以及更慢的查询。
-
索引映射的灵活性差。例如,如果要更改 Jenkins 日志的一个字段的数据类型,则必须重新索引所有其他服务的文档,因为它们存储在相同的环境范围索引中。
-
针对在同一环境中运行的所有服务的一个 ILM 策略和翻转策略。假设您必须将 Nginx 身份验证日志保留 5 年以确保安全合规。如果没有临时清理例程来删除过时的文档(不是最佳实践),您还必须在磁盘上保留保留期较短的服务日志。
-
Elasticsearch 输出插件配置中的样板和重复项,需要手动和繁琐的维护。
-
从一项服务收集的日志数量激增(例如,在事件期间,启用调试日志记录时)可能会超出目标索引的索引容量并导致数据丢失。
S2:按服务和环境分组 - 按年龄轮换
在上一节介绍了所有重要概念之后,第二种日志索引策略的介绍会更快。我保证。在策略 S2 中,我们为每个环境和服务引入了专用索引,以克服将异构服务日志放入同一索引的缺点。实现这一点的最简单方法是每月创建环境服务索引以强制执行时间日志轮换,并将 JSON 文档路由到相关索引。生成的索引将命名为logs-prod-jenkins-2021.03
或logs-dev-nginx-2020.12
。
实施细节
要应用索引策略 S2,只需在 Elasticsearch 输出插件“index”属性中指定所需的索引模式即可,该属性将根据host.env
和service.name
字段的值动态生成目标索引名称。
elasticsearch {
hosts => ["es_hostname"]
index => "logs-%{host.env}-%{service.name}-%{+yyyy.MM}"
...
}
进入全屏模式 退出全屏模式
请注意,Logstash 使用Joda 格式从当前时间戳中提取时间值(例如,yyyy
提取年份,MM
提取月,ww
提取周......)。每月轮换策略完全由上面的索引模式强制执行 - 不需要 Elasticsearch 轮转功能。
假设您要将 ILM 策略应用于特定环境或服务。在这种情况下,您必须在 Elasticsearch 中创建 ILM 策略,然后将该策略添加到将匹配正确索引名称模式的索引模板。
PUT es_hostname:9200/_ilm/policy/ilm_s2_dev_logs
{
"policy": { ... }
}
PUT es_hostname:9200/_ilm/policy/ilm_s2_prod_jenkins_logs
{
"policy": { ... }
}
PUT es_hostname:9200/_index_template/dev_logs
{
"index_patterns": ["logs-dev-*"],
"template": {
"settings": {
"index.lifecycle.name": "ilm_s2_dev_logs"
},
...
},
"priority": 201
}
PUT es_hostname:9200/_index_template/jenkins_prod_logs
{
"index_patterns": ["logs-prod-jenkins-*"],
"template": {
"settings": {
"index.lifecycle.name": "ilm_s2_prod_jenkins_logs"
},
...
},
"priority": 201
}
进入全屏模式 退出全屏模式
索引模板的优先级字段允许管理重叠模式:如果一个索引匹配多个索引模板,则使用具有最高优先级的那个。因为 Elasticsearch 附带了具有匹配模式日志 -* 和优先级 200 的内置模板,所以我们需要将自定义模板的优先级设置为大于该值的任何值。
评估
日志索引策略 S2 的优点:
-
由于动态变量替换,Logstash 中的样板和重复代码更少。
-
特定于服务的索引具有更少的字段,从而导致更快的查询、提高的空间效率和更少的映射冲突风险。
-
更精细地控制 ILM 策略的分配。
-
一个分片的数据损坏只会影响一个服务的日志(爆炸半径小)。
缺点:
-
指数爆炸风险:每项服务每年新增12个指数。
-
仅支持基于年龄的翻转条件,这可能导致索引太大或太小,具体取决于相关服务的索引率。这不是对资源的有效利用,并且在 S2 设置中无法控制它。
-
Elasticsearch 输出插件的索引属性允许强制执行非常基本的年龄条件:每天、每周、每月或每年轮换,但不像策略 S1 那样 - 比如说 - 3 个月轮换。
S3的一个外壳
如何结合日志索引策略 S1(复杂的日志轮换策略,无索引爆炸风险)和 S2(对服务特定设置和行为的精细控制,改进操作,有效利用集群资源)的优点,同时尽量减少它们的缺点?这是一个很好的问题,但是对于另一篇博客文章(真糟糕!)。如果您已经有了一些想法并且迫不及待地想要分享它们,欢迎您通过elastic@kreuzwerker.de与我们联系。
图片来自Ag Ku,来自[Pixabay
更多推荐
所有评论(0)