博客/工程

Loki:普罗米修斯式的,云原生的开源日志记录

2018年12月12日8分钟

洛基

简介

这篇博客文章是我在https://devopsdaysindia.org.我将讨论Grafana中日志的动机、架构和未来!让我们开始吧。你可以在这里看到演讲的幻灯片:https://speakerdeck.com/gouthamve/devopsdaysindia-2018-loki-prometheus-but-for-logs

动机

Grafana实际上是时间序列数据的仪表板解决方案。它支持超过40个数据源(在撰写本文时),而且仪表盘的故事已经相当成熟,增加了许多新功能,包括团队和文件夹。我们现在想要从仪表板解决方案转变为可观察平台,当您需要调试系统时,它将成为您的首选。

完整的可观测性

可观察性。关于这意味着什么,有很多定义。对我来说,可观察性是对系统及其行为和执行的可见性。我非常喜欢将可观察性分为3个部分(或支柱)的模型:度量、日志和轨迹;彼此赞美对方,帮助你快速找到问题所在。

下面的例子说明了我是如何处理工作中的突发事件的:我如何处理事件

普罗米修斯给我发送了一个警告,说有什么地方出错了,我打开了相关的仪表板。如果我发现一个面板或图形异常,我将在Grafana的new中打开查询探索界面为了更深入的潜水。例如,如果我发现其中一个服务抛出了500个错误,我将尝试弄清楚是某个特定的处理程序/路由抛出了该错误,还是所有实例都抛出了该错误,等等。

接下来,一旦我对哪里出了问题或哪里出了问题有了一个模糊的心理模型,我就会查看日志。Pre Loki,我以前用过kubectl获取相关日志,看看错误是什么,以及我是否可以做些什么。这对于错误非常有效,但有时由于高延迟,我会被分页。在这种情况下,我从跟踪中获得了关于什么很慢以及哪个方法/操作/函数很慢的更多信息。我们使用Jaeger来获取痕迹。

虽然这些并不总是直接告诉我哪里出了问题,但它们通常会让我足够近地查看代码并找出哪里出了问题。然后,我可以扩展服务(如果服务过载)或部署修复程序。

日志记录

普罗米修斯做得很好,Jaeger也快到了,kubectl也不错。标签模型足够强大,可以让我深入了解错误服务的根源。如果我发现ingester服务出错,我会这样做:kubectl——namespace prod logs -l name=ingester | grep XXX . txt获取相关日志并通过它们进行grep。

如果我发现一个特定的实例出错,或者如果我想跟踪一个服务的日志,我必须使用单独的pod来跟踪,因为kubectl不允许你基于标签选择器跟踪。这不是理想的,但对于大多数用例都是可行的。

这是有效的,只要吊舱不崩溃或不被替换。如果pod或节点被终止,日志将永远丢失。此外,kubectl只存储最近的日志,所以当我们想要前一天或更早的日志时,我们是盲目的。此外,必须从Grafana跳转到CLI,然后再返回,这并不理想。我们需要一个减少上下文切换的解决方案,而我们探索的许多解决方案都非常昂贵,或者伸缩性不太好。bob彩票中奖计划

这是预期的,因为他们做的远远超过select + grep,这基本上是我们需要的。在研究了现有的解决方案后,我们决定建立自己的解决方案bob彩票中奖计划。

洛基

由于对任何开源解决方案都不满意,我们开始与人们交谈,并注意到很多人都有同样的bob彩票中奖计划问题。事实上,我已经意识到,即使在今天,许多开发人员仍然在机器上使用SSH和grep/tail跟踪日志!他们使用bob彩票中奖计划的解决方案要么太贵,要么不够稳定。事实上,人们被要求记录更少的日志,我们认为这是日志的反模式。我们认为我们可以在内部构建一些东西,让更广泛的开源社区可以使用。我们有一个主要目标:

  • 保持简单。只支持grep!

保持简单。只支持grep!

这条推文来自@alicegoldfuss这只能说明洛基试图解决的问题

  • 我们还瞄准了其他内容:
    • 原木应该便宜。任何人都不应该被要求减少日志记录。
    • 易于操作和规模化
    • 度量、日志(以及后续的跟踪)需要一起工作

