iptables CLUSTERIP构建独特的负载均衡集群

标签: iptablesCLUSTERIP负载均衡
3783人阅读 评论(8) 收藏 举报

我一开始不知道树莓派有什么好玩的,后来发现真正好玩的地方在于你要具有想象力,用它丰富的GPIO针脚去接各种外设…同样,iptables本身也没啥好玩的,真正好玩的地方,在于它的各种match,target模块,很多需要你自己写,但是其自带的那些已经够玩了,如果不够,请试试xtables-addons,再不行再自己写…

  本文介绍一个iptables比较好玩的模块,即CLUSTERIP,顾名思义,这是一个与负载均衡有关的东西。

动机

同一个服务分布在不同的进程中,一直以来都非常具有吸引力,特别是当我们知道受制于摩尔定律,程序已经不能跑得更快的时候,这种横向的扩展就更具有吸引力了。这就是负载均衡。

  广义来讲,多核CPU,多CPU等这些都是负载均衡的实例,因为它们的背景均是:单独的处理器性能遇到了不可逾越的瓶颈! 这是物理定律决定的,我们无法改变,然而,正所谓人生,我们无法延长其长度,但我们可以无限拓展其宽度

主动负载均衡总体结构

们来看一下典型的负载均衡的结构是什么样子的,它看起来是下图的样子:

这里写图片描述

这只是一个结构图,我来实际说两个例子,大家对它就有观感上的认识了。

1.Linux REUSEPORT机制

关于REUSEPORT的细节,在本文中不再赘述,感兴趣的可以参见:
Linux 4.6内核对TCP REUSEPORT的优化
基于UDP服务的负载均衡方法
REUSEPORT机制实现的负载均衡是一种在本机的不同进程之间分发请求的负载均衡方案,请注意,关键词是本机。在REUSEPORT机制之前,在同一台机器上,只允许一个<IP,Port>对的侦听套机制存在,彼时,不同的侦听进程要么侦听不同的IP地址,要么侦听不同的端口,若要实现请求在这些侦听进程之间分发,就不得不构建一个前端,比如使用DNAT的方式来向侦听不同的<IP,Port>对的进程分发请求。REUSEPORT机制省掉了这个前端,它可以直接处理负载均衡。

2.Linux LVS

和REUSEPORT不同,LVS并没有将服务进程局限在本机,而是可以在不同的机器的不同服务之间分发请求,虽然有这点不同,但是本质上,它们都是完全一致的,负载均衡本身都扮演了分发者的角色,因为它自己知道请求应该分发给谁。

  请注意关键,它自己知道分发给谁
  以上的这种负载均衡机制,我称为第一类负载均衡,这完全是为了与我紧接着要介绍的iptables构建的第二类负载均衡相区别,除此之外,再没有别的深意了。


被动负载均衡

OK,我接下来介绍另外一种负载均衡机制,我称之为第二类负载均衡

  这种负载均衡没有集中统一的分发者的概念,请求一开始就广播给所有的服务进程,由各个服务进程自己来决定该请求是不是分发给自己的。这听起来有点绕,我们来看个图:

这里写图片描述

这相当于每一个服务器上都会有一个分发者副本,它仅仅用来决定该请求是不是符合分发给自己的条件,如果符合,那么处理,如果不符合,直接丢弃,在逻辑上看来,这非常简单易懂。

  然而这是怎么做到的呢?严格来讲,做到这件事使用的技术是一个Trick,这种负载均衡采用了类似ARP欺骗的技术,在有人请求针对特定服务绑定的IP地址的ARP请求时,集群中的机器只要收到请求,便回复一个与该服务绑定的组播MAC地址,而不是自己的MAC地址!这就会诱导上游L3/L2设备在发送数据的时候,采用广播方式在每个端口均发送一份数据拷贝而不是像单播方式那般,仅仅在MAC/Port表不命中的情况下才会广播:

这里写图片描述

