LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 931|回复: 2

adsl网关问题?

[复制链接]
发表于 2003-10-27 14:38:49 | 显示全部楼层 |阅读模式
加入我有两个adsl,都拨号连接,
想要对私网的机器的通信,用两个ip进行负荷分担,
应该如何实现?
发表于 2003-10-27 17:08:32 | 显示全部楼层
关于双连接的负载均衡-----转贴

向原作者致敬!

关键词:ADSL,PPP,拨号上网,负载均衡,load balancing


版权及免责声明:

本文件意在有所助益,但不保证如此,也不对诸如销售或特殊应用之类做任何隐含承诺。如果你的网络、机器或其它因此停止运转或不能正常工作,很抱歉,我将不对此负责。

本文件遵循 Open Publication License v1.0 或更高版本。最高版本可在此网站获得:

http://www.opencontent.org/openpub/

本文件及其副本可以任何格式和媒介自由散发(包括销售或赠送)而无须向作者缴纳任何费用。然而任何修正及/或建议,皆须通知文件的维护者。只须符合以下条件,您也可创建自己的派生版本:派生版本必须遵循相同版权(即Open Publication License v1.0 或更高版本)。

Jing Tuo 版权所有 (c) 2002。

包级别的 TCP/UDP 负载均衡和NAT(Network Address Translate)不能并存。

这是什么意思呢?简单来说,如果你有动态IP的连接,一个使用私有IP地址的局域网,通过NAT(Network Address Translate)上网,现在觉得速度不够,想再加一条使到某一Internet主机的速度加倍(现在中国大陆的典型情况),对不起,你就死了这条心吧,这是不可能的。

这里所说的连接包括 Ethernet,PPPoE,PPPoA,PPP,以及SLIP等等。并且,这是TCP/UDP 协议的内在机制造成的,和软/硬件无关。任何架构在 TCP/UDP 之上的应用,不论硬件还是软件,皆不能绕过此限制。

注意,如果你的局域网使用公用IP(public IP)而不需要NAT,则不在此列。

如果你想知道原因或者质疑我的结论:),请继续往下读。


本文假设


1.你已经阅读过 Linux Advanced Routing & Traffic Control HOWTO,特别是 4.2 小节的 Routing for multiple uplinks/providers,4.2.1小节Split access 和4.2.2小节 Load balancing。此文(以下按惯例简称lartc)非常清楚的说明了连接级别的TCP/UDP 负载均衡。

________

+------------+ /

| | |

+--- NATed ---+ Provider 1 +-------

__ IP1 | 100.0.0.1 | | / remote host 1

___/ \__ +------+-------+ +------------+ |

_/ \_ | if1 | /

/ local host 1\ | | |

| Local network -----+ Linux router | | Internet

\_local host 2/ | | |

\__ __/ | if2 | \

\___/ +------+-------+ +------------+ |

IP2 | 150.0.0.1 | | \ remote host 2

+--- NATed ---+ Provider 2 +-------

| | |

+------------+ \________

-------------------------------------

那么连接级别和包级别的负载均衡究竟有何不同?

