<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>linkerd | 伪架构师</title>
    <link>/tags/linkerd/</link>
      <atom:link href="/tags/linkerd/index.xml" rel="self" type="application/rss+xml" />
    <description>linkerd</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Fri, 12 Jul 2019 11:40:31 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>linkerd</title>
      <link>/tags/linkerd/</link>
    </image>
    
    <item>
      <title>在 Linkerd2 中进行流量拆分</title>
      <link>/post/split-traffic-in-linkerd2/</link>
      <pubDate>Fri, 12 Jul 2019 11:40:31 +0800</pubDate>
      <guid>/post/split-traffic-in-linkerd2/</guid>
      <description>&lt;p&gt;最新发布的 Linkerd 2.4，加入了对流量拆分的支持。&lt;/p&gt;

&lt;p&gt;安装最新版本之后，可以看到这个流量拆分功能所使用的 API 资源并非来自 Linkerd，而是 SMI 规范的一部分。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ curl -sL https://run.linkerd.io/install | sh
...
$ kubectl api-resources | grep -i split
trafficsplits ts split.smi-spec.io true TrafficSplit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;和 Istio 的 Service + Selector 的拆分方式不同，Linkerd 其实没有什么特别的上游定义方式，简单的定义独立的 Service 即可。例如我们要从 &lt;code&gt;flaskapp&lt;/code&gt; 服务分流到 v1 和 v2 两个版本，在 Istio 中，需要定义一个 flaskapp 服务，然后使用标签，在 Service 的标签子集中，选择两组 Subset 作为目的地。而在 Linkerd/SMI 中，就需要分别定义三个服务了，例如 flaskapp、flaskapp-v1、flaskapp-v2。下面简单操练一下。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ wget https://raw.githubusercontent.com/fleeto/istio-for-beginner/master/code/flaskapp/flaskapp.istio.yaml
$ linkerd inject flaskapp.istio.yaml | kubectl apply -f -
...
$ wget https://raw.githubusercontent.com/fleeto/istio-for-beginner/master/code/sleep/sleep.yaml
$ linkerd inject sleep.yaml | kubectl apply -f -
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;分别安装了两个版本的 flaskapp，和一个版本的 sleep 服务之后。再创建两个 flaskapp 的分版本服务。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v1
kind: Service
metadata:
  name: flaskapp-v1
  labels:
    app: flaskapp
spec:
  selector:
    app: flaskapp
    version: v1
  ports:
    - name: http
      port: 80
      targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: flaskapp-v2
  labels:
    app: flaskapp
spec:
  selector:
    app: flaskapp
    version: v2
  ports:
    - name: http
      port: 80
      targetPort: 80
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;创建两个服务之后，就可以尝试拆分了，同样是一个 YAML：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
  name: flask-split
spec:
  service: flaskapp
  backends:
  - service: flaskapp-v1
    weight: 1
  - service: flaskapp-v2
    weight: 500m
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;注意这里的定义和 Istio 也稍有不同，使用权重而非百分比进行分流。&lt;/p&gt;

&lt;p&gt;可以在 Sleep 中进行测试：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ for i in {1..1000}; do curl -sSL http://flaskapp/env/version | grep v1; done | wc -l
660
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到，按照我们的权重分配，成功进行了分流。但是目前在 SMI 中并没有看到条件选择的相关内容，因此目前的功能还比较初级。可以通过 &lt;a href=&#34;https://flagger.app/&#34; target=&#34;_blank&#34;&gt;Flagger&lt;/a&gt; 的加持，实现更加复杂的功能。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio 和 Linkerd 的性能测试分析</title>
      <link>/post/performance-benchmark-analysis-of-istio-and-linkerd/</link>
      <pubDate>Sun, 19 May 2019 13:29:38 +0800</pubDate>
      <guid>/post/performance-benchmark-analysis-of-istio-and-linkerd/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://kinvolk.io/blog/2019/05/performance-benchmark-analysis-of-istio-and-linkerd/&#34; target=&#34;_blank&#34;&gt;Performance Benchmark Analysis of Istio and Linkerd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：&lt;a href=&#34;https://twitter.com/ThiloFM&#34; target=&#34;_blank&#34;&gt;Thilo Fromm&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;动机&#34;&gt;动机&lt;/h2&gt;

&lt;p&gt;过去几年里，服务网格在 Kubernetes 生态中迅速成长。Service Mesh 的&lt;strong&gt;价值&lt;/strong&gt;难以抗拒，然而对摩拳擦掌的用户来说，另一个基础问题就是：&lt;strong&gt;成本&lt;/strong&gt;怎样？&lt;/p&gt;

