Service Profiles for Per-Route Metrics

内容摘要自: Service Profiles for Per-Route Metrics,这里介绍了service profile在每route的metrics中的使用。

Linkerd的主要目标之一是使服务和平台所有者能够理解他们的服务:不仅在数据包和字节方面,而且在请求和响应方面。对于HTTP等协议,这需要了解协议的语义,以便Linkerd可以测量成功率和响应延迟等内容。我们还需要能够在不同维度(例如源服务,目标服务和HTTP路径)中分解这些指标。

但是,通过路径聚合指标尤其会带来一些重大挑战。在这篇文章中,我们将探讨这些挑战,并展示Linkerd如何使用称为service profile的新概念来处理它们。

第一次尝试

将成为Linkerd 2.0的最早版本(当它被称为Conduit时)实际上具有开箱即用的每路径指标:

这个功能非常有用,但是有一个很大的问题。Conduit 将所有指标存储在Prometheus中,使用Prometheus lable 存储数据的所有不同维度,例如service,deployment和path。Path的Prometheus label 意味着每条独特的 Path 都会在 Prometheus 中创建新的时间序列。由于Conduit无法控制它收到的请求,因此Prometheus很容易被无限数量的唯一Path所导致的无数的时间序列所淹没。事实上,Prometheus的文档包括对这个问题的警告!虽然这个早期版本向我们展示了这个功能有多棒,但我们最终还是如此决定删除Path label,以确保在Linkerd中,Prometheus可以继续表现良好。

Linkerd Top

“别急!”你可能会说,“linkerd top命令呢?这不是显示每个路径的指标吗?”你是对的,确实如此!

linkerd top命令通过完全避开Prometheus来回避时间序列的基数问题。它直接使用实时流量流(使用和linkerd tap相同的机制)并在内存中进行每路径聚合。这有一些非常强大的优势:

  • 由于结果是直接从实时流量计算的,因此数据是真实的。没有等待指标被抓取和聚合的延迟。
  • 没有让Prometheus爆炸的担忧。

当然,这种方法也有一些缺点:

  • 没有时间序列意味着没有历史数据。仅限实时数据。
  • 在高流量速率下,可能对实时业务流进行采样。这意味着,数据的在linkerd top被不能保证代表请求的100%,并且不应该被认为是100%精确的。

尽管如此,linkerd top仍然是一个非常有用的工具,可以快速了解实时流量的表现。

烦人的路径参数问题

对于每路径的metrics,还有一个主要问题,不管是基于普罗米修斯还是基于实时流量的方法。看看你能否在这个截图中找到它:

当路径中包含参数(如用户名或ID)时,通常没有必要单独计算每个路径的度量。通常需要的是为一组相似路径聚合在一起的指标。在上面的截图中,我们很想看到的是 /books/* 的指标。在Linkerd中,我们将一组路径称为 route。

service profile

Linkerd 2.1引入了service profile的概念。service profile是自定义Kubernetes资源,它部署在Linkerd控制平面命名空间中,并允许运维为Linkerd提供有关服务的其他信息。特别是,它允许您定义服务的route列表。每个route使用正则表达式来定义哪些路径应与该route匹配。我们来看一个定义2个route的service profile示例。

apiVersion: linkerd.io/v1alpha1
kind: ServiceProfile
metadata:
  name: webapp.default.svc.cluster.local
  namespace: linkerd
spec:
  routes:
  - name: '/books' # This is used as the value for the rt_route label
    condition:
      method: POST
      pathRegex: '/books'
  - name: '/books/{id}' # This is used as the value for the rt_route label
    condition:
      method: GET
      pathRegex: '/books/\d+'

Service Profile中的每个route都包含name和condition。Condition与Method匹配,并使用正则表达式匹配Path。匹配route的请求将 rt_routePrometheus 标签设置为route名称。

通过要求在service profile中手动定义route,Linkerd能够解决以前方法的许多问题:

  • Path 以用户定义的方式聚合,可以匹配应用程序的语义。
  • Route 必须显式配置,因此route的数量(和时间序列的数量)是有限的。
  • 不需要对route度量进行采样,并且在度量的计算中计算每个请求。
  • Route度量在Prometheus 中存储为时间序列数据,因此可以在事后查询历史数据。

让我们来看一个端到端的例子。

每Route Metrics示例

以下是一个快速示例,您可以在家中尝试使用Linkerd获取每个路由指标是多么容易。首先将Linkerd和我们的示例Books应用程序安装到您的Kubernetes集群中。

linkerd install | kubectl apply -f -
linkerd check
curl https://run.linkerd.io/booksapp.yml | linkerd inject - | kubectl apply -f -

此时,Books应用程序已安装并从内置流量生成器接收流量。我们希望看到 webapp 服务 每route metrics - 但我们不能,因为我们还没有定义该服务的任何route呢!

$ linkerd routes svc/webapp
ROUTE       SERVICE   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
[UNKNOWN]    webapp    70.00%   5.7rps          34ms         100ms         269ms

我们可以看到 webapp 服务有流量但除此之外看不到其他。让我们通过使用 linkerd profile 命令创建service profile来解决这个问题。

$ linkerd profile --template webapp > webapp-profile.yaml

linkerd profile --template 命令生成基本service profile规范,您可以编辑该规范以定义所需的路由。让我们编辑webapp-profile.yaml为以下内容:

### ServiceProfile for webapp.default ###
apiVersion: linkerd.io/v1alpha1
kind: ServiceProfile
metadata:
  name: webapp.default.svc.cluster.local
  namespace: linkerd
spec:
  routes:
  - name: '/books' # This is used as the value for the rt_route label
    condition:
      method: POST
      pathRegex: '/books'
  - name: '/books/{id}' # This is used as the value for the rt_route label
    condition:
      method: GET
      pathRegex: '/books/\d+'

此服务描述了 webapp 服务响应的两个 route,/books 以及/books/<id>。我们通过 kubectl apply添加服务配置文件:

$ kubectl apply -f webapp-profile.yaml

在大约一分钟内(Prometheus定期从代理中收集指标)每route metrics将可用于该服务:

$ linkerd routes svc/webapp
ROUTE         SERVICE   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
/books/{id}    webapp   100.00%   0.3rps          26ms          75ms          95ms
/books         webapp    56.25%   0.5rps          25ms         320ms         384ms
[UNKNOWN]      webapp    79.14%   4.6rps          29ms         165ms         193ms

现在我们可以轻松地看到每条route的成功率,每秒请求数和延迟,并且我们避免了有关时间序列基数的任何问题。成功!我们还可以看到有些请求与我们定义的任何route都不匹配,这表明我们可能需要添加更多route定义。

结论

在这篇文章中,我们展示了如何通过使用Linkerd 2.1中称为service profile的新功能来为服务启用每route(也称为每path)metrics。通过向Linkerd提供有关您的服务所期望的route的一些信息,您可以超越“我的服务失败”,达到“我的服务大部分都很好,除了这个特定的调用是失败的” - 在运行时调试中向前迈出了一大步。

Service Profile不仅适用于基于route的metrics。它们还将成为 Linkerd 路线图中许多功能的基础。将来,您将能够在Service Profile和route上指定其他属性,例如可重试性,速率限制,超时等。在即将发布的Linkerd版本中查找这些功能以及更多功能!