在我們?nèi)粘_\(yùn)維工作中,經(jīng)常會碰到負(fù)載均衡器后端應(yīng)用代碼更新、臨時(shí)剔除后端服務(wù)器、排查一主機(jī)應(yīng)用故障等,往往我們會選擇比較粗魯?shù)淖龇ǎ苯油V够蛑貑?yīng)用服務(wù),讓負(fù)載均衡器探測服務(wù)不可用將其剔除。這樣帶來的壞處是用戶與服務(wù)器已經(jīng)建立的連接會被中止,開發(fā)人員無法對已經(jīng)停止服務(wù)的主機(jī)進(jìn)行調(diào)試。現(xiàn)介紹一種較為溫柔的做法,即通過禁用/啟用成員的方式來達(dá)到目的。本文針對目前最為流行的負(fù)載均衡器逐一進(jìn)行介紹。包括LVS、Haproxy、F5在命令行模式下的實(shí)現(xiàn)(方便與其它管理平臺對接,實(shí)現(xiàn)自動化維護(hù))。當(dāng)然,Haproxy與F5都提供了人性化管理界面,不過只依賴手工來進(jìn)行操作。

一、LVS負(fù)載均衡器
原理
使用LVS自帶的管理工具來實(shí)現(xiàn)。

環(huán)境說明
Disable VIP:192.168.100.11:80
Disable REAL SERVER:192.168.100.78

實(shí)施步驟
1、初始狀態(tài)
[devuser@lvsserver ~]# ipvsadm -Ln

IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.100.11:80 rr persistent 60
  -> 192.168.100.74:80            Route   3      462        464        
  -> 192.168.100.75:80            Route   3      420        440       
  -> 192.168.100.76:80            Route   3      431        400
  -> 192.168.100.77:80            Route   3      430        432
  -> 192.168.100.78:80            Route   3      435        438

2、禁用成員
[devuser@lvsserver ~]# ipvsadm -d -t 192.168.100.11:80 -r 192.168.100.78

3、當(dāng)前狀態(tài)
[devuser@lvsserver ~]# ipvsadm -Ln

IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.100.11:80 rr persistent 60
  -> 192.168.100.74:80            Route   3      462        464        
  -> 192.168.100.75:80            Route   3      420        440       
  -> 192.168.100.76:80            Route   3      431        400
  -> 192.168.100.77:80            Route   3      430        432

4、啟用成員
[devuser@lvsserver ~]#ipvsadm -a -t 192.168.100.11:80 -r 192.168.100.78

5、當(dāng)前狀態(tài)
[devuser@lvsserver ~]# ipvsadm -Ln

IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.100.11:80 rr persistent 60
  -> 192.168.100.74:80            Route   3      462        464        
  -> 192.168.100.75:80            Route   3      420        440       
  -> 192.168.100.76:80            Route   3      431        400
  -> 192.168.100.77:80            Route   3      430        432
  -> 192.168.100.78:80            Route   3      435        438


二、Haproxy負(fù)載均衡器
原理
使用Haproxy的socket admin通道來實(shí)現(xiàn)。

環(huán)境說明
Disable backend:test.tianya.cn
Disable REAL SERVER:192.168.100.78

實(shí)施步驟
1、修改haproxy.cfg配置
#vi /usr/local/haproxy/etc/haproxy.cfg
在global域添加socket admin支持并重啟Haproxy服務(wù)

global
... ...
   stats socket /usr/local/haproxy/HaproxySocket level admin
... ...
#service haproxy restart

2、安裝socat(在任意的兩個(gè)socket管道之間建立一個(gè)通道,在該通道中交換兩端的數(shù)據(jù)。)

wget http://www.dest-unreach.org/socat/download/socat-2.0.0-b3.tar.gz
./configure --disable-fips
make;make install

注:disable OpenSSL FIPS support  "--disable-fips",在沒有安裝fips包的情況下make時(shí)會提示:

FIPSLD_CC=gcc fipsld -O -D_GNU_SOURCE  -Wall -Wno-parentheses -DHAVE_CONFIG_H -I.  -I.   -c -o socat.o socat.c
/bin/sh: fipsld: command not found
make: *** [socat.o] Error 127


3、禁用成員
#echo "disable server test.tianya.cn/192.168.100.78" | socat stdio /usr/local/haproxy/HaproxySocket
點(diǎn)擊在新窗口中瀏覽此圖片

4、啟用成員
#echo "enable server test.tianya.cn/192.168.100.78" | socat stdio /usr/local/haproxy/HaproxySocket


三、F5-LTM負(fù)載均衡器
原理
使用F5-iControl開發(fā)包Pycontrol對F5設(shè)備進(jìn)行管理。

環(huán)境說明
Disable POOL:test.tianya.cn
Disable SERVER:192.168.100.42:80 192.168.100.43:80 192.168.100.44:80

實(shí)施步驟
1、部署運(yùn)行環(huán)境
#mkdir -p /home/install;cd /home/install
安裝python環(huán)境(略),要求py2.5或以上。
1.1、安裝SUDS模塊