&lt;p&gt;成本有很多种，可不仅仅是学习新技术时的投入。在这一篇报告中，我们选择了一个易于量化的方面：在一定规模的服务中的资源消耗和性能影响。要进行这个测量，我们设计一系列测试场景，针对候选产品进行测试。我们的的候选包括 Istio（来自 Google 和 IBM 的 Istio 以及 Linkerd（CNCF 项目）。&lt;/p&gt;

&lt;p&gt;Buoyant 是 Linkerd 的首创者，他们和我们取得联系，目的是获得一个 Istio 和 Linkerd 的客观评判。这给我们一个深入服务网格技术的机会，欣然从命。&lt;/p&gt;

&lt;p&gt;Kinvolk 目前有客户正在尝试 Istio。我们的使命是在云原生世界中促进开源技术的发展，这也是我们呈现这一对比报告的根本原因。&lt;/p&gt;

&lt;p&gt;下面使用的测试方案也已经开放给开源社区，地址是 &lt;a href=&#34;https://github.com/kinvolk/service-mesh-benchmark。&#34; target=&#34;_blank&#34;&gt;https://github.com/kinvolk/service-mesh-benchmark。&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;目标&#34;&gt;目标&lt;/h2&gt;

&lt;p&gt;研究过程中我们有三个目标：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;提供一个可重现的测试框架，任何人都可以下载和使用。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;识别最能反应服务网格运行成本的场景和指标。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;根据业界在性能测试方面的最佳实践，例如控制编译来源，处理 Coordinated Omission（CO），来对流行服务网格进行评估。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;场景&#34;&gt;场景&lt;/h2&gt;

&lt;p&gt;我们的目标是在常规大负载集群的操作环境下，理解服务网格的性能表现。这意味着在产生压力的时候，集群应用还有能力在已定时间范围内给出响应。在系统受到压力的时候，用户访问该集群所服务的页面，还能够在一个可忍受的范围内提供服务。在真实世界中，延迟增大到一定程度之后，就会采取措施进行扩容了。&lt;/p&gt;

&lt;p&gt;在本文的测试中，测试负载（每秒 HTTP 请求）的水平是这样设置的——在给应用和服务网格施加压力的时候，运行其上的流量还在一个可控范围之内。&lt;/p&gt;

&lt;h2 id=&#34;指标&#34;&gt;指标&lt;/h2&gt;

&lt;h3 id=&#34;rps-用户体验和-co&#34;&gt;RPS、用户体验和 CO&lt;/h3&gt;

&lt;p&gt;测试中使用一个恒定的请求速率（RPS）发送 hTTP 请求，我们对响应延迟进行测量，来确定服务网格的总体性能。同样的 RPS 也会施加到一个无服务网格的集群上，以此结果来描述集群和应用的性能基线。&lt;/p&gt;

&lt;p&gt;我们的测试过程很注重 CO，在以 UX 为中心的视角下的一个重要因素。负载生成器只会在前一个请求完成之后才发起新请求，而不是为了满足 RPS 要求，不顾之前的请求直接按照时间点发起心情求。&lt;/p&gt;

&lt;p&gt;比如说如果我们要做一个 10 RPS 的延迟测试，我们每隔 100 毫秒就发出一个新请求，也就是一个 10 Hz 的速率。但是如果负载生成器在等待一个耗时超出 100 毫秒的请求的结束的话，那么这个 RPS 最多只能到 9。单一请求造成了高延迟，后续的请求也会受到拖累——处理的并不慢，只是开始得晚了。这种行为有两个缺点：第一个就是刚提到的，单一的高延迟请求造成后续请求的延迟；第二就是请求的发生过程被暂停，不符合 RPS 要求。在真实情况下，高延迟问题很可能因为用户蜂拥而至，产生大量积压。&lt;/p&gt;

&lt;p&gt;我们使用 &lt;a href=&#34;https://github.com/giltene/wrk2&#34; target=&#34;_blank&#34;&gt;wrk2&lt;/a&gt; 来生成负载并在客户端测量延迟。wrk2（Gil Tene）是流行的 http 压测工具 wrk（Will Glozer）的 Fork。wrk2 提供了 RPS 参数，可以用指定速率来生成负载，它通过在发起请求的时间点上测试延迟的方式来消除 CO 问题，还会尝试在请求迟发的情况下以双倍速率生成请求的方式来追赶进度。wrk2 还包含了 Gil Tene 的 HDR 直方图功能，提供了无损精确性的记录。越长的执行时间会有越高的精确度，这样后几个百分位的数据精度更高，也是我们更感兴趣的区域。&lt;/p&gt;

