Google Maglev 牛逼的网络负载均衡器
Maglev 是什么
Maglev 是谷歌搞的一个工作在三层(IP层)的网络负载均衡器, 它是一个运行在普通的 Linux 系统上的巨大的分布式系统, 并且可以简单平滑的伸缩后端服务器数量, 谷歌在自己的数据中心便使用该方案做负载均衡, 后面又以论文的形式将 Maglev 的负载均衡方案分享了出来.
刚说 Maglev 是一个三层的负载均衡, 那么什么是三层的负载均衡呢?
就是当你访问一个负载均衡的 IP 的时候, 这个 IP 的后面是一个服务器组, 而不是单个服务器, 而这个服务器组中的任意一个服务器上面都可以监听该 IP 来提供对外服务, 这样达到的一个效果是不存在 IP 单点故障的问题, 并且该 IP 的服务能力可以通过增加机器来进行扩展.
它达到的效果如图所示:
Maglev 是如何工作的
首先, 我们来看一下 maglev 的数据包的流向图:
如图, 当一个用户访问一个带有 Maglev 负载均衡的服务的 VIP 的时候, 用户的请求首先通过 Internet 到达真实的服务节点所在的物理机房的核心交换机上, 也就是上图的 Router, 这个时候核心交换机通过 ECMP 的功能将请求该 VIP 的数据包均衡的发送给后面的 N 个 Maglev 节点(蓝色线1).
请求该 VIP 的数据包到达 Maglev 节点之后, Maglev 会知道该 VIP 对应哪些 Service Endpoint, 然后通过一种牛逼的一致性哈希算法选择一个 Service Endpoint 将数据包发过去(紫色线2), 而要返回给用户的数据包会由 Service Endpoint 直接返回到核心交换机上, 然后通过 Internet 返回给用户(红色线3).
以上简要的概括了数据包的是如何传输的, 看起来很简单, 那么整套体系要如何实现呢? 下面挑最重要的几个技术细节来详细讲解一下.
首先是 ECMP 等价路由功能, 它可以让交换机或者路由器使用多条不同链路而达到相同的目的地址, 一般的物理交换机都是支持该协议的, 只要打开该选项即可.
在物理交换机打开了 ECMP 的情况下, 对于同一个 VIP 地址, 只要有多个不同链路的路由信息, 交换机便可以工作, 那么这个路由信息是从哪里来的呢?
这个时候就轮到 Maglev 上场了, 首先每一个 Maglev 节点都会和核心交换机建立 BGP 连接, BGP 连接建立之后, Maglev 会通过该连接告诉交换机某某某 IP 我是可达的, 如果多个 Maglev 都告诉交换机说某某某 IP 我是可达的, 交换机上面便会记录多条类似于下面的路由条目:
<vip> via <Maglev1_IP> dev eth0
<vip> via <Maglev2_IP> dev eth0
<vip> via <Maglev3_IP> dev eth0
....
这个时候交换机在启用 ECMP 路由功能的情况下, 会根据上述的路由信息将数据包均衡的发送给多个 Maglev 节点, 好了, 这个时候数据包到了 Maglev 节点, 那么 Maglev 节点本身是如何处理这些数据包的呢? 如下图是数据包在 Maglev 节点上面的处理过程:
上面简要的说过, Maglev 要挑选一个 Service Endpoint 然后将数据包发给选中的 Service Endpoint, 那么两个问题, 如何挑? 如何发?
先说 Maglev 是如何挑选 Service Endpoint 的, 首先交换机会通过简单的一致性哈希算法将拥有相同5元组的 packet 发送给同一台 Maglev 节点, 然后 Maglev 通过 packet 目标 IP, 也就是 VIP 来选择对应的后端节点, 同样的在选择后端的时候 Maglev 也使用了一种一致性哈希算法, 这样便可以保证同一 TCP 连接上的所有的 packet 会打到相同的 Service Endpoint 上. 选择好后端之后, Maglev 会将该5元组对应的后端记录在自己的 connection tracking 表中, 等到下个数据包来的时候, 只要根据包的5元组直接查询这个 connection tracking 表即可. 那为什么有了一致性哈希选择后端, 还要有 connection tracking 呢? 这是因为当一个 VIP 对应的 Service Endpoint 扩容或者缩容的时候, 一致性哈希选择的结果会发生变化, 这样会导致同一连接上的包选择的后端不一致, 造成网络错误.
然后在说说 Maglev 是如何将数据包发送给挑好的 Service Endpoint 的, 从原理上来说, Maglev 会将收到的数据包封一层 GRE/IP 头然后发给 Service Endpoint, 相应的 Service Endpoint 端需要对收到的 packet 进行解包, 还有一种比较简单的修改方式, 如果 Maglev 节点和 Service Endpoint 是在一个二层网络里的话, 那么只要修改数据包的目标 mac 地址为选中的 Service Endpoint 的 mac 地址便可以将数据包发送过去, 后端也不需要进行解包. 修改好数据包之后, Maglev 只要把修改好的包从相应的网卡上发出去即可. 这里涉及到了读包写包的问题, 如果直接使用 Linux Kernel 提供的方法来直接读写 packet, 会发现性能不能满足需求, 在这里可以使用一些 Kernel Bypass 的技术来做, 比如 dpdk 或者其他 Kernel Bypass 的技术.
至此, Maglev 最重要的原理已经讲清楚了, 当然还有更细节的, 比如 Maglev 的一致性哈希算法是如何实现的等等, 这里不再赘述, 如果你想更加深入的了解可以看看 Maglev 的论文. 本文也是对 Maglev 论文的一个简单总结, 其中如果有理解错误或者不准确的地方也欢迎指正.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。