前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linkerd 2.10(Step by Step)—使用每个路由指标调试 HTTP 应用程序

Linkerd 2.10(Step by Step)—使用每个路由指标调试 HTTP 应用程序

作者头像
为少
发布2021-07-07 11:12:31
5010
发布2021-07-07 11:12:31
举报
文章被收录于专栏:黑客下午茶黑客下午茶

Linkerd 2.10 系列

Linkerd 2.10 中文手册持续修正更新中:

  • https://linkerd.hacker-linner.com

这个演示是一个Ruby应用程序,可以帮助您管理书架。它由多个微服务组成,并通过 HTTP 使用 JSON 与其他服务通信。有三种服务:

  • webapp: 前端
  • authors: 管理系统中作者的 API
  • books: 管理系统中书籍的API

出于演示目的,该应用程序带有一个简单的流量生成器。整体拓扑如下所示:

先决条件

要使用本指南,您需要在集群上安装 Linkerd 及其 Viz 扩展。如果您还没有这样做,请按照安装 Linkerd 指南进行操作。

安装应用

首先,让我们将 books app 安装到您的集群上。在本地终端中,运行:

代码语言:javascript
复制
kubectl create ns booksapp && \
  curl -sL https://run.linkerd.io/booksapp.yml \
  | kubectl -n booksapp apply -f -

此命令为 demo 创建一个命名空间,下载其 Kubernetes 资源清单 并使用 kubectl 将其应用到您的集群。该应用程序包含在 booksapp 命名空间中 运行的 Kubernetes deployments 和 services。

第一次下载一堆容器需要一点时间。Kubernetes 可以告诉您所有服务何 时都在运行并准备好进行通信。通过运行以下命令等待它发生:

代码语言:javascript
复制
kubectl -n booksapp rollout status deploy webapp

您还可以通过运行以下命令快速查看添加到集群中的所有组件:

代码语言:javascript
复制
kubectl -n booksapp get all

部署成功完成后,您可以通过本地端口转发 webapp 访问应用程序本身:

代码语言:javascript
复制
kubectl -n booksapp port-forward svc/webapp 7000 &

在浏览器中打开 http://localhost:7000/ 以查看前端。

不幸的是,应用程序中有一个错误:如果您单击 Add Book,它有 50% 的时间会失败。这是一个典型的不明显、间歇性故障的案例——这种故障让服务所有者抓狂,因为它很难调试。Kubernetes 本身无法检测或显示此错误。从 Kubernetes 的角度来看, 看起来一切都很好,但您知道应用程序正在返回错误。

将 Linkerd 添加到服务中

现在我们需要将 Linkerd 数据平面代理添加到服务中。最简单的选择是做这样的事情:

代码语言:javascript
复制
kubectl get -n booksapp deploy -o yaml \
  | linkerd inject - \
  | kubectl apply -f -

此命令检索 booksapp 命名空间中所有部署的清单, 通过 linkerd inject 运行它们,然后使用 kubectl apply 重新应用。 linkerd inject 命令对每个资源进行注释, 以指定它们应该添加 Linkerd 数据平面代理, 当清单重新应用于集群时,Kubernetes 会执行此操作。最重要的是,由于 Kubernetes 进行滚动部署,因此应用程序始终保持运行。

调试

让我们使用 Linkerd 来发现此应用程序失败的根本原因。要查看 Linkerd 仪表板,请运行:

代码语言:javascript
复制
linkerd viz dashboard &

从命名空间下拉列表中选择 booksapp 并单击 Deployments 工作负载。您应该会看到 booksapp 命名空间中的所有部署都显示出来了。会有成功率、每秒请求数和延迟百分位数。

这很酷,但你会注意到 webapp 的成功率不是 100%。这是因为流量生成器正在提交新书。你可以自己做同样的事情,把成功率推得更低。单击 Linkerd 仪表板中的 webapp 以进行实时调试会话。

您现在应该查看 webapp 服务的详细信息视图。您会看到 webapp 正在从 traffic(负载生成器)中获取流量, 并且它有两个传出依赖项:authorsbook。一个是作者信息拉取服务,一个是图书信息拉取服务。