&lt;p&gt;为了完成这个测试，我们对 wrk2 的功能做了扩展，加入了多服务器地址和多 HTTP 资源路径的支持。我们不想将这个功能独立 Fork 出来，而是会和上游合作加入我们的&lt;a href=&#34;https://github.com/kinvolk/wrk2&#34; target=&#34;_blank&#34;&gt;变更&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&#34;性能&#34;&gt;性能&lt;/h3&gt;

&lt;p&gt;为了评估性能，我们可以研究一下延迟的分布（直方图），尤其是尾部的最后几个百分位的延迟。这反映了我们本次测试在 UE 上的焦点：一个典型的页面或者服务，需要不止一个请求来完成动作。如果一个请求延迟了，整个动作都会变慢。单一请求的 p99 在更复杂的操作中会有很大影响，例如浏览器访问一个页面，获取页面中的资源并进行顺序渲染——这就是我们看重 p99 的原因。&lt;/p&gt;

&lt;h3 id=&#34;资源消耗&#34;&gt;资源消耗&lt;/h3&gt;

&lt;p&gt;使用服务网格会让集群消耗更多资源，和业务逻辑发生争用。为了更好地理解这一效果，我们同时衡量了服务网格控制平面和应用 Sidecar 中的 CPU 和内存消耗。在测试期间，会用一个较高频率在容器级别收集 CPU 使用率和内存用量，每次运行中会选择组件的最大资源消耗，得出所有运行中的中位数并用于出具结果。&lt;/p&gt;

&lt;p&gt;我们注意到，内存消耗在测试结束时达到高峰。这个情况是合理的，根据上面的讨论，wrk2 用固定频率发起请求，当延迟超过一个阈值时，负载就会开始堆积，所以内存一旦分配就一直要到测试结束才会释放。CPU 使用率也会全程持续走高。&lt;/p&gt;

&lt;h2 id=&#34;测试环境&#34;&gt;测试环境&lt;/h2&gt;

&lt;h3 id=&#34;集群&#34;&gt;集群&lt;/h3&gt;

&lt;p&gt;我们使用了自动部署的测试集群，方便测试过程的启动和结束，也更加容易进行统计，生成可靠的数据。&lt;/p&gt;

&lt;p&gt;在这个服务网格性能测试过程中，我们使用了一个 5 节点的集群，每个节点使用 24核/48线程的 AMD EPYC CPU，主频为 2.4GHz，64G 内存。我们的工具可以使用可配置的节点数量，可以用不同的配置重新运行。&lt;/p&gt;

&lt;p&gt;负载的生成和延迟的测量都在集群内完成。为了消除噪音和 Ingress Gateway 的数据污染，我们把测试聚焦在应用之间的服务网格。负载生成器作为一个 Pod 部署在集群中，我们保留一个节点，用于负载生成和指标测量，在其它四个节点运行一定数量的应用实例。为了合理的统计分布，我们每次运行都会随机选择一个节点来运行负载生成器。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/clusterlayout.png&#34; alt=&#34;cluster layout&#34; /&gt;&lt;/p&gt;

&lt;p&gt;每次运行之前，会随机选择一个节点专门用于生成负载。其它节点运行应用负责承担负载。&lt;/p&gt;

&lt;p&gt;为了完成这次测试，我们选择 Packet 作为我们的 IaaS 供应商，工作节点我们选择了 c2.medium。Packet 提供了裸金属服务器，这样就让我们避免了虚拟化环境中常见的干扰问题。&lt;/p&gt;

&lt;h3 id=&#34;应用&#34;&gt;应用&lt;/h3&gt;

&lt;p&gt;根据前面的讨论，我们选择 wrk2 生成负载，并对这一工具进行了定制，可以同时访问多个 HTTP 端点。&lt;/p&gt;

&lt;p&gt;我们用来运行测试的目标应用是 Linkerd 的演示应用 &lt;code&gt;Emojivoto&lt;/code&gt;，这个应用自身跟 Linkerd/服务网格 的功能并无相关，Emojivoto 使用一个名为 &lt;code&gt;web-svc&lt;/code&gt;（&lt;code&gt;type: load-balancer&lt;/code&gt;）的 HTTP 微服务作为前端。&lt;code&gt;web-svc&lt;/code&gt; 使用 gRPC 和 &lt;code&gt;emoji-svc&lt;/code&gt;（提供表情符） 以及 &lt;code&gt;voting-svc&lt;/code&gt;（提供可控的投票）后端进行通信。这个应用简单清晰，包含了测试所需的云原生应用的所有要素，因此我们选择它作为测试应用。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/emojivoto.png&#34; alt=&#34;emojivoto&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Emojivoto 应用包含了三个微服务。&lt;/p&gt;

