博客/工程

使用foobar开始使用分布式跟踪和Grafana Tempo,这是一个用Python编写的演示

2021年5月4日5分钟

Daniel是一名站点可靠性工程师k6.io.他对可观察性、分布式系统和开源尤其感兴趣。在他的空闲时间,他帮助维护Grafana节奏,一个易于使用的,高规模的分布式跟踪后端。

分布式跟踪是一种通过应用程序跟踪请求路径的方法。当您在处理微服务体系结构时,它特别有用。但是开始使用它可能很困难:您必须配置服务、摄取跟踪数据、将所有跟踪存储在某个地方、选择跟踪发现方法,并祈祷一切都能协同工作。此外,您还必须向团队的其他成员解释这个新东西是如何工作的,以及如何有效地使用它。

这就是我建造的原因foobar这是一个用Python编写的小型微服务应用程序,它包含了开始使用分布式跟踪所需的所有内容。

在这篇博文中,我们将尝试使用foobar并排除一些(完全)意想不到的问题。

开始

foobar演示由两个部分组成复杂的服务:foo和bar。

这两个服务都是用Python编写的,都使用OpenTelemetry进行检测,并使用OTLP gRPC出口商将跟踪发送到OpenTelemetry收集器。这个Collector将跟踪导出到Grafana Tempo,并且我们可以使用Tempo数据源从Grafana查询我们的跟踪数据。

在本地运行

如果你想跟随,确保你已经安装了Docker和Docker Compose。

让我们从克隆回购开始:

➜git克隆https://github.com/dgzlopes/foobar-demo;cd foobar-demo

然后我们将安装并运行整个设置:

➜docker-compose up——build -d #(这将花费一些时间)

就是这样!我们需要的都有了。现在我们要检查foobar是否正常运行。我们有两种方法可以做到这一点:

  1. 卷发:跑步curl http://localhost: 5000 / foo
  2. 使用浏览器:转到http://localhost:5000/foo

无论哪种方式,响应都应该是相同的:foobar。哈!

找到一些痕迹

这毕竟是一个跟踪教程,对吧?让我们找一些痕迹。

目前,在Tempo上查找跟踪的唯一方法是了解trace_id,这是每个跟踪所具有的唯一ID。我们将使用Docker Compose CLI查询foo服务的日志,然后我们将使用grep查找trace_ids:

➜docwalker -compose logs foo | grep trace_id foo_1 | time=" 21004-18 09:08:26,543" service=foo level=INFO addr="172.19.0.1" method=GET scheme=http path="/foo?" status=200 trace_id=5ac85e3e517f7ff62ac5aaaacccfabe8 foo_1 | time=" 21004-18 09:08:26,545" service=foo level=INFO addr="172.19.0.1" method=GET scheme=http path="/foo?" status=200 trace_id=9e38679e1782a593eb60c3375496467b foo_1 | time=" 21004-18 09:08:26,545" service=foo level=INFO addr="172.19.0.1" method=GET scheme=http path="/foo?"= 200 trace_id = 61 b93a71bf42369c988930847ba12381地位

选择其中一个,转到Grafana (http://localhost:3000) -> Explore -> Tempo,粘贴trace_id,然后单击Run Query。您应该在屏幕上看到完整的跟踪显示!

要进一步

我们通过Curl(和/或浏览器)检查了foobar是否正常工作,但这还不够。我们应该做个冒烟测试。

冒烟测试

冒烟测试是一种常规负载测试,配置为最小负载,当您希望验证系统在最小负载下不会抛出任何错误时,运行该测试非常有用。

为了进行冒烟测试,我们将使用转k6这是一个开源的负载测试工具,它允许我们使用JavaScript将测试创建为代码。我们的测试是这样的:

从“k6/ HTTP”导入HTTP;从'k6'导入{check, sleep};导出let选项= {vus: 5,持续时间:'20s',};导出默认函数(){let res = http.get('http://foo:5000/foo');Check (res, {'is status 200': (r) => r.status === 200, 'returns foobar': (r) => r.body == "foobar",});睡眠(1);}

这个测试将使用5个虚拟用户运行20秒,它将向我们的foo端点发出HTTP GET请求。此外,它还会检查响应状态是否为200并且主体是否为foobar。

为了运行测试,我们将使用k6 Docker映像:

Docker运行-i——network=foobar-demo_default loadimpact/k6运行——quiet -

测试完成后,k6为我们提供了测试运行期间发生的事情的总结,我们可以看到一些……意料之外的东西。有些检查失败了!呵。

故障排除

让我们保持冷静,试着弄清楚发生了什么事。

我们知道有时候状态码不是200,对吧?然后我们可以查看foo服务的日志,并使用grep查找与异常请求(status!=200)匹配的日志:

➜docer -compose logs foo | grep trace_id | grep -v status=200 foo_1 | time=" 21021-04-18 10:28:11,142" service=foo level=INFO addr="172.19.0.7" method=GET scheme=http path="/foo?" status=500 trace_id=b9e61bb959353927062acf99ed0b2de2 foo_1 | time=" 21021-04-18 10:28:16233 " service=foo level=INFO addr="172.19.0.7" method=GET scheme=http path="/foo?" status=500 trace_id=ae6ed04f4aa4244065fb04955fdcc9af .

一旦我们有了这些有问题的请求的日志行,我们就可以从其中一个中选择trace_id,并在Grafana中打开跟踪,如我们前面所示。

如您所见,这里有一些感叹号。不是很好!深入研究跨度,我们可以看到foo向bar发出的请求返回一个500状态码。

所以可以肯定地说,这个问题与酒吧服务和它的运作方式有关。没错!这段代码是酒吧服务代码的一部分:

@app.route("/bar") def bar(): random_value = random() #范围[0.0,1.0]内的随机数,如果random_value < 0.05:返回"Edge case!", 500返回"bar"

看起来这个服务被编码为随机失败…这是一个怎样的设计决策。

我们应该把它去掉。:)

结束

在这篇博文中,我们对foobar进行了一些尝试,并在分布式跟踪和k6的帮助下发现了一些奇怪的行为。如果您想了解更多关于分布式跟踪的知识,请查看之前的博客文章,”分布式跟踪的初学者指南.”

如果k6听起来很有趣,看看我们的文档Github库

如果你觉得Tempo看起来很酷,看看"追踪与格拉夫纳节拍的开始"网络研讨会在需求。你可以获得免费的开放测试访问TempoGrafana云.我们有免费和付费的Grafana Cloud计划,以适应每个用例-现在就免费注册