依赖服务中的故障可能正是导致 webapp 返回错误的原因(以及您作为用户在单击时可以看到的错误)。我们可以看到 books 服务也失败了。让我们进一步向下滚动页面, 我们将看到 webapp 正在接收的所有流量端点的实时列表。这是有趣的:

啊哈!我们可以看到,从 webapp 服务到 books 服务的入站流量在很大一部分时间都失败了。这可以解释为什么 webapp 会引发间歇性故障。让我们点击 tap (?) 图标, 然后点击开始按钮来查看实际的请求和响应流。

事实上,许多这些请求都返回 500。

诊断仅影响单一路线的间歇性问题非常容易。您现在拥有了打开详细错误报告所需的一切,该报告准确地解释了根本原因是什么。如果 books 服务是您自己的,您就知道在代码中的确切位置。

Service Profiles

为了了解根本原因,我们使用了实时流量。对于某些问题,这很好,但是如果问题是间歇性的并且发生在半夜会怎样?Service profiles 为 Linkerd 提供了有关您的服务的一些附加信息。这些定义了您正在服务的路由,除其他外,还允许在每个路由的基础上收集指标。通过 Prometheus 存储这些指标,您将能够睡个好觉并在早上查找间歇性问题。

获取 service profiles 设置的最简单方法之一是使用现有的 OpenAPI (Swagger) 规范。此 demo 已发布其每项服务的规范。您可以通过运行以下命令为 webapp 创建 service profile:

代码语言:javascript
复制
curl -sL https://run.linkerd.io/booksapp/webapp.swagger \
  | linkerd -n booksapp profile --open-api - webapp \
  | kubectl -n booksapp apply -f -

这个命令会做三件事:

  1. 获取 webapp 的 swagger 规范。
  2. 获取规范并使用 profile 命令将其转换为服务配置文件。
  3. 将此配置应用于集群。

除了 installinjectprofile 也是一个纯文本操作。查看生成的配置文件:

代码语言:javascript
复制
apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
  creationTimestamp: null
  name: webapp.booksapp.svc.cluster.local
  namespace: booksapp
spec:
  routes:
  - condition:
      method: GET
      pathRegex: /
    name: GET /
  - condition:
      method: POST
      pathRegex: /authors
    name: POST /authors
  - condition:
      method: GET
      pathRegex: /authors/[^/]*
    name: GET /authors/{id}
  - condition:
      method: POST
      pathRegex: /authors/[^/]*/delete
    name: POST /authors/{id}/delete
  - condition:
      method: POST
      pathRegex: /authors/[^/]*/edit
    name: POST /authors/{id}/edit
  - condition:
      method: POST
      pathRegex: /books
    name: POST /books
  - condition:
      method: GET
      pathRegex: /books/[^/]*
    name: GET /books/{id}
  - condition:
      method: POST
      pathRegex: /books/[^/]*/delete
    name: POST /books/{id}/delete
  - condition:
      method: POST
      pathRegex: /books/[^/]*/edit
    name: POST /books/{id}/edit

name 指的是你的 Kubernetes 服务的 FQDN, 在这个实例中 webapp.booksapp.svc.cluster.local。Linkerd 使用请求的 Host 头将服务配置文件与请求相关联。当代理看到 webapp.booksapp.svc.cluster.localHost 头时, 它将使用它来查找服务配置文件的配置。

路由是包含方法(例如 GET)和匹配路径的正则表达式的简单条件。这允许您将 REST 风格的资源组合在一起,而不是看到一个巨大的列表。路由的名称可以是您喜欢的任何名称。对于此 demo,该方法附加到路由正则表达式。

要获取 authorsbooks 的配置文件,您可以运行:

代码语言:javascript
复制
curl -sL https://run.linkerd.io/booksapp/authors.swagger \
  | linkerd -n booksapp profile --open-api - authors \
  | kubectl -n booksapp apply -f -
curl -sL https://run.linkerd.io/booksapp/books.swagger \
  | linkerd -n booksapp profile --open-api - books \
  | kubectl -n booksapp apply -f -

当您使用 linkerd viz tap 时,很容易验证这一切是否有效。每个实时请求都会显示正在看到的 :authorityHost 标头以及正在使用的 :pathrt_route。运行:

代码语言:javascript
复制
linkerd viz tap -n booksapp deploy/webapp -o wide | grep req