&lt;p&gt;然而只用一个应用进行服务网格测试，是很不现实的，真实世界中的服务网格，应该有复杂的多应用的部署。为了在保持简单的情况下更加仿真，我们用可部署的份数来部署 Emojivoto 应用，每个应用的名字中都加入序号。例如  &lt;code&gt;web-svc-1&lt;/code&gt;、&lt;code&gt;emoji-svc-1&lt;/code&gt;、&lt;code&gt;voting-svc-1&lt;/code&gt; 以及 &lt;code&gt;web-svc-2&lt;/code&gt;、&lt;code&gt;emoji-svc-2&lt;/code&gt;、&lt;code&gt;voting-svc-2&lt;/code&gt;。我们的负载均衡会将请求分发给所有这些 App，观察固定的 RPS。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/manyemojivotos.png&#34; alt=&#34;replica&#34; /&gt;&lt;/p&gt;

&lt;p&gt;循环利用 YAML，并在名字中加入序号，部署多套应用。&lt;/p&gt;

&lt;h3 id=&#34;运行测试和统计的稳健性&#34;&gt;运行测试和统计的稳健性&lt;/h3&gt;

&lt;p&gt;因为我们使用的是 Packet 提供的公共数据中心来运行我们的测试，所以也不能选择特定的服务器来进行部署。服务器的年龄和他的部件（内存、CPU 等），数据中心中的相对位置（同一个机架、房间、安全区），以及节点之间的物理连接，这些情况都会对测试的原始数据产生影响。其它服务器和我们的测试无关，但是在同一个数据中心内，共享同样的物理网络资源，也是可能对测试造成干扰的，最终会产生不可靠的测试数据。我们的每个数据点都有足够的统计分布样本，这样在进行对比的时候就能消除同一网络内外部因素造成的影响——例如 Istio 和 Linkerd 的延迟以及资源消耗方面的对比。我们还使用了不同数据中心的多个集群进行了测试，这也让我们对测试数据的可靠性信心大增。&lt;/p&gt;

&lt;p&gt;为了得到足够的统计分布，我们会每个测试都会运行两次，以得出平均值和标准差，我们在两个集群上同时独立部署，防止遭遇低档硬件或者故障网络，或有服务器被放置在数据中心的角落。&lt;/p&gt;

&lt;p&gt;典型的性能测试一般有几个步骤，这些步骤会在两个集群上同时运行，来消除上面提到的隐患。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;测试之前，重启所有工作节点。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;在两个集群的 &lt;code&gt;istio-stock&lt;/code&gt;、&lt;code&gt;istio-tuned&lt;/code&gt;、&lt;code&gt;linkerd&lt;/code&gt;、&lt;code&gt;bare&lt;/code&gt; 命名空间中，分别：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;安装服务网格（当然，不包含 &lt;code&gt;bare&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;部署 emojivoto 应用。&lt;/li&gt;
&lt;li&gt;部署负载生成器 Job。&lt;/li&gt;
&lt;li&gt;等 Job 结束，每 30 秒拉取一次资源消耗数据。&lt;/li&gt;
&lt;li&gt;拉取测试结果日志，其中包含了延迟指标。&lt;/li&gt;
&lt;li&gt;删除敷在生成 Job 以及 emojivoto。&lt;/li&gt;
&lt;li&gt;删除服务网格。&lt;/li&gt;
&lt;li&gt;回到第一步，测试下一个服务网格（顺序为：Linkerd-&amp;gt;Istio-&amp;gt;Bare）。&lt;/li&gt;
&lt;li&gt;在所有的 4 个测试结束之后，再运行第二次，以满足统计需要。&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;重现性&#34;&gt;重现性&lt;/h3&gt;

&lt;p&gt;w我们使用的是 Kinvolk 最近发布的 Kubernetes 发行版：Lokomotive。用于集群部署以及用于测试的代码都是开源的，保存在 Github 上。允许重新进行测试，也希望能够从其它用户那里得到改进。&lt;/p&gt;

