dtabs

Delegation tables/委托表(简称dtabs)是路由规则列表,将 “逻辑路径”(例如流行的冰淇淋店)转换为它所在的“具体名称”(例如,2790 Harrison St, San Francisco,CA 94110)。这是一个我们称之为“解析”的过程,它通过一系列前缀重写发生。

除了本文档,您还可以参考 Finagle 的 dtab 文档。 您还可以通过浏览 http://localhost:9990/delegator 来体验为运行中的 linkerd 实例服务的 dtab 功能。有关 dtab playground 的更多详细信息,请参阅 “管理”页面

路径

最简单的dtab包含一个规则(称为dentry/目录项):

  1. / iceCreamStore => / smitten;

这个目录项真的只适用于冰淇淋店,所以规则不适用于路径 /shoeStore/windowShop/sandals

但是对于路径 /iceCreamStore/try/allFlavors ,前缀与目录项的左侧(源)匹配,并用右侧(目标)替换以创建新路径: /smitten/try/allFlavors

目录项和顺序

Dtabs可以(并且经常做)有多个目录项。例如,我们可以列出几个商店:

  1. /smitten => /USA/CA/SF/Octavia/432;
  2. /iceCreamStore => /smitten;
  3. /iceCreamStore => /humphrys;

当我们尝试解析一个匹配多个前缀的路径时,优先使用底部的目录项。 所以路径 /iceCreamStore/try/allFlavors 将首先解析为 /humphrys/try/allFlavors。 然而,如果humphrys 的地址是未知的(在本例中),我们将返回 /smitten/try/allFlavors,最终解析为 /USA/CA/SF/Octavia/432/try/allFlavors

一步一步的例子

假设有 dtab:

  1. /iceCreamStore => /smitten;
  2. /smitten/try => /smittenLocation/waitInLine/thenTry;
  3. /smittenLocation => /sanfrancisco/octavia/432;
  4. /california => /USA/CA;
  5. /sanfrancisco => /california/SF;

和路径:

  1. /iceCreamStore/try/allFlavors

这是解析步骤:

/iceCreamStore/try/allFlavors 首先匹配规则 /iceCreamStore => /smitten; 并被重写为

/smitten/try/allFlavors 继续匹配规则 smitten/try => /smittenLocation/waitInLine/thenTry; 并被重写为

/smittenLocation/waitInLine/thenTry/allFlavors 继续匹配规则 /smittenLocation => /sanfrancisco/octavia/432; 并被重写为

/sanfrancisco/octavia/432/waitInLine/thenTry/allFlavors 继续匹配规则 /sanfrancisco => /california/SF; 并被重写为

/california/SF/octavia/432/waitInLine/thenTry/allFlavors 继续匹配规则 /california => /USA/CA; 并被重写为

/USA/CA/SF/octavia/432/waitInLine/thenTry/allFlavors!

请注意,每次前缀匹配时,我们从新创建的路径开始,并从底部到顶部再次游历整个dtab。这是有用的,但也容易意外循环! 考虑以下无限dtab(不用担心,递归调用过多时 Finagle 会退出):

  1. /iceCream => /youScream;
  2. /youScream => /weAllScream/for;
  3. /weAllScream/for => /iceCream;

命名器 & 地址

到目前为止,我们只讨论了路径路由。但是为了使 Finagle 成功路由请求,路径必须最终解决为具体的名称。大多数这些具体名称(在Finagle中,它们被称为“绑定地址”)由命名器定义或查找。

Finagle 提供了一个这样的名为 /$/inet 的命名器,将两个后续路径段解释为ip地址和端口。所以路径 /$/inet/127.0.0.1/4140 将解析到绑定地址 127.0.0.1:4140

Linkerd 还为许多不同的服务发现机制提供了一套命名器。 例如 /#/io.l5d.consul/#/io.l5d.k8s/#/io.l5d.marathon 。请在 linkerd documentation on namers 中查看更多关于这些和其他的更多信息。

