Server-Speaks-First 有点坑,Linkerd 2.10 中的协议检测和不透明端口
协议检测(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
,而不管协议是什么。
我是为少
微信:uuhells123
公众号:黑客下午茶
加我微信(互相学习交流),关注公众号(获取更多学习资料~)