最后一点很重要。我们已经在收集元数据普罗米修斯我们想用它来计算对数相关性。例如,Prometheus用名称空间、服务名、实例ip等标记每个度量。当我收到警报时,我使用元数据来确定在哪里查找日志。如果我们设法用相同的元数据标记日志,我们就可以在指标和日志之间无缝切换。你可以看到我们写的内部设计文件在这里.下面是洛基的演示视频:

洛基——普罗米修斯的灵感,云原生的开源日志。

体系结构

凭借我们的建设和运营经验皮质水平可扩展的,分布式版本的Prometheus,我们作为一个服务运行-我们提出了以下架构:

日志记录架构!

指标和日志匹配之间的元数据对我们来说至关重要,我们最初决定只针对Kubernetes。我们的想法是在每个节点上运行一个日志收集代理,使用它收集日志,与kubernetes API对话,找出日志的正确元数据,并将它们发送到中央服务,我们可以使用该服务来显示在Grafana中收集的日志。

代理支持与Prometheus相同的配置(重新贴标签规则),以确保元数据匹配。我们称这个特工为promtail。

进入Loki,可伸缩的日志收集引擎。日志记录架构!

写路径和读路径(查询)彼此是相当分离的,它有助于分别讨论它们。洛基:架构!

经销商

promtail收集并将日志发送给Loki后,分发器是第一个接收它们的组件。现在我们可能每秒接收数百万次写入,我们不想在它们进入时就将它们写入数据库。那会毁了所有的数据库。我们需要批处理和压缩传入的数据。

我们通过构建压缩的数据块来做到这一点,通过gzip日志来实现。摄取器组件是一个有状态的组件,负责构建数据块,然后刷新数据块。我们有多个摄取器,属于每个流的日志应该总是在相同的摄取器中结束,以便所有相关的条目都在相同的块中结束。我们通过构建一个摄取器环并使用一致的哈希来做到这一点。当条目进入时,分发服务器对日志标签进行散列,然后根据散列值查找要将条目发送到哪个摄取器。洛基:经销商

此外,为了冗余和弹性,我们复制了n(默认为3)次。

摄取

现在,摄取器将接收条目并开始构建块。洛基:摄取

这基本上是gzip日志并附加它们。一旦数据块“填满”,我们将其刷新到数据库。我们为块(ObjectStorage)和索引使用单独的数据库,因为它们存储的数据类型不同。

一旦数据块“填满”,我们将其刷新到数据库

在刷新一个块之后,摄取器然后创建一个新的空块,并将新条目添加到该块中。

查询器

读取路径非常简单,大部分繁重的工作都由查询器完成。给定一个时间范围和标签选择器,它将查看索引以找出匹配的数据块,并通过它们进行grep以给出结果。它还与摄取器对话以获得尚未刷新的最近数据。

请注意,现在对于每个查询,都有一个查询器greps所有相关日志。我们已经在Cortex中使用前端实现了查询并行化,同样也可以扩展到Loki,以提供分布式的grep,这将使即使是大型查询也足够灵活。

洛基:看看询问者

可伸缩性

现在我们来看看这个是否成比例。

  1. 我们将数据块放入对象存储中,然后进行缩放。
  2. 我们把索引放到Cassandra/Bigtable/DynamoDB中,它也可以伸缩。
  3. 分发器和查询器是无状态组件,可以横向扩展。

说到摄取器,它是一个有状态的组件,但我们已经在其中构建了完整的分片和重分片生命周期。当完成滚出或当摄取器放大或缩小时,环形拓扑会发生变化,摄取器会重新分配它们的块以匹配新的拓扑。这些代码大多来自于已经在生产环境中运行了2年多的Cortex。

警告

虽然所有这些都在概念上可行,但随着我们的发展,我们预计会遇到新的问题和限制。它的运行成本应该非常低,因为所有的数据都位于S3这样的对象存储中。但你只能通过这些数据进行浏览。这可能不适合其他用例,如警报或构建仪表板,您最好在指标中进行这些操作。

结论

Loki是一个非常alpha的软件,不应该在生产环境中使用。我们希望尽快宣布并发布Loki,以获得来自社区的反馈和贡献,并找出哪些是有效的,哪些需要改进。我们相信这将帮助我们在明年发布更高质量和更准确的产品。

洛基可以在预存中运行,也可以在Grafana Cloud上作为免费演示版本运行。我们强烈建议你试一试,给我们写信,让我们知道你的想法。参观洛基主页从今天开始。