一旦命名器将路径转换成绑定地址,则路由被认为是完整的,并且未在前缀匹配中使用的任何剩余路径段将保持未使用。作为一个例子,我们定义一个命名器 /#/routeOnMethod,它采用下一个路径段,并根据它是一个GET还是POST路由流量。然后对于 /http/1.1 => /#/routeOnMethod; 路径 /http/1.1/GET/host/users 将被重写到 /#/routeOnMethod/GET/host/users ,而前缀 /#/routeOnMethod/GET 将解析为绑定地址。其余的段 /host/users 对请求路由没有任何影响。

然而,命名器并不仅限于解析路径。作为他们最基本的用法,命名器的功能是操作它后面的路径段。考虑将后面两个段相乘并返回数字的命名器 /#/multiply 。 对于dtab:

  1. /byNine => /#/multiply/9;
  2. /byEight => /#/multiply/8;
  3. /bySeven => /#/multiply/7;

The path /byNine/3 will be rewritten to /#/multiply/9/3 and finally to /27.

通配符

当接收到像 /http/1.1/GET/chocolate/icecream 这样的路径,在路由请求时我们可能没有兴趣使用每个路径段。 如果所有冰淇淋需要路由到 /smitten,它是什么味道没关系。写这个 dtab 的一种方法是列出所有可能的风格:

  1. /http/1.1/GET/chocolate/icecream => /smitten;
  2. /http/1.1/GET/vanilla/icecream => /smitten;
  3. /http/1.1/GET/rockyroad/icecream => /smitten;
  4. /http/1.1/GET/strawberry/icecream => /smitten;
  5. /http/1.1/GET/mintchip/icecream => /smitten;

更简单和更优雅的解决方案是使用通配符替换风味段,该通配符将匹配该段的任何字符串。

  1. /http/1.1/GET/*/icecream => /smitten;

备选,并列和权重

当两个目录项具有相同的前缀时,我们将它们称为备选。 我们早先看到一个例子,再看一次:

  1. /smitten => /USA/CA/SF/Octavia/432;
  2. /iceCreamStore => /smitten;
  3. /iceCreamStore => /humphrys;

备选也可以使用管道操作符指定:

  1. /smitten => /USA/CA/SF/Harrison/2790;
  2. /iceCreamStore => /humphrys | /smitten;

在这两个例子中,humphrys 是我们尝试解决的第一个冰淇淋店。但是如果没有找到地址,我们继续处理smitten(如果smitten也没有找到,则整个路由操作失败 - 没有人得到冰淇淋)。您可以指定任意数量的备选 /humphrys | /smitten | /birite | /three-twins

Dtabs 还支持并列,使用以下语法的 /iceCreamStore => /humphrys & /smitten。 在这个例子中,我们有平等的机会将路径路由到任一个商店。如果我们希望比另一个更有可能进入一个商店,我们可以为每个路径添加权重:

  1. /smitten => 3 * /SF/Octavia/432 & 1 * /SF/California/2404;
  2. /iceCreamStore => 0.7 * /humphrys & 0.3 * /smitten;

权重可以是小数或整数。

负面,失败和空解析

如果命名器不能找到具体的地址,它会返回一个负面的解析。 这是向 Finagle 发出信号,这个路径无效,如果有任何替代路径可以尝试,现在是合适的时间。如果所有路径都为负面,Finagle 会抛出错误。这种回退逻辑可以用符号进行测试,”~“ 是 Finagle 理解为负面解析的符号。例如:

  1. /iceCreamStore => ~ | /smitten;

如果我们要在检查任何备选路径之前停止,我们应该使用失败而不是负面。失败指定使用 /$/fail 甚至更短 ,像在这个 dtab 中,我们路由到 smitten 或失败:

  1. /iceCreamStore => /smitten | !;

命名器有时也会返回失败的解析。例如对于路径 /multiply/cats/dogs 命名器 /multiply 会返回失败。

最后还有一种称为空的解析。它通过 /$/nil 或者 $ 调用,通常仅在测试场景中使用。