1、连结级别的负载均衡
Linux 2.4内核支持连结级别的负载均衡。为理解这个问题,这里首先简述 Linux 的静态路由机制。当一部 Linux 主机收到一个需要转发的IP包时,它首先检查Cache中是否有相关的路由信息:如果有的话,会直接使用;否则再查找路由表。Cache中一段时间不使用的路由信息会被丢弃。如果设置了 MultiPath 路由,则选择哪一个路由是随机的,但随后的IP包都会走这条路由,直到Cache中的路由信息被丢弃。
比如,当LAN上的主机 local host 1 向 remote host 1 发起一次连结的时候,Linux router 在Cache中找不到有关remote host 1 的路由信息,因此转去查找路由表,当它发现有一个 MultiPath 路由的时候,会随机选择一个路由,比方说 if1,并把此路由加入Cache;下一个从 local hsot 1到 remote host 1 的 IP 包到达时,Linux router 直接在Cache 中找到路由信息然后直接转发,也就是说,所有目的地为 remote host 1 的 IP 包都会经由 if1 转发直到 Cache 中相关路由信息失效并被丢弃为止而不会经过if2,即使if2完全空闲也是如此。
因此,和 remote host 1 之间的通信并不会从附加的第二条连接中获益。其实际效果就是你用 Realplay 看网络电影时效果没有改善,当然心理作用除外
如果与此同时 local host 1 有发起一条到 remote host 2 的连接,则有可能这一次会使用 if2。其实际效果就是你用 Realplay 看网络电影时用 flashget开8个并发线程到一个FTP站下载一个 600M Redhat ISO 文件,两者不会互相影响。
那么,下载 ISO 文件的同时 localhost 2 发起一条到 remote host 2 的连接,会出现怎样的情况?是简单地走if1?又或别有蹊径?请读者思考。

