本文转载自微信公众号「黑客下午茶」,作者为少。转载本文请联系黑客下午茶公众号。
协议检测(Protocol detection),顾名思义,允许 Linkerd 自动检测 TCP 连接中使用的协议。 Linkerd 的设计原则之一是“just work”,协议检测是 Linkerd 如何实现这一目标的重要组成部分。
什么是协议检测?
简而言之,协议检测是通过检查连接上的流量来确定 TCP 连接上使用的协议的能力。
Linkerd 使用 Protocol detection 来避免要求用户指定协议。 Linkered 的代理不需要用户配置每个端口使用的协议,而是简单地执行协议检测来回答问题。
Linkerd 的 Protocol detection 通过查看客户端连接的前几个字节来获取有关流量的信息来工作。这种实现有一些后果,我们将在下面介绍。
但首先,让我们首先回答为什么 Linkerd 关心任何协议的问题。
可观察性、可靠性和安全性
我们通常将 Linkerd 的广泛功能分为三类:可观察性(Observability)、可靠性(reliability)和安全性(security)。了解连接(connection)上使用的协议是每个类别的基础。
可观察性
Linkerd 可观察性功能的核心是流量检测。这种仪器需要了解正在使用的协议,因为协议的知识可以提供丰富的指标。例如,知道连接正在使用 HTTP,Linkerd 就可以解析请求、响应和响应代码,并报告响应延迟、请求量和错误率等指标。这些指标非常有价值,以至于它们成为谷歌 SRE 书中所谓的“黄金信号”的一部分。另一方面,如果 Linkerd 只知道连接是 TCP,则它仅限于记录非常基本的信息,例如读取和写入的字节数——无法进一步解释字节。
Linkerd 可观察特性的核心是流量的测量。这种检测需要理解正在使用的协议,因为对协议的了解可以提供丰富的度量。例如,知道一个连接正在使用 HTTP,就允许 Linkerd 解析请求、响应和响应代码,并报告响应延迟、请求量和错误率等指标。这些指标非常有价值,它们是谷歌的 SRE 书中所谓的“黄金信号”的一部分。另一方面,如果 Linkerd 只知道一个连接是 TCP,那么它只能记录非常基本的信息,比如读取和写入的字节数——没有进一步解释字节的能力。
安全
双向 TLS (mTLS) 是 Linkerd 的核心功能。从 Linkerd 2.9 开始,网状端点(meshed endpoints)之间的所有 TCP 流量默认由 Linkerd 代理进行 mTLS。(有一些警告 - 请参阅下面有关 skip-ports 的部分。)
在这里,再次了解连接的协议至关重要。例如,如果连接已经是 TLS 的(例如,通过应用程序),则没有理由重新 TLS。(严格来说,TLS 是一种传输层协议,而不是像 HTTP 那样的应用层协议,但就本文而言,两者之间的区别并不重要。)
可靠性
最后,了解底层连接的协议允许 Linkerd 提供复杂的可靠性功能。这里的一个例子是负载平衡。在不知道连接协议的情况下,Linkerd 仅限于平衡连接(balancing connections):一旦与服务器建立了 TCP 连接,它就无法进一步操作该连接。
但是,如果 Linkerd 知道连接是 HTTP,它可以从连接平衡(connection balancing)转移到请求平衡(request balancing)。Linkerd 将建立一个跨端点的连接池,并平衡这个池中的请求。由于它现在可以访问 requests 和 responses,Linkerd 在平衡请求方面可以非常复杂;事实上,它根据每个可能端点的最近性能(使用称为“指数加权移动平均(exponentially weighted moving average)”或 EWMA 的指标)来平衡请求,以避免从慢速端点引起尾部延迟(tail latency)。
( Linkerd 也是 Kubernetes 中负载平衡 gRPC 连接的一个简单解决方案。)
当协议检测失败时
虽然协议检测旨在允许 Linkerd “just work”,但在某些情况下它不能:臭名昭著的服务器优先协议(server-speaks-first)。这些协议(包括 MySQL 和 SMTP)通过让客户端建立连接然后等待服务器响应来工作。从 TCP 的角度来看,这是一种完全合法的行为,但这意味着 Linkerd 无法检测到协议,因为相关信息来自服务器,而不是客户端。
(为什么不简单地使用服务器的字节来检测协议?因为在检测协议的时候,Linkerd 甚至还没有建立到服务器的连接。选择与哪个服务器对话是负载均衡器的一个功能,而使用哪个负载均衡器是协议的一个功能。这是一个 delicious、带有 TCP-flavored 的“先有鸡还是先有蛋(chicken-and-egg)”问题。)
为了避免这种情况,Linkerd 引入了 skip-inbound-ports 和 skip-outbound-ports 配置选项。这些选项指示 Linkerd 通过修改 Linkerd 用于通过其 sidecar 代理连接 pod 的 iptables 规则来完全绕过某些端口的代理。例如,将 annotation config.linkerd.io/skip-outbound-ports: 3306 添加到工作负载的 PodSpec 指示 Linkerd 创建一个 iptables 规则,以确保 Linkerd 代理永远不会处理到端口 3306(MySQL 端口)的任何流量 . 同样,annotation config.linkerd.io/skip-inbound-ports: 3306 将编写一个 iptables 规则,以便代理永远不会处理发送给它的 MySQL 流量。
Skip Ports 配置
这些选项为 protocol detection 无法处理 server-speaks-first 协议提供了一种解决方法。然而,它们有一个明显的缺点:因为它们完全绕过 Linkerd 代理,Linkerd 无法应用 mTLS 或捕获这些端口的任何指标。
Linkerd 2.10 中的不透明端口和改进的协议检测
为了解决 skip-ports 的不足,在 2.10 版本中,Linkerd 将添加不透明端口(opaque ports)的概念(以及相应的 opaque-ports annotation)。不透明端口就是 Linkerd 将代理而不执行协议检测的端口。虽然这种方法仍然需要配置,但将端口标记为不透明允许 Linkerd 应用 mTLS 并报告 TCP-level metrics —— 这比完全跳过它是一个很大的改进。
Opaque Ports 配置
Linkerd 2.10 还将通过使其“fail open”来改进协议检测的工作方式:如果协议检测代码在 10 秒后没有看到客户端字节,它会将连接视为 TCP 连接并继续,而不是像 2.9 那样失败 . 这意味着不使用 opaque-ports(或 skip-ports)annotating server-speaks-first 端口的最坏情况行为是 10 秒的连接时间延迟,而不是连接失败。
总结
Protocol detection 是 Linkerd 最强大的功能之一,也是 Linkerd “just works” 原则的基础。虽然协议检测不是万灵药,但 Linkerd 2.10 中引入的 opaque-ports 应该解决早期 skip-ports 特性的大部分缺点,并允许 Linkerd 使用者在整个 Kubernetes 环境中扩展 mTLS,而不管协议是什么。
Refs
- Protocol Detection and Opaque Ports in Linkerd
https://linkerd.io/2021/02/23/protocol-detection-and-opaque-ports-in-linkerd