这将观察流经 webapp 的所有实时请求,看起来像:

代码语言:javascript
复制
req id=0:1 proxy=in  src=10.1.3.76:57152 dst=10.1.3.74:7000 tls=true :method=POST :authority=webapp.default:7000 :path=/books/2878/edit src_res=deploy/traffic src_ns=booksapp dst_res=deploy/webapp dst_ns=booksapp rt_route=POST /books/{id}/edit

As you can see:

  • :authority 是正确的 host
  • :path 正确匹配
  • rt_route 包含 route 名称

这些指标是 linkerd viz routes 命令的一部分, 而不是 linkerd viz stat。要查看到目前为止累积的指标,请运行:

代码语言:javascript
复制
linkerd viz -n booksapp routes svc/webapp

这将输出所有观察到的路由及其黄金指标的表。 [DEFAULT] 路由是所有与服务配置文件不匹配的所有内容。

配置文件可用于观察传出(outgoing)请求以及传入(incoming)请求。为此,请运行:

代码语言:javascript
复制
linkerd viz -n booksapp routes deploy/webapp --to svc/books

这将显示源自 webapp deployment 并发往 books 服务的所有请求和路由。与在调试部分使用 taptop 视图类似,此 demo 中错误的根本原因很明显:

代码语言:javascript
复制
ROUTE                     SERVICE   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
DELETE /books/{id}.json     books   100.00%   0.5rps          18ms          29ms          30ms
GET /books.json             books   100.00%   1.1rps           7ms          12ms          18ms
GET /books/{id}.json        books   100.00%   2.5rps           6ms          10ms          10ms
POST /books.json            books    52.24%   2.2rps          23ms          34ms          39ms
PUT /books/{id}.json        books    41.98%   1.4rps          73ms          97ms          99ms
[DEFAULT]                   books         -        -             -             -             -

重试

由于更新代码和推出新版本可能需要一段时间,让我们告诉 Linkerd 它可以重试对失败端点的请求。这会 增加请求延迟,因为请求将被多次重试,并不需要推出新版本。

在这个应用中,从 books deployment 到 authors service 的请求成功率很低。要查看这些指标,请运行:

代码语言:javascript
复制
linkerd viz -n booksapp routes deploy/books --to svc/authors

输出应如下所示:

代码语言:javascript
复制
ROUTE                       SERVICE   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
DELETE /authors/{id}.json   authors         -        -             -             -             -
GET /authors.json           authors         -        -             -             -             -
GET /authors/{id}.json      authors         -        -             -             -             -
HEAD /authors/{id}.json     authors    50.85%   3.9rps           5ms          10ms          17ms
POST /authors.json          authors         -        -             -             -             -
[DEFAULT]                   authors         -        -             -             -             -

有一点很清楚,从书籍到作者的所有请求都发送到 HEAD /authors/{id}.json 路由, 并且这些请求在大约 50% 的时间内失败。

为了更正这个问题,让我们编辑 authors 服务配置文件并使那些请求可重试,运行以下命令:

代码语言:javascript
复制
kubectl -n booksapp edit sp/authors.booksapp.svc.cluster.local

您需要将 isRetryable 添加到特定路由。它应该看起来像:

代码语言:javascript
复制
spec:
  routes:
  - condition:
      method: HEAD
      pathRegex: /authors/[^/]*\.json
    name: HEAD /authors/{id}.json
    isRetryable: true ### ADD THIS LINE ###

编辑服务配置文件后,Linkerd 将开始自动重试对该路由的请求。我们可以看到通过运行以下命令:

代码语言:javascript
复制
linkerd viz -n booksapp routes deploy/books --to svc/authors -o wide

这应该是这样的:

代码语言:javascript
复制
ROUTE                       SERVICE   EFFECTIVE_SUCCESS   EFFECTIVE_RPS   ACTUAL_SUCCESS   ACTUAL_RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
DELETE /authors/{id}.json   authors                   -               -                -            -             -           0ms
GET /authors.json           authors                   -               -                -            -             -           0ms
GET /authors/{id}.json      authors                   -               -                -            -             -           0ms
HEAD /authors/{id}.json     authors             100.00%          2.8rps           58.45%       4.7rps           7ms          25ms          37ms
POST /authors.json          authors                   -               -                -            -             -           0ms
[DEFAULT]                   authors                   -               -                -            -             -           0ms