2、包级别的负载均衡
现实中这种一边忙一边无所事事的情况在所多有,毋庸赘述。那么如何改善呢?很自然的想到,我们可以把同一条TCP/IP连接中的IP包同时从两条上行连接中发出,左右开弓,不就可以了吗?实际上,我们在 PPP Multilink 就是这么干的,不过现在没有服务器的支持,要靠自己。这是Internet,因此已经有人想到这一点并且编写了内核补丁供下载,请搜索 equalize_2.4.18.patch。
需要特别提醒你的是,请确保该补丁的日期是 Fri Mar 22 2002,而不是有问题的 Thu Mar 21 2002 版本。另外,根据我的经验,这个 patch 也可以用于 2.4.19 内核。
重新编译了内核以后,你可以使用 equalize 关键字了。如果你的 LAN 使用公有 IP 地址,那么恭喜你,你现在可以在双倍速度下用 Realplay 看网络电影了。但是正所谓人生不如意事常八九,如果你使用的是私有 IP 地址配合以NAT上网,让我们来看看当 local host 1 对 remote host 1 发起一次连结时会发生什么。
local host 1 第一次从(192.168.0.1,5000)向 remote host 1 (200.0.0.1, 80) 发起一条连接,现在第一个 IP 包 (SYN 包)已经到达 Linux router。既然是第一次,Cache 中当然没有有关路由信息,Linux router 查找路由表,发现带 equalize 标记的 MultiPath 路由,因此随机决定如何转发此IP 包 -- 好,这次茫茫中命里注定从 if2 走 并且雁过留声,在 Cache 中添加一条到 remote host 1 的路由信息-- 既然 local host 1 的 IP 是私有的,NAT 起作用,转换源地址为 (150.0.0.1,7000)后发出,没问题,remote host 1 收到并向 (150.0.0.1,7000) 发回SYN+ACK 包表示接受连结。Linux router if2 收到返回的 SYN+ACK 包,早有准备,NAT 再次转换目的地址为 (192.168.0.1, 5000)。
第一回合。到目前为止一切 OK。
紧接着 local host 1 (192.168.0.1, 5000) 按规矩再向 (200.0.0.1, 80) 发送 ACK 包表示确认。此 ACK 包又来到Linux router 这个岔路口,它将走向何方呢?既然设定了 equalize,Linux 不会根据先前生成的路由表 Cache 中的记录(就是由 SYN 包生成的)来决定走法,相反,它从 Cache 中删除该记录,然后重新查找路由表。这导致又一次重新选择路由,可能是 if1,也可能是 if2。
如果又是 if2,很好,remote host 1 收到,握手完成,连接建立。
若是 if1,又当如何呢?很不幸,if1 将该包源地址经 NAT 转换为 (100.0.0.1,6000),然后丢上 Internet,一路平安到达 remote host 1。remote host 1 正在苦等从 if2 (也就是 150.0.0.1,7000) 来的 ACK 包,没想却收到一个从(100.0.0.1,6000) 来的 ACK 包,它作何打算呢?难道说,反正是 ACK 包,马马虎虎将就着用用吗?很明显,这不是个好主意。其次,即便意欲如此,remote host 1 如何判断这个 ACK 包和哪一个 SYN 包关联呢?因此,
唯一合理的措施就是:忽略它,当没看见好了。
丢弃此来路不明的 ACK 包后,remote host 1 继续等待中......结果可想而知:不能同步,连结建立失败。这里 TCP/IP 的重传机制并不能解决问题,remote host 1 并不认为这是一个正常的 TCP 包,虽然它是一个正常的 IP 包。
刚才提到如果走的是 if2,非常幸运,连接可以建立。同样,以后 remote host 1 会收到所有数据包,不论是从 if1还是 if2 来的,只是从 if1 来的 TCP 包一概按例办理,全部丢弃。好在local host 1 会重传这些被丢弃的包,总有机会走到 if2 而被收到,因此连结还可以勉强维持,只是比较慢而已;当然,在某种极端情况下,也可能中途断掉。
所以,equalize 负载均衡和 NAT 在一起工作,可能会导致建立连结失败或者较缓慢的连结。换句话说,1+1 < 1。
最后有一个好消息,不是大好,是小好:ICMP 协议在此种情况下可以工作,也许你可以试着用它干点什么。当然这也意味着一个使用动态IP对你发动 ICMP 攻击的黑客有双倍的可用带宽
注1:2.4内核中 MultiPath 设定的具体的位置在 Networking options -> TCP/IP networking -> IP: advanced router -> IP: equal cost multipath,.config 文件中的对应行为 CONFIG_IP_ROUTE_MULTIPATH
注2:iproute2 的手册明确指出,仅当内核打过补丁的情况下 equalize 关键字才能工作,原文"equalize only works if the kernel is patched." iproute2-ss010824, p26.
注3:本文所说的随机并不是真正意义的随机,但我们假定考察真正随机的情况。
注4:对于如何处理所谓"来路不明的 ACK 包",可能是实现相关的,还请了解的朋友说一说。
附录A
关于 lartc 中 split access 和 load-balancing 设置的一点说明:
在 load-balancing 小节中提到"如果你已经如前所述设置了 split access 的话 load-balancing 真的不是太难"。而在 split access 小节中就给出了一堆命令,T1 T2 P1 P2 IF1 IF2 什么的。很多人不明白这些命令到底有何作用。其实这些命令是说,到 P1_NET 去的走 if1,到 P2_NET 去的走 if2,大家各行其道。那么,我到 P1_NET 去的走if2,到 P2_NET 去的走 if1,可不可以呢?理论上也是可以的,但是这里有个问题。如果 P1_NET 和 P2_NET 分属两家不同的 ISP,则从 if2 到 P1_NET 就要走远路经过交换中心,而这可能会造成瓶颈。
至于从 P1_NET 和 P2_NET 回来的包,已经超出了我们的控制范围,只能等它到 IF1或 IF2。如果出于某种原因路由不正常,没有收到回音,那我们能做的也只是承认失败而已。
因此这段命令想要防止舍近求远,如此而已。
另外这段命令似乎有点问题。我已经在lartc邮件列表中请求帮助了,希望能尽快有一个满意的答复。
在搞清楚这一点后,如果读者的 P1_NET 和 P2_NET 和我一样其实是同一家 ISP 的网络,这段准备功夫是完全可以省去的。
发表于 2003-10-27 17:16:08 | 显示全部楼层
转自chinaunix

可以试试以下方法:
由於前些日子, 我所服務的單位, 決定將原本使用的專線退租, 改用 ADSL ?硖峁
上網的服務, 為了降低 ADSL 斷線無法連線的情形, 所以由 SeedNet, Hinet 各申
請了一條單機型的 T1/384 ADSL ?硎褂.

