“Backconnect”(回连)是那种出现在代理文档中却从未被定义的术语,通常是因为编写文档的人已经忘记了这个词曾经也让人感到陌生。它描述的是一种架构,一旦你理解了这种架构,产品的其余部分也就说得通了:为什么只有一个地址需要配置,为什么定位信息存放在用户名里,以及为什么你的 HTTP 客户端会在没有任何明显异常的情况下悄悄地破坏轮换。
名称的由来
较早的模式是一份列表。你购买一组代理,得到一份包含地址和端口的文件,你的代码直接连接到每一个地址。管理它们是你自己的问题:哪些还活着,哪些在哪个目标上被封了,如何在它们之间分摊负载,列表变化时该怎么办。
Backconnect 把这一切反过来。你连接到单一的网关地址,网关代表你通过其网络中众多节点之一回连出去。你事先不会知道出口地址,也不需要管理列表,因为路由决策是在请求发生的那一刻由服务商那一侧完成的。这就是整个理念:一个稳定的前门,多个不断轮换的后门。
在实践中,“backconnect proxy”(回连代理)、“rotating proxy”(轮换代理)和”gateway proxy”(网关代理)如今或多或少可以互换使用,backconnect 强调的是架构,而 rotation 强调的是这种架构所产生的行为。
单次请求中发生了什么
具体来说,当你的客户端通过一个 backconnect 网关发送请求时:
- 你的客户端打开一个到网关的连接,例如
p.shifter.io:443,并使用用户名和密码进行认证。 - 网关解析你的用户名,其中携带的信息不止身份。国家、地区、城市或 ASN 的定位标记,以及会话标识符和 TTL,都编码在其中。
- 它从当前可用的池中选择一个匹配这些约束的出口节点。“可用”是关键词,因为这个池是一个不断更替的群体,具体内容见服务商如何构建和刷新池。
- 它通过该节点转发你的请求,因此目标看到的是该节点的住宅地址,而不是你的地址或网关的地址。
- 响应沿相同路径返回。
如果你提供了会话标识符,网关会记住这个映射,并将带有该标识符的后续请求路由到同一个节点,直到 TTL 到期或该节点掉线。如果你没有提供,下一个请求会得到一个独立选择的出口。
这就是为什么定位信息存放在用户名里。因为只有一个端点,所以针对每次请求的指令必须通过代理协议在隧道建立之前所提供的唯一一个可按请求变化的字段来传递。
# same host and port, different behaviour, expressed entirely in the username
curl -x customer-USERNAME:PASSWORD@p.shifter.io:443 https://ipinfo.io/json
curl -x customer-USERNAME-country-de:PASSWORD@p.shifter.io:443 https://ipinfo.io/json
curl -x customer-USERNAME-country-de-sid-abc123-ttl-600:PASSWORD@p.shifter.io:443 https://ipinfo.io/json
这对你的代码意味着什么变化
这种架构带来三个实际后果,其中第一个引发的困惑比这个产品中任何其他方面都多。
轮换是按连接发生的,而不是按请求。 出口是在与网关建立隧道时被选定的。现代 HTTP 客户端会保持连接存活并复用它们,所以如果你的客户端在一个复用的连接上发送十个请求,这十个请求全部通过同一个出口离开,看起来就像轮换坏了一样。其实并没有坏:你的客户端只是在做它被设计要做的事。修复方法和诊断方式见 IP 不轮换,简而言之,在独立进程中运行的 curl 循环会轮换,而共享的会话对象则不会。
没有需要管理的 IP 列表,也没有可以归咎的 IP。 健康状况是路由(即目标加地理位置)和会话的属性,而不是某个可以加入拒绝列表的地址的属性。这彻底改变了监控和故障处理的方式,详见大规模监控代理健康状况。
配置是静态的,行为是动态的。 主机和端口从不改变,所以把一个任务从轮换的美国出口切换到粘性的德国出口,只是一次字符串修改,而不是一次重新部署。这正是让多市场采集成为配置事项而非基础设施项目的原因。
Backconnect 与端口列表模式的对比
较早的模式仍然存在,这种比较很有用,因为它解释了这个行业为什么会转变。
使用端口列表时,你知道自己的地址,这听起来像是一个优势,但大多数情况下并不是:你继承了存活检测、负载分摊和替换的工作,你的容量是固定数量的端口,而不是随需求灵活变化的东西。定价也遵循同样的模式,按端口而不是按工作单位计费,这一模式在为什么按端口计费的时代已经结束中有所讨论。
使用 backconnect 时,你放弃了事先知道出口的能力,但换来了不必管理出口的好处。容量变成了带宽和并发数的问题,而不是你购买了多少端口的问题,轮换成为一个参数,而不是你自己编写的实现。
较早的模式仍然占优的情况是,当你确实需要同一个地址持续存在时,这正是静态 ISP 代理存在的意义,详见 ISP 代理与住宅代理对比。
Backconnect 网关内部的粘性会话
值得按其本质来理解粘性会话:它是网关持有的一个映射,而不是你拥有的一次分配。
你选择一个标识符,网关将其与某个出口节点关联,携带该标识符的请求会沿着同一路由走,直到 TTL 用尽。因为该节点是一台真实的家用设备,它也可能在 TTL 到期之前就消失了,这就是为什么粘性会话是尽力而为的,而不是一份租约。如果代码把序列中途的地址变化当作错误而不是正常事件来处理,就会出现与服务商本身无关的不稳定问题。相关行为见粘性会话与轮换会话对比,底层的更替机制见轮换的工作原理。
总结
Backconnect 意味着你连接到一个端点,它则通过许多出口回连出去,按请求从当前可用的资源中选择出口。正是这种架构导致了单一的主机和端口,导致国家、城市、会话和 TTL 被编码在用户名中,也导致你无需管理地址列表。这也解释了这个产品中最常见的困惑来源:轮换是在连接建立时决定的,所以复用池化连接的 HTTP 客户端会把每个请求都发送到同一个出口,看起来就像轮换失败了一样。把出口当作短暂存在的东西,把会话当作映射而不是分配,把健康状况当作路由的属性,这样这种架构就不会再让你感到意外。
那个网关就是通往住宅代理的全部接口:一个主机、一对凭证,轮换、地理位置和会话行为按请求表达,并按每 GB而非按端口计费。如果你对这些术语还不熟悉,术语表涵盖了其余的内容。