你会注意到 -o wide 标志在 routes 视图中添加了一些列。这些显示了 EFFECTIVE_SUCCESSACTUAL_SUCCESS 之间的区别。这两者之间的差异表明重试的效果如何。 EFFECTIVE_RPSACTUAL_RPS 显示有多少请求被发送到目标服务, 以及有多少请求被客户端的 Linkerd 代理接收。

现在自动重试,成功率看起来不错,但 p95 和 p99 延迟增加了。这是可以预料的,因为重试需要时间。

超时

Linkerd 可以限制在传出请求到另一个服务失败之前等待的时间。这些超时通过向服务配置文件的路由配置添加另一个 key 来工作。

首先,让我们看一下从 webappbooks 服务的请求的当前延迟:

代码语言:javascript
复制
linkerd viz -n booksapp routes deploy/webapp --to svc/books

这应该类似于:

代码语言:javascript
复制
ROUTE                     SERVICE   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
DELETE /books/{id}.json     books   100.00%   0.7rps          10ms          27ms          29ms
GET /books.json             books   100.00%   1.3rps           9ms          34ms          39ms
GET /books/{id}.json        books   100.00%   2.0rps           9ms          52ms          91ms
POST /books.json            books   100.00%   1.3rps          45ms         140ms         188ms
PUT /books/{id}.json        books   100.00%   0.7rps          80ms         170ms         194ms
[DEFAULT]                   books         -        -             -             -             -

books 服务的 PUT /books/{id}.json 路由的请求包括当该服务调用 authors 服务 作为服务这些请求的一部分时的重试,如上一节所述。这以额外的延迟为代价提高了成功率。出于本 demo 的目的,让我们为对该路由的调用设置 25 毫秒超时。您的延迟数字将根据集群的特征而有所不同。要编辑 books 服务配置文件,请运行:

代码语言:javascript
复制
kubectl -n booksapp edit sp/books.booksapp.svc.cluster.local

更新 PUT /books/{id}.json 路由以设置超时:

代码语言:javascript
复制
spec:
  routes:
  - condition:
      method: PUT
      pathRegex: /books/[^/]*\.json
    name: PUT /books/{id}.json
    timeout: 25ms ### ADD THIS LINE ###

Linkerd 现在将在达到超时时将错误返回给 webapp REST 客户端。此超时包括重试请求,并且是 REST 客户端等待响应的最长时间。

运行 routes 以查看发生了什么变化:

代码语言:javascript
复制
linkerd viz -n booksapp routes deploy/webapp --to svc/books -o wide

现在发生超时,指标将发生变化:

代码语言:javascript
复制
ROUTE                     SERVICE   EFFECTIVE_SUCCESS   EFFECTIVE_RPS   ACTUAL_SUCCESS   ACTUAL_RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
DELETE /books/{id}.json     books             100.00%          0.7rps          100.00%       0.7rps           8ms          46ms          49ms
GET /books.json             books             100.00%          1.3rps          100.00%       1.3rps           9ms          33ms          39ms
GET /books/{id}.json        books             100.00%          2.2rps          100.00%       2.2rps           8ms          19ms          28ms
POST /books.json            books             100.00%          1.3rps          100.00%       1.3rps          27ms          81ms          96ms
PUT /books/{id}.json        books              86.96%          0.8rps          100.00%       0.7rps          75ms          98ms         100ms
[DEFAULT]                   books                   -               -                -            -             -

延迟数字包括在 webapp 应用程序本身中花费的时间, 因此预计它们会超过我们为从 webappbooks 的请求设置的 25 毫秒超时。我们可以通过观察路由的有效成功率下降到 100% 以下来看到超时正在起作用。

清理

要从集群中删除 books 应用程序和 booksapp 命名空间,请运行:

代码语言:javascript
复制
curl -sL https://run.linkerd.io/booksapp.yml \
  | kubectl -n booksapp delete -f - \
  && kubectl delete ns booksapp
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 黑客下午茶 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Linkerd 2.10 系列
  • 先决条件
  • 安装应用
  • 将 Linkerd 添加到服务中
  • 调试
  • Service Profiles
  • 重试
  • 超时
  • 清理
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档