OK,现在数据请求可以到达每一台集群中的服务器了,接下来各个服务器将采用一模一样的Hash算法针对请求的来源IP地址做运算,运算结果决定了哪台机器接收这个请求并处理之:

这里写图片描述

可见,为了不引起冲突(同一个请求被不同的机器认领并处理),集群中的所有机器必须认领完全不同的Hash运算结果

  最简单的算法就是源IP地址对集群机器数量取模,集群中的n台机器按照从0开始到n1编号,每台机器认领自己编号的运算结果即可。最终的结果只要能保证同一个请求有且只有一台集群中的服务器处理即可!


iptables实现

了这么多,理论应该是讲清楚了,那么接下啦要实际部署一个这样的第二类负载均衡集群了。

  很幸运,虽然是如此简单的理论,我们也不必花几个小时时间自己写内核模块来实现,iptables/Netfilter已经完全实现了它,这就是iptables的CLUSTERIP机制!
我用一幅图来展示一个真正集群的配置,该集群中有3台机器:

这里写图片描述

【为了便于复制粘贴,我将命令行列如下】

# 服务器1上的配置
iptables -I INPUT -d 192.168.44.3 -i eth0 -p tcp --dport 80 -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:9A:1E:40:0A --total-nodes 3 --local-node 1
# 服务器2上的配置
iptables -I INPUT -d 192.168.44.3 -i eth0 -p tcp --dport 80 -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:9A:1E:40:0A --total-nodes 3 --local-node 2
# 服务器3上的配置
iptables -I INPUT -d 192.168.44.3 -i eth0 -p tcp --dport 80 -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:9A:1E:40:0A --total-nodes 3 --local-node 3            

CLUSTERIP还提供了profs接口,可以让你添加,删除或修改认领的运算结果

echo +$No. >/proc/net/ipt_CLUSTERIP/192.168.44.3   #添加一个认领的计算结果,No.为新的认领的计算结果
echo -$No. >/proc/net/ipt_CLUSTERIP/192.168.44.3   #删除一个认领的计算结果,No.为新的认领的计算结果

查看/proc/net/ipt_CLUSTERIP/192.168.44.3文件,如果它的内容是:

1,2

那么它的含义便是,数据请求到达本机时,拿源IP地址做Hash运算,结果如果是1或者2,那么本机就认领请求数据包继续让其在协议栈中被处理,否则就丢弃它。

  iptables的CLUSTERIP target模块额外还注册了一个nf_hook_ops,这是用来进行ARP欺骗的。


一点评价

进一步的关于iptables CLUSTERIP如何使用的问题,请自行查阅iptables的各类相关manuals,网上也有很多这种文章。本文最后,我想针对iptables CLUSTERIP进行一个细节上的评价。

  你可能会发现,和以往我们认识到的负载均衡集群不同的是,iptables CLUSTERIP集群中的每一台机器将会收到所有的流量,差异仅仅在于收到后是否继续处理这些数据,这会不会带来洪泛的问题呢?

  你觉得呢?

  其实,iptables CLUSTERIP适合的场景显然必然是最后一跳的场景,否则ARP透传就是个问题(严格来讲,由于L3设备几乎不转发广播,可以采用IGMP来规避,但这增加了实现的难度,也毫无必要),我觉得,即便在这最后一跳的内网,iptables CLUSTERIP对上下行的流量也有一定的要求。

  那就是,流量最好是不对称的,即外部流向集群所有服务器的组播流量要远小于从集群服务器中的某一台(即认领该请求的那确定的一台)流出的业务流量。这样一来,在目前的最后一跳均千兆,万兆的环境中,上述引发疑虑的洪泛就不再是个事儿了…

  没啥疑问了。OK,开始玩转XDP…

5
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:6377685次
    • 积分:78666
    • 等级:
    • 排名:第19名
    • 原创:1407篇
    • 转载:2篇
    • 译文:0篇
    • 评论:2995条