#wget https://fedorahosted.org/releases/s/u/suds/python-suds-0.3.8.tar.gz
#tar xvfz python-suds-0.3.8.tar.gz
#cd python-suds-0.3.8
#python setup.py install

1.2、安裝PYCONTROL模塊

#wget http://trungale.net/pycontrol.tar.gz
#tar xvfz pycontrol.tar.gz
#cd trunk
#python setup.py install

1.3、校驗(yàn)安裝結(jié)果
#python
>>> import suds >>> import pycontrol.pycontrol as pc >>> suds.__version__ '0.4' >>> suds.__build__ 'GA R699-20100913' >>> pc.__version__ '2.0.1' >>> pc.__build__ 'r83' >>> 
2、編寫LB_member.py代碼
# -*- coding: utf-8 -*- """ ---------------------------------------------------------------------------- Disable/Enable F5-LTM POOL member Name:        LB_member.py Author:      Liu tian si Email:       liutiansi@gamil.com Created:     2011/05/08 Version:     1.0 Blog:        http://blog.liuts.com Copyright:   (c) 2011 ---------------------------------------------------------------------------- """ import sys import time import string import pycontrol.pycontrol as pc """ ---------------------------------------------------------------------------- F5-LTM Disable/Enable Pool member Class ---------------------------------------------------------------------------- __init__() -Initialization F5-BIG object set_pool_member() -Initialization pool and member object member_factory() -Create a pool member object (Common.IPPortDefinition) session_state_factory() -Create a session state object (LocalLB.PoolMember.MemberSessionState) disable_member() -Disable menber methods enable_member() -Enable menber methods ---------------------------------------------------------------------------- """ class F5_LB_menber():     def __init__(self,_hostname,_username,_password):         self.b = pc.BIGIP(         hostname = _hostname,         username = _username,         password = _password,         fromurl = True,         wsdls = ['LocalLB.PoolMember'])         self.sstate_seq = self.b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberSessionStateSequence')              def set_pool_member(self,pool,members):         self.POOL=pool         self.members=members         self.sstate_seq.item = self.session_state_factory()     def member_factory(self, member):         ip,port = member.split(':')         pmem = self.b.LocalLB.PoolMember.typefactory.create('Common.IPPortDefinition')         pmem.address = ip         pmem.port = int(port)         return pmem     def session_state_factory(self):         session_states = []         for x in self.members:             sstate = self.b.LocalLB.PoolMember.typefactory.create('LocalLB.PoolMember.MemberSessionState')             sstate.member = self.member_factory(x)             session_states.append(sstate)         return session_states     def disable_member(self):         for x in self.sstate_seq.item:             x.session_state = 'STATE_DISABLED'         try:             self.b.LocalLB.PoolMember.set_session_enabled_state(pool_names =                 [self.POOL], session_states = [self.sstate_seq])              except Exception, e:             print e     def enable_member(self):         for x in self.sstate_seq.item:             x.session_state = 'STATE_ENABLED'         try:             self.b.LocalLB.PoolMember.set_session_enabled_state(pool_names = [self.POOL],                 session_states = [self.sstate_seq])         except Exception, e:             print e if __name__ == "__main__":     if len(sys.argv) < 4:         print "Usage %s POOL MEMBER:port[,member1:80,member2:80,member3:80] enable|disable" % sys.argv[0]         print "Examples: python LB_member.py app.domain.com 192.168.0.10:80,192.168.0.11:80,192.168.0.12:80 disable"         sys.exit()     #F5 administrator info     hostname="192.168.100.2"     username="adminuser"     password="adminpass"     App=F5_LB_menber(hostname,username,password)          #init F5 pool and member     CommandParameters = sys.argv[1:]     pool=CommandParameters[0]     members=string.split(CommandParameters[1],',')          App.set_pool_member(pool,members)     if CommandParameters[2]=="enable":         App.enable_member()     elif CommandParameters[2]=="disable":         App.disable_member()     else:         print "opt parameters error!"         sys.exit() 

3、源碼分析:
3.1、創(chuàng)建一個(gè)池成員對象,將用戶傳入的成員列表轉(zhuǎn)成規(guī)范的pool成員,見member_factory()方法;
3.2、創(chuàng)建一個(gè)會話狀態(tài)對象,追加成員對象到會話狀態(tài)當(dāng)中,見session_state_factory()方法;
3.3、創(chuàng)建一個(gè)隊(duì)列,將會話狀態(tài)對象添加到隊(duì)列子項(xiàng)中,同時(shí)修改所處狀態(tài),見__init__()、set_pool_member()、disable_member()/enable_member()方法。

4、禁用成員
#python LB_member.py test.tianya.cn 192.168.100.42:80,192.168.100.43:80,192.168.100.44:80 disable


5、啟用成員
#python LB_member.py test.tianya.cn 192.168.100.42:80,192.168.100.43:80,192.168.100.44:80 enable


參考文章
http://devcentral.f5.com/wiki/default.aspx/iControl.CodeShare