但是一般 ISP 業者似乎沒有提供兩條線路頻寬合用的服務, 更何況是使用兩家不同
ISP 的線路, 所以決定自己利用 Linux 的 Equal-Cost MultiPath Routing (ECMP)
功能?斫鉀Q這個問題.

關於 ECMP 的設定說明, 可以參考
http://www.study-area.org/tips/m_routing.htm

初期, 我利用上述的功能?硖幚, 但是發現效率不怎麼好, 由於路由的決定, ?K不
是依據 packet ?韨魉, 所以出去的時候, 同一個 session 只會使用一條線路,
仍然會常常造成, 明明另一條線路沒有什麼流量, 但是大家都擠在同一條線路的情
形發生.

在 iproute2 的說明中有提到 equalize 參數, 會將 packet 分散到不同的線路上
面, 但是 kernel 需要另外的 patch 才能運作, 上網查了一下, 有找到下面這個
patch:

http://www.van-dijk.net/linuxker ... ualize_2.4.18.patch

測試後發現的確可以同時使用不同的線路傳送 packet. 現在說明一下, 如何做到這
個功能:

1. 你必須要有 iproute2 套件. 另外由於要對 kernel 加上另外的 patch, 所以相關
的工具也是必要的.

2. 由 http://www.kernel.org/ 抓下 linux-2.4.18.tar.bz2 與上述的 patch.
上述的 patch, 我在 2.4.18 之後的版本都裝過, 都可以正常使用, 之前的 kernel
沒有試過, ?K不清楚... 不過如果 2.4.18 應該算是 2.4 版本中最穩定的一個版
本, 如果你還在用舊的 kernel, 建議升級到這個版本.

tommywu@fw:/usr/src$ tar jxvf linux-2.4.18.tar.bz2
...
...
tommywu@fw:/usr/src$ cd linux
tommywu@fw:/usr/src/linux$ patch -p1 < ../01-equalize_2.4.18.patch
patching file Documentation/networking/load-balancing.txt
patching file include/linux/in_route.h
patching file net/ipv4/fib_semantics.c
patching file net/ipv4/ip_output.c
patching file net/ipv4/route.c
patching file net/ipv4/udp.c

這個 patch ?K不會新增任何的設定, 所以你可以參考上述 ECMP 文件中的設定選
項?碓O定你的 kernel. 然後重新 make 一個新的 kernel ?硎褂. 我通常會選取
下面這幾個功能:

CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_FWMARK=y
CONFIG_IP_ROUTE_NAT=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_TOS=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_ROUTE_LARGE_TABLES=y

3. 利用上面的 kernel 重新開機之後, 就應該可以使用 equalize 參數了. 多數的設
定都與上述的 ECMP 文件相同, 只是多了一個 equalize 參數. 舉例?碚f:

# 對外網卡
EXT_IF="eth0"

# HiNet IP
EXT_IP1="111.111.111.111"
EXT_MASK1="24"
GW1="111.111.111.1"

# SeedNet IP
EXT_IP2="222.222.222.222"
EXT_MASK2="24"
GW2="222.222.222.1"

# 設定 ip
ip addr add $EXT_IP1/$EXT_MASK1 dev $EXT_IF
ip addr add $EXT_IP2/$EXT_MASK2 dev $EXT_IF

# 設定 HiNet routing
ip rule add from $EXT_IP1 lookup 201
ip route add default via $GW1 dev $EXT_IF table 201

# 設定 SeedNet routing
ip rule add from $EXT_IP2 lookup 202
ip route add default via $GW2 dev $EXT_IF table 202

# 設定 Default route
ip route replace default equalize \
nexthop via $GW1 dev $EXT_IF \
nexthop via $GW2 dev $EXT_IF

# 清除 route cache
ip route flush cache

利用上面的設定, 我們就可以將兩條線路合?闶褂. 以 T1/384 的 ADSL ?碚f, 一般
上傳的頻寬約可到 40KB 上下, 現在利用這個 patch, 我們上傳一個檔案試看看:

