Linkerd 数据平面的代理是多线程(multithreaded
)的, 并且能够运行可变数量的工作线程, 以便它们的资源使用(resource usage
)与应用程序工作负载(application workload
)相匹配。
当然,在真空(vacuum)中,当允许使用尽可能多的 CPU 内核时, 代理将表现出最佳的吞吐量(throughput
)和最低的延迟(latency
)。但是,在实践中,还需要考虑其他因素。
真实世界的部署不是一个负载测试(load test
), 在这个测试中,客户端和服务器除了用请求使代理饱和之外,没有其他工作要做。相反,服务网格模型将代理实例部署为应用程序容器的 sidecar
。每个代理只处理进出它注入的 pod 的流量。这意味着吞吐量和延迟受应用程序工作负载的限制。如果应用程序容器实例每秒只能处理这么多请求,那么代理可以处理更多的请求可能并不重要。事实上,给代理提供比它需要的更多 CPU 内核来跟上应用程序可能会损害整体性能, 因为应用程序可能不得不与代理竞争有限的系统资源。
因此,单个代理有效处理其流量比配置所有代理以处理最大可能负载更为重要。调整代理资源使用的主要方法是限制代理用于转发流量的工作线程数。有多种方法可以做到这一点。
使用 proxy-cpu-limit
Annotation
配置代理线程池的最简单方法是使用 config.linkerd.io/proxy-cpu-limit
annotation。此 annotation 配置代理注入器以设置一个环境变量,该变量控制代理将使用的 CPU 核数。
使用 linkerd install
CLI 命令安装 Linkerd 时, --proxy-cpu-limit
参数会为 Linkerd 安装注入的所有代理全局设置此 annotation。例如,
linkerd install --proxy-cpu-limit 2 | kubectl apply -f -
对于更细粒度(fine-grained)的配置,可以将 annotation 添加到 任何可注入的 Kubernetes 资源,例如 namespace、pod 或 deployment。
例如,以下将配置 my-deployment
部署中的代理使用1个 CPU 内核:
kind: Deployment apiVersion: apps/v1 metadata: name: my-deployment # ... spec: template: metadata: annotations: config.linkerd.io/proxy-cpu-limit: '1' # ...
与 Kubernetes CPU 限制和请求可以用 milliCPUs 表示不同, proxy-cpu-limit
注解应该用 CPU 内核的整数来表示。小数值将四舍五入到最接近的整数。
使用 Kubernetes CPU Limits 与 Requests
Kubernetes 提供 CPU limits and CPU requests 来配置分配给任何 pod 或容器的资源。这些也可用于配置 Linkerd 代理的 CPU 使用率。但是,根据 kubelet 的配置方式, 使用 Kubernetes 资源限制 而不是 proxy-cpu-limit
annotation 可能并不理想。
kubelet 使用两种机制之一来强制执行 pod CPU 限制。这由 --cpu-manager-policy
kubelet 选项 决定。使用默认的 CPU 管理器策略 none
, kubelet 使用 CFS 配额 来强制执行 CPU limits。这意味着 Linux 内核被配置为限制属于给定进程的线程被调度的时间量。或者,CPU 管理器策略可以设置为 static
。在这种情况下,kubelet 将使用 Linux cgroup
s 对满足特定条件的容器实施 CPU limits。
当 proxy-cpu-limit
annotation 配置的环境变量未设置时, 代理将运行与可用 CPU 内核数相等的工作线程数。这意味着使用默认的 none
CPU 管理器策略,代理可能会产生大量工作线程, 但 Linux 内核会限制它们的调度频率。这比简单地减少工作线程的数量效率更低,就像 proxy-cpu-limit
所做的那样:更多的时间花在上下文切换上,每个工作线程的运行频率将降低,这可能会影响延迟。
另一方面,使用 cgroup cpusets 将限制进程可用的 CPU 核数。从本质上讲,代理会认为系统的 CPU 内核数比实际少。这将导致与 proxy-cpu-limit
annotation 类似的行为。
但是,值得注意的是,要使用此机制,必须满足某些条件:
- kubelet 必须配置
static
CPU 管理器策略 - Pod 必须属于有 Guaranteed QoS class。这意味着 pod 中的所有容器都必须同时具有内存和 CPU 的 limit 和 request,并且每个的 limit 必须与 request 具有相同的值。
- CPU limit 和 CPU request 必须是大于或等于 1 的整数。
如果您不确定是否会全部满足这些条件,除了任何 Kubernetes CPU limits 和 requests 之外, 最好使用 proxy-cpu-limit
annotation。
使用 Helm
使用 Helm 时,如果不满足上述基于 cgroup 的 CPU 限制条件, 用户必须注意设置 proxy.cores
Helm 变量和 proxy.cpu.limit
之外的变量。