日志记录和查询跟踪是最佳实践。Yandex报告

Yandex.Market具有大型微服务架构。Market主页上的浏览器请求在由不同人员开发的不同服务(后端)中引发了数十个嵌入式请求。在这样的系统中,可能很难理解请求由于什么原因而失败或花费很长时间来处理。


阿纳托利·奥斯特洛夫斯基(Anatoly Ostrovsky) 巨大菌解释了他的团队如何解决此问题并分享了特定于市场的实践,但通常与任何出色的服务有关。他的报告基于他自己在相当短的时间内部署新市场的经验。几年来,Tolya领导了Market中的界面开发团队,现在他已转向无人驾驶汽车的方向。

-我们所有的市场都是根据一般原则建立的。这是一个很大的单一系统。但是,如果我们谈论前端,那么从用户的角度来看,应用程序是完全不同的。



同时,我们的前端有许多后端。有时这些后端彼此相似(同一应用程序的不同实例)。有时它们是服务所独有的(特殊账单)。可以将这种系统的结构视为经典的微服务体系结构。

大型服务始终存在问题-很难理解其中到底发生了什么。或者,例如,在用户发生付款错误时发生的情况。假设昨天发生在他家,今天我们需要了解发生了什么。



后端2可以为特定产品,特定时间或特定用户“刻录”。我们需要能够应对任何情况。



我们有许多后端,而且正如我所说,它们可以自己行走。如果以图表的形式呈现,那么结果将相当混乱。在现实生活中,可能有数百种微服务。想象一下它们之间将有多少连接。

有许多步骤可以深入探讨该主题。我将简要地谈谈每个。



首先,在通用的请求标记系统上与后端的同事达成共识-以后更容易找到他们。接下来,您需要能够快速重现该问题。假设发生付款错误-尝试快速了解它是如何发生的以及在哪个后端。不仅将日志存储在文件中,而且还存储在数据库中,以便可以进行聚合。当然,过程的重要部分是图形和监视。接下来,按顺序。

统一请求识别系统




这是了解服务正在发生的事情的最简单的工具之一。与同事达成一致,例如,您的前端生成某种id-request(图片中的requestId变量),然后将其扔到后端的所有端点中。后端本身不会重新发明任何东西。他采用到达的requestId并将其进一步转发给后端。同时,他可以指定自己的前缀,以便可以在相同的requestId中找到该特定的后端。



因此,当您获取日志时,例如,确保您的日志说后端为500,则可能有两个选择。您可以将此请求ID提供给您的同事,他们将在他们的日志中查看该ID,也可以自己查看。



我们所有的日志都标记有此类ID,以便不仅了解发生了什么情况和发生在什么时刻,而且还保留了此请求的上下文。它是异步的,以后可能会在日志中添加一些内容。如果您咬到requestId,那将没有任何好处。

卷曲


要重现该问题,我们使用cURL实用程序。这是一个发出网络请求的控制台实用程序-http和https。 cURL支持更多种不同的协议,但是在进行Web开发时,更容易假设这是用于处理HTTP请求的工具。



要结识cURL团队,您可以转到任何站点,然后转到“网络”并以cURL的形式复制任何请求。结果是这么大的一行:



如果您试图弄清楚,那就没有什么可担心的了。让我们尝试将其分解。



这是对market.yandex.ru的请求。



这里添加了一个User-Agent,它占用了大量空间。



实际上,其余的是cookie。 Yandex代码中有很多。以序列化形式,它们的外观非常强大。实际上,除了它们之外没有别的。

那么cURL有什么用?如果您将其复制并自己运行,您将看到与我相同的market.yandex.ru页面-只有运行它的计算机会不同。当然,某些副作用可能会导致IP地址有所不同,但通常它们是相同的请求。我们将重现相同的情况。



为了避免每次都创建此类cURL查询,可以使用npm-package format-curl。



它接受函数通常采用的所有请求参数-即,在这种情况下,仅标头和url。但是他也知道如何查询,正文等。输出只是带有cURL请求的字符串。



因此,我们在开发环境中的所有日志也都包含cURL请求。



我们甚至直接在浏览器中记录了后端cURL请求,以立即查看我们如何进入后端,而无需查看浏览器控制台。



请注意,cURL请求涉及会话cookie的传输-这很糟糕。如果您在market.yandex.ru上向我提出了cURL请求,那么我可以登录后登录到您的Market和任何其他Yandex服务。因此,我们不会将此类请求存储在任何地方,而只能将它们自己记录在测试台中-此类数据不会泄漏。

Clickhouse


接下来,我将讨论结构化日志。在这里,我会记住特定的ClickHouse数据库,但您可以选择任何一个。 ClickHouse是一种柱状DBMS,从大量数据中进行选择并吸收大量数据更为方便。这样做的好处是,您可以在其中保存大量日志,然后例如对十亿条记录进行某种汇总。



在这种情况下,ClickHouse选择示例是纯SQL。在这里,我们显示了今天请求状态码的数量。



结果,我们将拥有18.025.75,例如,其余的状态代码对我们来说并不有趣。但是,如何才能有趣地使用它呢?



我们可以说服务级别指标是200与答案总数之比,​​它回答了我们的应用程序在状态码方面的性能问题。尽管很简单,但他已​​经在谈论一些东西。



根据我们的指标,我们可以提出第一个SLI,例如,我们的99%的请求应该可以。在这里,我们可以比较我们执行SLI的情况。如果他们还没有完成,我们本来可以尝试找出最后的请求,这些请求可能是500个,或者仅仅是关键的事情。



例如,付款错误对我们来说至关重要,但是在这种情况下,它们将返回零-很幸运:)



您如何以一种方便的方式制作日志并可以通过SQL记录日志?



这是一个单独的大型报告的主题,并且全部取决于您的基础结构。但是似乎有两种方法。第一:直接将元数据提交给运行时,直接提交给数据库。我们以第二种方式做不同的事情:我们遵循日志文件并在数据库中或在中间位置提交块。

这对我们来说是相当多层的-我们将日志从特定实例发送到此类日志的远程存储服务器。

要求追踪


没有“查询跟踪”的概念。这个词是Google创造的。



如果在Internet上搜索“查询跟踪”,则会看到traceroute命令。也许这类似于查询跟踪。



甚至还有一个控制台程序,我在这里为网站blyly.ru(我们去年春季开发的服务)执行了该程序。它有助于了解请求在到达平衡器之前将经过哪种机器和服务器,平衡器将以布局或其他方式响应。



这是我们的平衡器。通过查询跟踪,我们不是要这个意思,而是要在平衡器内部发生的一切-请求如何在我们的node.js应用程序中进一步存在。



我们以时间轴的形式看到了这一点,其中显示了水平时间,并显示了垂直的请求顺序。在这种情况下,我们有一个对产品卡的请求,可以看出这是对我们授权后端的请求。在他做出决定后,我们排了三排龙-这是向我们的主要后端要求的篮子,产品卡和类似产品。因此,我们有一个痕迹。



在这里,您看到了相同的授权请求,然后后端进入了。在这种情况下,后端的性能不是很理想,因为它对其数据库有许多连续查询。可能可以优化这种查询。



这是一个跟踪的示例,当我们不使用任何后端但立即将状态指定为500时。这样的跟踪对我们有什么用?我们不必打扰同事。我们有此请求的ID,因此我们可以自己查看日志并找出正在发生的情况。



这是相反的情况。Backend表示出了点问题,同时在元信息中记录了到底发生了什么—出现了某种堆栈跟踪。



如何使自己成为相同的工具?

这里最重要的是数据库。如果您在该服务的某些操作的数据库中拥有最简单的“ INSERT INTO”,则以后至少可以使用SQL查找必要的事件。如有必要,您可以为此接口。

图表


这是一个非常有趣的话题,今天,我将不再详细介绍它:)



让我们谈谈日志记录。我们有很多图,当我们推出某些东西时我们会看它们-并且在时间上有这样的噪音。



图表可帮助您直观地看出问题所在。然后,您仍然需要查看日志并了解它们出了什么问题。在这种情况下,释放后立即增加的浪涌至少意味着需要立即回滚此释放。

监控方式


监视是更重要的部分,并且在该主题中的沉浸度更高。通过监视,我首先了解图表的自动监视,其次了解监视某事物的任何自动规则。



我们监控每分钟响应总数与500的比率。我们还监视了四百个服务负载,检查运行状况检查旋钮,该旋钮拉动每个后端的ping旋钮,等等。



此外,我们在工作站附近的屏幕上还包含监控仪表板。因此,我们立即看到哪个监视“脸红”。例如,这里是主要的前端之一,前端和我们的主要后端可见。在这里,您可以看到后端的一些监控指示灯亮起。这意味着负责此服务的人员此时将在Telegram上收到一条消息,或者他们甚至会打电话给他-这取决于监视设置。

摘要


单个requestId可以帮助您在包含多个应用程序的服务中更轻松地发现问题。正确的cURL将使您能够更准确地重现问题并查看自己的情况,例如,将数据发送到后端。结构化日志使您可以提出SLI,并且比常规文本日志更易于使用。并且不要忘记遵循图表并进行监视。如果您对基础设施感兴趣,

建议阅读Google 的《网站可靠性工程》一书

All Articles