目录
简介
参考资料:Maglev: A Fast and Reliable Software Network Load Balancer
https://storage.googleapis.com/pub-tools-public-publication-data/pdf/44824.pdf
自2008年起,google已经用Maglev来部署服务的负载均衡,这是一套与传统硬件负载均衡不同的软件网络负载均衡。而Maglev负载均衡器可以单独部署,也可以直接部署在server节点上。
LB工作流程
首先是通过DNS把请求分配到该用户相近的集群中(分配给用户的DNS解析IP为该集群vip)。集群的核心路由器将请求转发给Maglev(负载均衡器)。
集群中多个Maglev通过BGP(边界网管协议)向路由器报告自己所监听的vips, 核心路由器通过ECMP(等价多路径)协议将请求分发给Maglev, 而ECMP可以保证同一条流分发到同一个Maglev,可以保证用户数据流通畅。但是ECMP还有一个缺点,所有链路等价的(不能权重配置),必须所有Meglev处理能力是相近的,否则,可能会发生拥塞。
Maglev在收到请求后,再做负载均衡,分发给服务节点。在对请求选定服务节点之后,对该请求做封包处理,加上Gre header发给节点。节点将解封并处理请求,而返回的response直接以vip为源地址,用户地址为目的地址,发往路由器(DSR,Direct Server Return),不再经过Maglev. 这样又提高了Maglev一半的处理能力!
Maglev内部架构
Maglev分为两个部分:控制器和转发器
控制器
通过心跳检查转发器是否正常,并将所有的vips通过BGP通知给路由器
转发器
每一个vip关联到一个或多个后端池(BP: backend pool),每一个BP包含多个后端server的真实ip或者其他BP。同时对每一个后端server做健康检查,通过一些策略,将数据包均衡负载到各个健康的后端server上去。
转发器实现
转发器作作为核心模块通过steering module内核模块直接从网卡收发包,从而绕过了linux kernel协议栈,从而实现快速转发。
转发器收包时先将数据包五元组做哈希运算,并根据哈希值放入到不同的接收队列,每个接收队列的都有一个独立的线程处理其数据包重写(添加Gre header)的逻辑。
线程处理先做vip匹配过滤,再计算五元组哈希,查找连接跟踪表(每个线程都有一个独立的连接跟踪表),查到就直接用该连接信息添加Greheader,查不到就通过一致性哈希选择一个后端服务器,并添加对应Gre header,同时将该五元组的连接添加到连接跟踪表中去。数据包添加完Gre header之后,就将数据包发送到对应的发送队列(即一个处理线程对应一个接收队列和一个发送队列)。
muxing module内核模块通过poll轮询所有的发送队列,将数据包都发送到网卡。
快速包处理
免拷贝
steering module和muxing module使得收发包绕过了内核,避免了kernel昂贵的开销。且共享内存处理包,避免内存反复拷贝的开销。
启动时建立packet pool的共享内存池,steering和muxing各自有环形一个指针队列,每个指针指向packet pool中的一个packet对象。接收端有3个指针指向接收队列,
1. received指针: 网卡将接收到的数据包放在这个指针对应内存,并让received指针向前移动。
2. processed指针:steering将received数据包分发给处理线程,processed指针向前移动。
3. reserved指针: 将未使用的packet对象存环形队列,reserved指针向前移动。
发送端也有3个指针指向发送队列,
1. sent指针: 网卡将就绪的数据包发送,并让sent指针向前移动
2. ready指针:muxing将重写包头的数据包放入队列,改为就绪状态,ready指针前进
3. recyle指针:muxing将已发送数据包返回packet pool, 并将recyle指针前进
批处理
1. 因为各线程间没有锁,没有竞争,将每个处理线程固定到一个CPU核心,降低内核切换,提高线程效率
2. 转换器会对进来的包设置延迟时间,缓冲数据包,再进行批处理。批处理也会提高转换效率
后续如何一致性哈希选择后端服务器,错误处理,vip匹配,这些这里就不多讲了(因为我也没看那么细^_^),有兴趣的朋友可以去阅读原文,这里只做一个大体结构逻辑的描述。