&lt;h3 id=&#34;测试的运行和观测&#34;&gt;测试的运行和观测&lt;/h3&gt;

&lt;p&gt;我们在 &lt;code&gt;bare&lt;/code&gt;（无服务网格）、&lt;code&gt;istio-stock&lt;/code&gt;（无微调）、&lt;code&gt;istio-tuned&lt;/code&gt; 以及 &lt;code&gt;Linkerd&lt;/code&gt; 上，用 500 的 RPS 运行 30 分钟。在两个集群上各运行两次，每种数据就有了 4 个样本。测试集群分布在两个不同地理区域的不同的数据中心，一个是 Packet 的 Sunnyvale 数据中心，另一个是纽约的 Parsippany 数据中心。&lt;/p&gt;

&lt;h3 id=&#34;服务网格的版本&#34;&gt;服务网格的版本&lt;/h3&gt;

&lt;h4 id=&#34;istio-stock-和-tuned&#34;&gt;Istio：stock 和 tuned&lt;/h4&gt;

&lt;p&gt;我们用 &lt;a href=&#34;https://github.com/istio/istio/releases/tag/1.1.6&#34; target=&#34;_blank&#34;&gt;Istio 1.1.6&lt;/a&gt; 运行这一测试，&lt;code&gt;stock&lt;/code&gt; 运行的是根据&lt;a href=&#34;https://istio.io/docs/setup/kubernetes/install/kubernetes/&#34; target=&#34;_blank&#34;&gt;安装文档&lt;/a&gt;进行部署的版本，&lt;code&gt;tuned&lt;/code&gt; 版本则移除了内存限制，禁用了部分 Istio 组件，执行了不少推荐的微调。尤其是我们禁用了 Mixer、Policy、Tracing、Gateways 以及 Prometheus。&lt;/p&gt;

&lt;h4 id=&#34;linkerd&#34;&gt;Linkerd&lt;/h4&gt;

&lt;p&gt;我们使用的是 Linkerd 的 &lt;a href=&#34;https://github.com/linkerd/linkerd2/releases/tag/edge-19.5.2&#34; target=&#34;_blank&#34;&gt;Linkerd2-edge-19.5.2&lt;/a&gt;。我们使用的是 Linkerd 的&lt;a href=&#34;https://linkerd.io/2/getting-started/&#34; target=&#34;_blank&#34;&gt;标准配置&lt;/a&gt;，没有进行任何调整。&lt;/p&gt;

&lt;h3 id=&#34;测试服务网格的上限&#34;&gt;测试服务网格的上限&lt;/h3&gt;

&lt;p&gt;在使用稳定吞吐量开始长期运行之前，我们用一个较短的测试来确定服务网格吞吐量和延迟的范围。我们的目标是找到一个负载点，在这个点上，网格还能够用可接受的性能来处理流量。&lt;/p&gt;

&lt;p&gt;为了我们的测试，我们运行了 30 个 Emojivoto 应用，也就是 90 个微服务，平均下来每个节点有 7.5 个应用 22 个微服务。我们用多个 RPS 各运行 10 分钟，来确定前面所说的负载点。&lt;/p&gt;

&lt;h3 id=&#34;测试运行时间&#34;&gt;测试运行时间&lt;/h3&gt;

&lt;p&gt;我们最有兴趣的是尾部的百分位，因此测试的运行时间就很有影响了。越长的运行时间，在 99.9999 百分位和 100 百分位上的延迟就会越高。为了模拟用户涌入造成的高峰、以及新计算资源加入后的恢复，我们决定了 30 分钟的运行时间。注意，我们认为在多数环境里，尤其是自动伸缩的环境中，新资源的加入周期应该远低于 30 分钟；我们还认为，一个健壮的应用环境中，30 分钟足以应对扩容方面的意外。&lt;/p&gt;

&lt;h2 id=&#34;第一次测试-500-rps-30-分钟&#34;&gt;第一次测试：500 RPS，30 分钟&lt;/h2&gt;

&lt;p&gt;这次测试运行超过 30 分钟，500 RPS。&lt;/p&gt;

&lt;h3 id=&#34;延迟分布&#34;&gt;延迟分布&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;images/500RPS-latency.png&#34; alt=&#34;500RPS-latency&#34; /&gt;&lt;/p&gt;

&lt;p&gt;我们在对数中观察到裸金属案例运行中，出现了很大的错误——可能是 Packet 的问题。这个情况在 99.9 和 99.999 上尤其明显，然而其他的数据点还是证明了整体趋势。我们看到 Linkerd 在这方面是胜出的，Istio 的缺省配置和微调配置相差不大，接下来看看资源消耗。&lt;/p&gt;