tommywu@hisstby:/usr/src$ ftp ftp.teatime.com.tw
Connected to http://www.teatime.com.tw./
220 ProFTPD 1.2.5rc1 Server (Debian) [211.23.144.122]
Name (ftp.teatime.com.tw:tommywu): tommy
331 Password required for tommy.
Password:
230 User tommy logged in.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> bin
200 Type set to I.
ftp> put patch-2.4.19-pre6.bz2
local: patch-2.4.19-pre6.bz2 remote: patch-2.4.19-pre6.bz2
200 PORT command successful.
150 Opening BINARY mode data connection for patch-2.4.19-pre6.bz2.
226 Transfer complete.
3858685 bytes sent in 49.92 secs (75.5 kB/s)
ftp> quit
221 Goodbye.
tommywu@hisstby:/usr/src$

可以超過 40KB, 也就是的確會同時使用到兩條線路?韨魉.
如果有興趣, 可以到下列的網址查看流量:

http://fw1.tahsda.org.tw/stats/mrtg/
http://fw2.tahsda.org.tw/stats/mrtg/

要注意這只有出去的 packet 是我們這端所能控制的, 回?淼 packet 就不是我們
可以控制了, 所以出去的流量在不同的線路上看起?硎穷?似的, 但是回?淼牧髁烤
不一定了. 如果要控制進?淼牧髁, 可能要利用 DNS 的方式?砜刂屏.

接下?, 要考慮一條線路斷線時, 要改變 routing table 的設定. 由於 ADSL router
應該都有支援 SNMP 的功能, 所以我們可以利用 SNMP ?砼袛嗍欠駭嗑. 你要先確定你
的 linux 中有 snmpd, snmp 套件.

我們有兩種方式?硖幚, 第一種是利用 snmp traps.

以 arcatel 340 ?碚f, 內定的 password 應該是 12345.

telnet 192.168.1.1 之後, 打入密碼, 在 > 符號打入 snmp, 就會進入 snmp> 設定
目錄, 打入 snmp trap help 有說明如下:

snmp trap add <community> <IP addr> [<port>]
- add a trap destination
snmp trap delete <community> <IP addr> [<port>]
- delete a trap destination
snmp trap flush - delete all trap destinations
snmp trap list - list trap destinations

假定你要收 trap 的 ip 是 192.168.1.254, 就打入

snmp trap add public 192.168.1.254

就可以了. 這樣就應該在該機器可以收到相對的 snmp traps.
以上面 Hinet/SeedNet 兩個線路?碚f, 如果要在同一網段上, 要先改變其中一個 ATU-R
的 ip 才可以, 內定都是 192.168.1.1, 我們把其中一個改成 192.168.1.2

然後在 192.168.1.254 機器上安裝 snmptrapd, 修改 /etc/snmp/snmptrapd.conf
加上下面兩行:

traphandle .1.3.6.1.6.3.1.1.5.2 /usr/local/bin/adsl_up
traphandle .1.3.6.1.6.3.1.1.5.3 /usr/local/bin/adsl_down

然後寫 adsl_up, adsl_down 兩個 script ?砀 route table.
內容大約是:

#!/bin/bash

read DUMMY_HOST
read ROUTE_IP

case "$ROUTE_IP" in
192.168.1.1)
ip route replace default ....
;;
*)
echo "snmp traps from unknown ip?"
esac

這樣子就會在每次斷線或恢?瓦B線時收到 ATU-R 的通知了.

另外, 如果不想使用 snmp trap, 要使用 polling 的方式, 主動去查詢線路情形,
可以使用 snmpwalk ?硖幚, 用上面的例子, 可以先執行

snmpwalk 192.168.1.1 public interfaces.ifTable.ifEntry

會出現一堆資料, 看一下 adsl 在的 index 是 20.

interfaces.ifTable.ifEntry.ifDescr.20 = ADSL physical interface
interfaces.ifTable.ifEntry.ifType.20 = adsl(94)

