使用一个公网IP地址来实现LVS的DR模式(外带php session粘滞问题解决)
去年有朋友问我单个公网ip怎么才能使用LVS的DR模式,我当时还不以为然,觉得他们公司可真小气,那么吝啬公网ip。结果这个问题今天也让我遇到了。
倒不是因为对方公司没有公网IP,而是由于安全性的考虑不希望服务器都暴漏在外,人家又不想因为这个小项目买防火墙,所以就提了这个要求。
我说用NAT方式不行吗?可人家说做分发器的服务器要身兼多职,不能再给她增加负担了......X﹏X

需求提出来了,那我就开始执行吧!不过这方面的资料很少,去章博士的网站里面找到了一篇文章,上面只说可以做,单具体怎么做却没有说,而且好像还要打上forward_shared包(⊙o⊙)…好麻烦啊~~~
怎么样才能实现呢?这时候田老师给我提了个醒,“说一个公网IP也可以做DR啊,前面加个路由器就可以了”不过他也没试过,让我自己测测就知道了,我一听有戏,马上就开始测试吧,呵呵
具体结构就想上面那个图那样,(随便画的大家凑合着看吧(*^__^*) 嘻嘻……)
原理就是让 路由器把所有的80端口请求都分给VIP,分发器再分给每个web服务器,而web服务器处理完请求后跟客户连接就不走分发器了,直接通过路由器去外网了,这样就实现了只用一个公网IP也能用DR模式,呵呵 具体配置如下
先从内网找了三台服务器分别是:
192.168.1.166 web1
192.168.1.167 web2
192.168.1.160 分发器
192.168.1.169 VIP
192.168.1.1   路由器内网ip(网关) 路由器是随便找的一台tplink adal路由器,凑合着测试用的
211.83.113.119 路由器的WAN口IP (随便蒙的,重复莫怪)

先安装ipvsadm 直接yum install ipvsadm就行了,不多说
我用的是keepalived,这个工具不错,至于安装我就不说了,请参考田老师写的《keepalived手册》我的博客里有下载链接
我的博客里也有他的测试
只把配置文件贴上来吧,以下是分发器上的设置
global_defs {
   notification_email {
        ufo@xman.com
   }

notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server smtp.qq.com
   smtp_connect_timeout 30
   router_id LVS_DEVEL
}

vrrp_sync_group VG1 {
        group{
        VI_1
                }
                    }
vrrp_instance VI_1 {
        state MASTER
        interface eth0
        virtual_router_id 51
        priority 100
        advert_int 1

        authentication {
        auth_type PASS
        auth_pass 33210
                        }

        virtual_ipaddress {
        192.168.1.169
                          }

        virtual_server 192.168.1.169 80 {
        delay_loop 6
        lb_algo rr
        lb_kind DR
        protocol TCP

                real_server 192.168.1.166 80 {
                weight 1
                inhibit_on_failure
                TCP_CHECK {
                connect_timeout 5
                nb_get_retry 3
                delay_before_retry 3
                connect_port 80
                          }
                                              }
                real_server 192.168.1.167 80 {
                weight 1
                inhibit_on_failure
                TCP_CHECK {
                connect_timeout 5
                nb_get_retry 3
                delay_before_retry 3
                connect_port 80
                          }
                                              }
配置文件写完了,然后就是
mkdir /etc/keepalived  #系统默认会到这里去找配置文件
cp /usr/local/keepalive/etc/keepalived/keepalived.conf /etc/keepalived/
cp /usr/local/keepalive/etc/rc.d/init.d/keepalived /etc/init.d/
cp /usr/local/keepalive/etc/sysconfig/keepalived /etc/sysconfig/
cp /usr/local/keepalive/sbin/keepalived /bin/ #将可执行程序放入sbin 或者 bin目录里

vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
保存退出 后执行sysctl -p
route add defaule gw 192.168.1.1 把路由内网地址添加为默认网关
web服务器设置
两台web服务器也要修改 /etc/sysctl.conf 修改内容如下
vim /etc/sysctl.conf
# LVS
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
sysctl -p
之后还要增加vip
ifconfig lo:1 192.168.1.169 netmask 255.255.255.255 别忘了加到rc.local里面
route add defaule gw 192.168.1.1 把路由内网地址添加为默认网关

路由器设置
路由器的设置没什么好说的,除了上网设置以外还要做一个端口映射,就是把80端口映射到 vip上也就是192.168.1.169

现在启动keepalived吧
/etc/init.d/keepalived start
开始的时候比较慢,大概1分钟后系统日志里面出现下面这条记录就OK了
avahi-daemon[3012]: Registering new address record for 192.168.1.169 on eth0

我们访问一下 http://211.83.113.119
哈哈成功了 ,我把我们的应用程序放到了上面跑了一下,结果测试通过,而且比较快,呵呵测试成功
ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.1.169:80 rr
  -> 192.168.1.166:80             Route   1      5          6         
  -> 192.168.1.167:80             Route   1      3          9

   后来遇到了一个问题,由于这套应用处在一个大网站的后台,所以大部分的请求都来自同一个IP地址,而有一部分程序需要给每个连接做session粘滞,
这样我就不能用lvs 的-p参数来设置ip粘滞时间,如果用lvs的粘滞时间的话大部分的请求都将分给同一台web服务器(注意:这里是session粘滞而不是IP粘滞)
lvs可做不到这点,怎么办呢?
在cu论坛上询问后得知有很多朋友做过类似的项目,他们的解决办法是 将session共享,共享到什么地方就有很多选择了
我们是把所有web服务器的php session都给memcached ,这样你不管分发器把 ip连接分给哪个web服务器都不会有问题了,配置方法很简单,就在php的配置文件内
增加一条语句就可以了,不过前提你需要装好memcache模块
[Session]
; Handler used to store/retrieve data.
session.save_handler = memcache
session.save_path = "tcp://192.168.1.161:11213"

就写到这里了,希望有同样需求的朋友能看到我的这篇文章