TT Lab
开始
学习 学习路径 课程

Envoy 内部结构

为什么你写的路由不生效

在 TT Lab 中继续学习

一句话总结

一个请求找到目的地,要经过两次选择。先由 Host 头选出虚拟主机,再从该虚拟主机的路由表中自上而下扫描,使用第一个匹配项。前一次选择按具体程度决定,后一次选择按顺序决定——这两者不同,就是本文的全部内容。

为什么需要它

“路由明明写了,却没有命中”这类报告,有一半并不是路由的问题,而是选错了虚拟主机。

一个路由表(route_config)中可以有多个虚拟主机。每个虚拟主机都有 domains 列表,请求的 Host 头(HTTP/2 中为 :authority)必须匹配其中之一,才会去查看该虚拟主机的路由表。这里的匹配规则与路由不同。路由是自上而下扫描并使用第一个匹配项,而虚拟主机使用的是最具体的那一个。

1. 정확한 이름        www.foo.com
2. 접미 와일드카드    *.foo.com   (더 긴 와일드카드가 먼저)
3. 접두 와일드카드    foo.*
4. 특별한 *          아무 이름에나

因此,即使把 *.example.com 虚拟主机放到文件最上面,精确写了 www.example.com 的虚拟主机仍然会获胜。要想不在调换顺序上白白耗掉一整天,就必须先了解这个区别。

* 在整个路由表中只能放一个。如果有两个,就无法确定谁更具体,所以 Envoy 不会放任它在运行时造成混乱,而是在读取配置时就拒绝。

工作原理

虚拟主机确定之后,会自上而下查看其中的 routes,在第一个匹配处停止。可用于匹配的不只有路径。

条件 含义
prefix 路径的开头相同
path 路径必须完全相同
safe_regex 匹配正则表达式
headers 头的值条件(精确、存在、前缀、正则)
query_parameters 查询字符串条件

同一个匹配中的条件必须全部满足。所以像“只让内部测试人员使用新版本”这样的需求,就要同时写上 prefix 和 headers 来实现。条件不满足时,会跳过该路由并继续向下扫描。这不会返回 404,而是由下一条路由接收——所以要把带条件的窄路由放在上面,把宽泛的 prefix: "/" 放在最下面。

目的地也不只有一个集群。

添加头的位置有三处——路由、虚拟主机、路由表。它们不是覆盖,而是各自追加。所以同名的响应头可能会留下多个。

在现场相遇的样子

权重没有按比例分配的报告。weighted_clusters 是概率,而不是分配表。而且 Envoy 的每个工作线程都保存各自的状态,在默认的 concurrency(核心数)下统计四十个请求,每次结果都不同。验证金丝雀比例时,要么把样本量放大,要么把工作线程减到一个。在生产环境中,不要说“比例对不上”,而要用统计数据来看。

用 direct_response 在不碰应用的情况下收尾。健康检查路径、维护提示、拦截机器人的响应这类应用不需要知道的事情,最好在代理处结束。这样不用部署就能修改,应用挂掉了也能应答。

滥用正则表达式导致变慢。prefix 和 path 是字符串比较,而 safe_regex 要经过正则引擎。在有几百条路由的表中,如果前面全部用正则填充,每个请求都要把它们全部跑一遍。正则只用在其他方式做不到的地方。

官方文档:HTTP routing · HTTP route components

下一项实验要做什么

放置四个虚拟主机,亲自确认具体程度的顺序,然后观察放两个 * 时配置被拒绝。接着用 path、safe_regex、headers、query_parameters 分流,用四十次请求统计 75 比 25 的权重,再加上 direct_response 和 redirect,最后确认头在三个层次上各自追加。