&lt;h3 id=&#34;内存和-cpu&#34;&gt;内存和 CPU&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;images/500RPS-memory_usage.png&#34; alt=&#34;500RPS-memory_usage.png&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/500RPS-cpu_utilization.png&#34; alt=&#34;500RPS-cpu_utilization&#34; /&gt;&lt;/p&gt;

&lt;p&gt;我们在 4 个独立测试运行的过程中，测量了内存分配和 CPU 使用率，在这 4 个样本中，使用了中位数以及最高最低值。Linkerd 控制平面内存消耗的异常点是由 linkerd-prometheus 容器造成的，它消耗了 Linkerd 平面其他组件内存的两倍。&lt;/p&gt;

&lt;p&gt;而 Istio 中，我们看到了几次控制平面容器（Pilot 及其代理）消失的情况。我们不明白其中的原因，也没有深究，也没有把消失的容器计入结果。&lt;/p&gt;

&lt;h2 id=&#34;第二次测试-600-rps-30-分钟&#34;&gt;第二次测试：600 RPS，30 分钟&lt;/h2&gt;

&lt;p&gt;这次测试运行超过 30 分钟，600 RPS。&lt;/p&gt;

&lt;h3 id=&#34;延迟分布-1&#34;&gt;延迟分布&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;images/600RPS-latency.png&#34; alt=&#34;600RPS-latency&#34; /&gt;&lt;/p&gt;

&lt;p&gt;我们再次观测到了裸金属测试中的抖动；然而其影响比 500 RPS 的时候更小。我们逼近了 Linkerd 的可接受响应时间的上限，在 100 百分位上的是 3 秒钟的延迟。&lt;/p&gt;

&lt;p&gt;Istio 轻松的把延迟时间推到了分钟级（别忘了 Y 轴是对数），我们还看到了大量的 Socket/HTTP 错误，占了大概 1%-5.2%，中位数在 3.6%。我们要指出，Istio 的 RPS 承受范围在 565 和 571 之间，中位数是 568。Istio 在本次测试中没能达到 600 RPS。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/600RPS-memory_usage.png&#34; alt=&#34;600RPS-memory_usage.png&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/600RPS-cpu_utilization.png&#34; alt=&#34;600RPS-cpu_utilization&#34; /&gt;&lt;/p&gt;

&lt;p&gt;上图的对比不太公平——我们看到的是 Linkerd 在 600 RPS 时候的表现，而 Istio 的是 570 RPS——但我们还是看得出，Istio 这里的资源需求。我们再次观察到 Istio 容器消失的情况，同样做了忽略处理。&lt;/p&gt;

&lt;h2 id=&#34;结论&#34;&gt;结论&lt;/h2&gt;

&lt;p&gt;与裸金属相比，在常规条件下，Linkerd 和 Istio 的开销都算是可以接受的。当进入高负载状态时，相对于 Istio，Linkerd 能够提供更高的 RPS，并且使用更少的资源。&lt;/p&gt;

&lt;h2 id=&#34;下一步&#34;&gt;下一步&lt;/h2&gt;

&lt;p&gt;基于上面测试的观察，我们认为我们建立了一个良好的测试基础。未来的测试会进行更多的尝试，包括增强现有的测试，以及扩展测试场景。&lt;/p&gt;

&lt;p&gt;我们认为把负载生成器限制在一个 Pod 中是一个最大的限制。这限制了负载的生成能力。如果突破了这一限制，我们就有能力进行更多样的测试方法。然而在多个 Pod 中并列运行，又带来了结果合并的问题。&lt;/p&gt;

&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;以下内容纯属个人胡言乱语&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;也不知道为啥，连续冒出几个性能测试来，与性能相比，更重要的是靠谱和有用好吗。Istio 还是 Linkerd，能长点心么。&lt;/p&gt;

