简单介绍 Leaf 的请求分发机制

Tachyon
6 min readJan 28, 2021

关于 Leaf

Leaf 是一个我写来代替 V2Ray 使用的客户端代理工具,这并不是说它准备取代 V2Ray,它也取代不了,尽管它在很多方面跟 V2Ray 相似,也在很多方面参考了 V2Ray 的设计,它更多是我个人满足自己需要所开发的工具。

其中一个 V2Ray 无法满足我需要的就是它的负载均衡功能,这也是这篇文章准备讨论的。

请求分发机制

Leaf 不把负载均衡看作是怎样从一组代理服务器里面选出一个最优的来使用,而是考虑拿到一个请求后,用什么样方式去分发它。

这里提到的最优并不一定指速度最快、延迟最低,不同测量方式会给到对最优不同的定义。负载均衡这个词也恐怕不合适用来描述这种功能,反正这么写就这么用吧。

Leaf 大体上有 3 种请求分发机制:

  • random:从组里随机选取一个服务器来发送请求
  • tryall:把请求同时发送到组里面的所有服务器
  • failover:按一定顺序向组里的服务器逐个发送请求

不同分发机制可以嵌套使用,具体是什么意思下文会体现到。

配置简介

这篇文章打算列出具体配置来介绍,所以有必要对所用到的配置做简单解释。

下面是一个大概的配置,定义了 1 个直连出口,2 个 Shadowsocks 代理服务器,和一个代理组:

[Proxy]
Direct = direct
Proxy1 = ss, 1.1.1.1, 8485, encrypt-method=chacha20-ietf-poly1305, password=123456Proxy2 = ss, 2.2.2.2, 8486, encrypt-method=chacha20-ietf-poly1305, password=123456[Proxy Group]
Group1 = failover, Proxy1, Proxy2, health-check=true

后面会直接忽略代理服务器的定义,只给出代理组的配置。

比如这是一个名字为 Group1 的 failover 代理组,里面包含 Proxy1 和 Proxy2,并且开启了健康检查:

Group1 = failover, Proxy1, Proxy2, health-check=true

又比如这是一个名字为 Group1 的 random 代理组,里面包含了直连出口 Direct,一个代理服务器 Proxy1,和另一个代理组 Group2:

Group1 = random, Direct, Proxy1, Group2

意思是请求给到这个 Group1 后,它可能是直连的,也可能是发到 Proxy1,也可能是发到 Group2,随机选。这里 Group2 的定义没给出所以最后到底发到哪这里没定义。

这里的 Group1, Group2, Proxy1, Proxy2, Direct 都只是名字,可以改任意名字。而 direct, ss, random, tryall, failover 是关键字不能随意改。

failover

首先介绍最有用且最常用的 failover,即按一定顺序向组里的服务器逐个发送请求。

给出下面的配置:

Group1 = failover, Proxy1, Proxy2, Proxy3, Proxy4

如果一个请求给到 Group1,它就会先尝试连接 Proxy1,如果连接成功,则使用 Proxy1 来处理这个请求,如果不成功,接着尝试 Proxy2,依此类推。

failover 有很多参数可以设置,比如说健康检查,默认开启,它就会对代理组里面的服务器定期按延迟大小进行重新排序,如果检测到 Proxy2 的延迟最低,Proxy2 就会被摆到第一位,会被首先拿来尝试连接。因为 failover 会逐个尝试的特性,所以就算在特定时间点最优的 Proxy2 服务器出现问题,它后面的服务器也会被逐个尝试,并不会说最优的 Proxy2 突然用不了就无法完成当前请求,可以做到非常高的容错性。

tryall 和 random

看完 failover 的介绍后,其它两个其实也就不言而喻了。

给出这个配置:

Group1 = tryall, Proxy1, Proxy2

如果一个请求给到 Group1,它会同时去连接 Proxy1 和 Proxy2,哪个返回快就用哪个。

而 random 就是随机挑一个用:

Group1 = random, Proxy1, Proxy2

组合使用

代理组中不仅可以包含代理服务器,还可以包含代理组。

假设你有以下代理服务器:

  • 一个速度延迟可用性都很棒的 Proxy1,但很贵,只想必要的时候用
  • 几个很便宜,但质量参差不齐的 Proxy2, Proxy3, Proxy4

你可能会想用到以下配置:

Group1 = tryall, Proxy2, Proxy3, Proxy4
Group2 = failover, Group1, Proxy1, health-check=false, fail-timeout=3

Group2 是一个没有健康检查的 failover,Group1 排在第一,Proxy1 排在第二,限制连接超时 3 秒。

当请求来到 Group2 时,它总会(因为没有健康检查,就不会有重新排序)首先尝试用 Group1,而 Group1 是另一个组,它会同时尝试连接 Proxy2, Proxy3, Proxy4,取最快的返回,所以就算是三个连接性不好的服务器,我们还是能够拿其中最快的来连接,并且我们设置 3 秒超时要求三个服务器中必需有至少一个在 3 秒内完成,否则我们使用 Proxy1。这里如果假设 Proxy1 总是可用且连接非常快的话,就意味着我们总是能够在大概 3 秒内完成对这个请求的分发,且通过性价比很好的方式。

这种负载均衡功能需求的出现,往往是因为像上面这种情况, 你有不同质量服务器,又想以性价比较高的方式使用。

这里给出另一个配置例子:

Group1 = failover, Proxy2, Proxy1, health-check=false, fail-timeout=3, fallback-cache=true, cache-timeout=5

fallback-cache 可以记住之前的分发记录,比如有一个请求到 www.google.com ,假设这时 Proxy2 出现问题完成不了请求,Proxy1 被用到,那么在接下来的 cache-timeout=5 分钟内,所有到 www.google.com 的请求都会跳过 Proxy2 直接使用 Proxy1。

fallback-cache 还可以用来做成一个带自动检测代理域名功能的代理组,具体见:https://github.com/eycorsican/leaf/blob/master/README.zh.md#failover

写在最后

可以看到,Leaf 在分发一个请求时,并不管哪个服务器是否最优,尽管它的 failover 有一个健康检查功能,但也是可选的,它只管分发方式,如果 failover 设置超时为 fail-timeout=3 秒,那当前代理连接握手必须在 3 秒内完成,否则就下一个。

--

--