線路狀態在

interfaces.ifTable.ifEntry.ifOperStatus.20 = up(1)

up(1) 表示連線中, 所以執行

snmpwalk 192.168.1.1 public interfaces.ifTable.ifEntry.ifOperStatus.20

會得到

interfaces.ifTable.ifEntry.ifOperStatus.20 = up(1)

當斷線時, 上面就不會在 up(1) 的狀態.
所以可以寫個 adsl_test 的 script

snmpwalk 192.168.1.1 public interfaces.ifTable.ifEntry.ifOperStatus.20 |
grep "up(1)" | wc -l

如果得到 0 就是斷線.

上面就是使用 snmpwalk ?聿樵兙路的方法. 這個我在 arcatel 340 上面使用,
可以正確得知線路的情形. 另外, 在我家的 cisco 677 上, 在 bridge mode 下,
使用 snmpwalk 查詢線路都是 up(1), 無法知道線路情形... 不過如有?動, 仍可
以收到對應的 snmp traps.

這兩種方式各有利弊, 第一種方式無法得知一開始的狀態, 第二種方式無法即時
得知狀態的改變, 所以通常會同時利用兩種方式?硖幚, 以上述的例子?碚f, 我
們可以使用下列的 script ?硖幚:

#!/bin/bash
# chk_adsl: check the status of ADSL and change routing table

# SNMP tree
SNMP_KEY="interfaces.ifTable.ifEntry.ifOperStatus.20"

# 對外網卡
EXT_IF="eth0"

# HiNet IP
EXT_ATUR1="192.168.1.1"
EXT_IP1="111.111.111.111"
EXT_MASK1="24"
GW1="111.111.111.1"

# SeedNet IP
EXT_ATUR2="192.168.1.2"
EXT_IP2="222.222.222.222"
EXT_MASK2="24"
GW2="222.222.222.1"


STATUS1=`snmpwalk $EXT_ATUR1 public $SNMP_KEY | grep "up(1)" | wc -l`
STATUS2=`snmpwalk $EXT_ATUR2 public $SNMP_KEY | grep "up(1)" | wc -l`

if [ "$STATUS1" = "0" ]; then
if [ "$STATUS2" = "0" ]; then
# ALL line down
echo -e "\n\
ALL ADSL DOWN!\n\
Date: $(date)\n\
Host: $(hostname)\n\
" | /bin/mail -s "$(date) ALL ADSL DOWN!" root
else
# ATUR1 down, ATUR2 up
echo -e "\n\
ADSL $EXT_ATUR1 DOWN!\n\
Date: $(date)\n\
Host: $(hostname)\n\
" | /bin/mail -s "$(date) ADSL $EXT_ATUR1 DOWN!" root
ip route relpace default via $GW2 dev $EXT_IF
ip route flush cache
fi
else
if [ "$STATUS2" = "0" ]; then
# ATUR1 up, ATUR2 down
echo -e "\n\
ADSL $EXT_ATUR2 DOWN!\n\
Date: $(date)\n\
Host: $(hostname)\n\
" | /bin/mail -s "$(date) ADSL $EXT_ATUR2 DOWN!" root
ip route relpace default via $GW1 dev $EXT_IF
ip route flush cache
else
# All line up
echo -e "\n\
ALL ADSL UP!\n\
Date: $(date)\n\
Host: $(hostname)\n\
" | /bin/mail -s "$(date) ALL ADSL UP!" root
ip route replace default equalize \
nexthop via $GW1 dev $EXT_IF \
nexthop via $GW2 dev $EXT_IF
ip route flush cache
fi
fi


利用上面的 script, 我們只要在 snmptrapd.conf 中將相關的 traphandle
指到這一個 script, 就可以依照線路的狀態?碜鰧奶幚. 當然, 如果你
的線路不只兩條, 我想應該也可以照上面的作法自己試試看.
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表