&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://linkerd.io/2019/05/18/linkerd-benchmarks/&#34; target=&#34;_blank&#34;&gt;https://linkerd.io/2019/05/18/linkerd-benchmarks/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Linkerd &#43; Namerd，实现 Kubernetes 集群的灰度发布</title>
      <link>/post/linerd-on-kubernetes/</link>
      <pubDate>Tue, 14 Feb 2017 06:42:02 +0800</pubDate>
      <guid>/post/linerd-on-kubernetes/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;主要内容源于 &lt;code&gt;https://blog.buoyant.io/2016/11/04/a-service-mesh-for-kubernetes-part-iv-continuous-deployment-via-traffic-shifting/&lt;/code&gt; ，砍掉了 Jenkins 等附加部分，更换了更加易于理解的示例应用，以保证主干突出。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kubernetes 所提供的 rolling-update 功能提供了一种渐进式的更新过程，然而其滚动过程并不容易控制，对于灰度发布的需要来说，仍稍显不足，这里介绍一种利用 Linkerd 方案进行流量切换的思路。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;官网介绍：linker∙d is a transparent proxy that adds service discovery, routing, failure handling, and visibility to modern software applications。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;本文从实际操作入手，上线两个版本的简单应用，利用这一组合完成流量的切换和测试过程。&lt;/p&gt;

&lt;h2 id=&#34;测试目标&#34;&gt;测试目标&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;同时上线两个版本的应用。两个应用均可工作，利用不同输出进行区分。&lt;/li&gt;
&lt;li&gt;动态调整分配给两个版本的流量。&lt;/li&gt;
&lt;li&gt;利用 CURL 进行流量分配的测试。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;准备工作&#34;&gt;准备工作&lt;/h2&gt;

&lt;p&gt;这里利用一个 1.2 以上版本的 Kubernetes 集群进行演示：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Server / Registry：10.211.55.62&lt;/li&gt;
&lt;li&gt;Node：10.211.66.63&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;另外因某些原因，需要有能力获取 Dockerhub 的镜像。&lt;/p&gt;

&lt;p&gt;例子程序很简单，用一个 PHP 文件显示环境变量中的内容：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-php&#34;&gt;&amp;lt;?php
echo getenv(&amp;quot;VAR_LABEL&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Docker file 继承自 &lt;code&gt;dustise/lamp:latest&lt;/code&gt;，文件内容如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dockerfile&#34;&gt;FROM dustise/lamp
COPY index.php /web/codebase
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;利用 Docker build 创建镜像，这里命名为 lamp:gray，备用。&lt;/p&gt;

&lt;h2 id=&#34;创建工作负载&#34;&gt;创建工作负载&lt;/h2&gt;

&lt;p&gt;做一个简单的 yaml 文件来加载蓝绿两组应用，名字、环境变量和端口三个位置需要更改：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;---
kind: ReplicationController
apiVersion: v1
metadata:
  name: green
# 此处省略若干
        env:
        - name: VAR_LABEL
          value: &#39;green&#39;
---
kind: Service
apiVersion: v1

# 此处省略若干

  type: NodePort
  ports:
  - protocol: TCP
    nodePort: 32001
    port: 80
    targetPort: 80
    name: http
  selector:
    name: green
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;利用 &lt;code&gt;kubectl create -f green.yaml&lt;/code&gt; （ 以及 blue.yaml ）之后，可以利用 curl 或者浏览器检查运行情况，如果正常，两个端口的访问应该分别会返回 &lt;code&gt;green&lt;/code&gt; 和 &lt;code&gt;blue&lt;/code&gt; ，这里的端口命名很重要，这一名称会被后面的规则引用到。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;注意，这里 NodePort 并非必须，仅为测试方便。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;运行-namerd&#34;&gt;运行 Namerd&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;此处 yaml 主要来自于官网 &lt;code&gt;https://raw.githubusercontent.com/BuoyantIO/linkerd-examples/master/k8s-daemonset/k8s/namerd.yml&lt;/code&gt;
为适应本地环境，将原有 Loadbalancer 类型的服务改为 NodePort&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;略微做一下讲解。&lt;/p&gt;

&lt;p&gt;整个 yaml 由四部分组成：&lt;/p&gt;

&lt;h3 id=&#34;thirdpartyresource&#34;&gt;ThirdPartyResource&lt;/h3&gt;

&lt;p&gt;这部分被用于做 Namerd 的存储后端。&lt;/p&gt;

&lt;h3 id=&#34;configmap&#34;&gt;Configmap&lt;/h3&gt;

&lt;p&gt;作为 Namerd 的配置，其中定义了这样几个内容（详情可参见 &lt;code&gt;https://linkerd.io/config/0.8.5/namerd/index.html#introduction&lt;/code&gt;）：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;管理端口 9990&lt;/li&gt;
&lt;li&gt;storage：存储定义，通过 8001 端口同 Kube Api Server 通信，完成在 ThrdPartyResource 中的访问（8001 端口由 kubectl proxy 指令开通）&lt;/li&gt;
&lt;li&gt;namer：定义服务发现能力由 Kubernetes 提供。&lt;/li&gt;
&lt;li&gt;interface 部分则是定义了两种支持协议。其中 HTTP Controller 可以接收 namerctl 的控制指令。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;rc&#34;&gt;RC&lt;/h3&gt;

&lt;p&gt;这部分不新鲜，除了 namerd 之外，还利用 kubectl proxy 提供通信端口给 namerd，颇有蛇足之嫌。正确的打开方式应该是直接和  Kube API Server 进行通信。&lt;/p&gt;

&lt;h3 id=&#34;service&#34;&gt;Service&lt;/h3&gt;

&lt;p&gt;这里注意服务类型的变更（ LoadBalancer -&amp;gt; NodePort ），需要暴露 4180 和 9990 两个端口，分别作为控制端口和界面端口。&lt;/p&gt;

&lt;p&gt;利用 kubectl 启用之后，就可以在指定的端口查看管理界面了。此时的管理界面没有做任何配置，因此比较单薄。&lt;/p&gt;

&lt;h3 id=&#34;添加规则&#34;&gt;添加规则&lt;/h3&gt;

&lt;p&gt;下面来安装 namerd 的控制工具，namerctl&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;go get -u github.com/buoyantio/namerctl
go install github.com/buoyantio/namerctl
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来创建一条规则：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/host=&amp;gt;/#/io.l5d.k8s/default/http;
/http/*/*/*=&amp;gt;8*/host/blue&amp;amp;2*/host/green;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这段代码表示该服务同时连接 blue 和 green 两个后端服务，按照 &lt;sup&gt;80&lt;/sup&gt;&amp;frasl;&lt;sub&gt;20&lt;/sub&gt; 的比例进行流量分配。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;namerctl dtab create [file name] --base-url&lt;/code&gt;，这里 base-url 取值就是我们给 namerd 设置的 Nodeport。&lt;/p&gt;

&lt;p&gt;接下来就能够看到管理界面上显示出新的规则了。&lt;/p&gt;

&lt;h2 id=&#34;运行-linkerd&#34;&gt;运行 Linkerd&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;这里同样基于官方的 &lt;code&gt;https://raw.githubusercontent.com/BuoyantIO/linkerd-examples/master/k8s-daemonset/k8s/linkerd-namerd.yml&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;需要注意的是，官方给出的 yaml 文件中有一处 bug，使得这个 yaml 只能在缺省的 namespace 和 domain suffix 下运行。需要纠正对 namerd 的访问方式，删除 Namerd 后面的 &lt;code&gt;default.svc.cloud.local&lt;/code&gt; 即可。&lt;/p&gt;

&lt;p&gt;同样的，他的服务端口和管理端口都应该改用 NodePort 方式进行暴露。&lt;/p&gt;

&lt;p&gt;运行后，同样可以看到 Linkerd 的管理界面。&lt;/p&gt;

&lt;h2 id=&#34;测试&#34;&gt;测试&lt;/h2&gt;

&lt;p&gt;下面可以做一个简单的测试，来证明流量分配的有效性：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;for ((i=1;i&amp;lt;=300;i++)); do curl -s &amp;quot;http://10.211.55.63:30001/&amp;quot;;echo &amp;quot;&amp;quot;; done | grep -i blue| wc -l
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到，随着循环次数的增加，其结果越来越趋近于 &lt;sup&gt;80&lt;/sup&gt;&amp;frasl;&lt;sub&gt;20&lt;/sub&gt; 的分配比例。&lt;/p&gt;

&lt;p&gt;接下来，我们修改上面的 dtab 为如下内容：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/host=&amp;gt;/#/io.l5d.k8s/default/http;
/http/*/*/*=&amp;gt;8*/host/blue&amp;amp;8*/host/green;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;重新进行测试，就可以看到，流量分配已经发生了变化。另外，还可以在 Linkerd 的管理界面上看到网络流量的变化情况。&lt;/p&gt;

&lt;h2 id=&#34;结语&#34;&gt;结语&lt;/h2&gt;

&lt;p&gt;这一组合基本能够满足流量渐变分配的功能需求，同时也有如豆瓣这样的大厂使用，但他的 dtab 还是个相对复杂的东西，如果在生产上进行使用，还是需要进一步的学习。&lt;/p&gt;

&lt;p&gt;另外，按照其文档中所陈述的功能范围内容来看，仅用来做流量分配还是颇有点大材小用的味道，从个人来说，我倾向于一些更轻量级的解决方法。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
