Skip to content

jursonmo/mwb

Repository files navigation

mwb (multi wan balance): 多wan负载均衡

相对原来做法的改进:
  • 少用了很多iptables conntrack connmark, --save-mark or --restore-mark
  • 自动添加本地路由到策略路由表,跟main路由表一样,应用层不需要配置wan ip是还要往策略路由表里加
  • 区分匹配用户自定义策略连接, ip ru add mark/0xf table table1,cat nf_conntrack 通过mark值不同来区分
  • 连接跟踪nf_conntrack绑定路由缓存,即每个连接只查找一次路由,之后该连接的所有数据包直接拿到路由信息并转发,提高转发效率,(同时把ip early demux 置0,也可相对提高转发效率, ip early demux作用是先查找skb属于哪个sk, 把sk的dst赋予给skb,这样就不用再查找路由了,对于来到本地的数据,这样提高了效率.如果是转发数据比较多,这样反而降低了效率)
  • 根据wan状态变化,策略路由自动添加及删除,main表默认路由的添加及删除
  • 均衡的单位(颗粒度)可以是连接connection, 也可以是“源地址和目的地址”的组合(这样保证某个pc跟某个服务器的数据一直就走同一个wan口)
  • 根据每个wan口流量的占用比例来负载(新到来的连接的选路原则:当任意一个线路的上行带宽利用率都没有超过85%,就走下载利用率小的线路,因为用户一般判断负载均衡是否有效,往往以下行带宽的均衡程度来判断。 当任意一个线路的上行带宽利用率超过85%,就走上行利用率小的线路,即上行带宽利用率超过85%的情况下,以上行利用率作为选路的优先考虑因素,因为上行带宽差不多满的情况下,新的连接继续选这条线路的话,这个线路就更拥塞。当然85%这个值,可以根据测试时的负载效果来调高或调低)
设计、实现过程
  1. 目的: 多wan负载,就要控制数据按照我们的要求走指定的wan口出去,现在的做法是按流量这个参数来选路,尽量往流量低的线路走

  2. 做法: 在内核netfilter prerouting 点注册一个模块,优先级在DNAT之后,这样可以保证目的ip是在做了dnat之后的,每当新连接的一个数据报文到达时,都进入我的模块,如果是从lan口进来的,模块再去判断哪个wan口的流量低,就给skb->mark 和 连接的mark 设置此wan对应标志,这样经过路由后,就路由到指定的wan出去,但要实现这一点,就必须给提前为每个wan口创建对应的策略路由和对应的路由表, 如下: 策略路由: ip ru add fwmark 1 table wan1_table 并且在 wan1_table里添加默认路由: ip ro default via xx.xx.xx.xx dev wan1 ;wan1_table 表里也要有其他网口的直连路由,这个由模块自动生成。

  • 连接跟踪记录mark和路由缓存: 此连接的下一个数据报文达到时,由于ct->mark已经保存之前标志了,不用去查看哪个wan口流量低了,只需要把skb->mark = ct->mark, 这样skb就能被路由到指定的wan口出去。 (这样skb还是会去找一遍路由,其实可以之前查找路由时,就可以把ct跟路由缓存dst绑定,而且是两个方向的路由缓存dst[dir],下一个skb到来时,直接到ct指向的dst[dir]赋给skb 就行,即每个连接只在刚开始时查找两次路由,每个方向各一次,以后此连接的所有数据报文都不需要查找路由,除非路由缓存过时,过时可能由多种原来导致,ip 有改变,接口有变化,反正这些能导致路由有变化的情况,系统都认为之前的路由缓存过时,所以每次把ct指向的dst[dir]赋给skb 时,都要判断下路由缓存是否过时,过时就要重新查找一遍,再赋给skb)

  • 目前这里的 连接跟踪 没有直接记录路由缓存,是struct mwb_entry 结构记录路由缓存: me 也有两个方向的路由缓存绑定me->dst[dir] ,即数据从lan->wan出去后,再有数据从wan回来时,也要路由,不如在模块里就查路由,并且把回来方向的路由缓存也绑定到me 上,这样以后此ct两个方向的所有数据报文都不需要再查找路由了。 me 是由另一种需求产生的,即某个客户端去到同一个服务器的数据,都走同一个wan口。 据说有些比较注重安全的系统,不允许同一个客户端对安全系统的访问过程中的两个连接的源ip不同,另一个原因是实现一个类似于路由缓存的效果。(新的内核是没有路由缓存的, trie) 类似于过去的路由缓存,去过的路由缓存是通过sip,dip ,mark ,iif, oif, tos来决定,现在没有路由缓存了,又想实现一对sip dip 走相同的线路,me 因此而生。

当skb进入模块,如果其ct->me 不为空,就说明这个连接是经过负载模块处理过的,就去查看me的dst[dir]是否可用,如果dst[dir]是空或者过时,就要查找路由,并把结果保存在me->dst[dir], 下次同样方向的skb再到来时,ct->me->dst[dir]就不为空了,skb可以直接引用。

以后可以优化地方或缺点
  • dns负载均衡, 在dns解释时就考虑负载的情况,不同isp线路情况回应dns 结果.
  • 没有考虑wan 口在不同isp 的情况. 当wan0 带宽剩余比较多,拦截客户端的dns解析,重定向到wan0 线路的isp dns 服务器上解析,这样解析出来的结果大多是该isp 下的服务器ip. 再根据解析的结果添加到路由表里,走wan0. 或者根据各个运营商的路由表路由

About

multi wan balance

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages