LVS是Linux Virtual Server的简称,也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项目,它的官方站点是www.linuxvirtualserver.org。现在LVS已经是 Linux标准内核的一部分,在Linux2.4内核以前,使用LVS时必须要重新编译内核以支持LVS功能模块,但是从Linux2.4内核以后,已经完>全内置了LVS的各个功能模块,无需给内核打任何补丁,可以直接使用LVS提供的各种功能。
目录
LVS的作用
LVS主要用于服务器集群的负载均衡。它工作在网络层,可以实现高性能,高可用的服务器集群技术。它廉价,可把许多低性能的服务器组合在一起形成一个超级服务器。它易用,配置非常简单,且有多种负载均衡的方法。它稳定可靠,即使在集群的服务器中某台服务器无法正常工作,也不影响整体效果。另外可扩展性也非常好。
LVS的体系结构
使用LVS架设的服务器集群系统有三个部分组成:
(1)最前端的负载均衡层,用Load Balancer表示;
(2)中间的服务器集群层,用Server Array表示;
(3)最底端的数据共享存储层,用Shared Storage表示;
在用户看来,所有的内部应用都是透明的,用户只是在使用一个虚拟服务器提供的高性能服务。
LVS负载均衡机制
(1)LVS是四层负载均衡,也就是说建立在OSI模型的第四层——传输层之上,传输层上有我们熟悉的TCP/UDP,LVS支持TCP/UDP的负载均衡。因为LVS是四层负载均衡,因此它相对于其它高层负载均衡的解决办法,比如DNS域名轮流解析、应用层负载的调度、客户端的调度等,它的效率是非常高的。
(2)LVS的转发主要通过修改IP地址(NAT模式,分为源地址修改SNAT和目标地址修改DNAT)、修改目标MAC(DR模式)来实现。
①NAT模式:网络地址转换
NAT(Network Address Translation)是一种外网和内网地址映射的技术。NAT模式下,网络数据报的进出都要经过LVS的处理。LVS需要作为RS(真实服务器)的网关。当包到达LVS时,LVS做目标地址转换(DNAT),将目标IP改为RS的IP。RS接收到包以后,仿佛是客户端直接发给它的一样。RS处理完,返回响应时,源IP是RS IP,目标IP是客户端的IP。这时RS的包通过网关(LVS)中转,LVS会做源地址转换(SNAT),将包的源地址改为VIP,这样,这个包对客户端看起来就仿佛是LVS直接返回给它的。客户端无法感知到后端RS的存在
②DR模式:直接路由
DR模式下需要LVS和RS集群绑定同一个VIP(RS通过将VIP绑定在loopback实现),但与NAT的不同点在于:请求由LVS接受,由真实提供服务的服务器(RealServer, RS)直接返回给用户,返回的时候不经过LVS。详细来看,一个请求过来时,LVS只需要将网络帧的MAC地址修改为某一台RS的MAC,该包就会被转发到相应的RS处理,注意此时的源IP和目标IP都没变,LVS只是做了一下移花接木。RS收到LVS转发来的包时,链路层发现MAC是自己的,到上面的网络层,发现IP也是自己的,于是这个包被合法地接受,RS感知不到前面有LVS的存在。而当RS返回响应时,只要直接向源IP(即用户的IP)返回即可,不再经过LVS
(3)DR负载均衡模式数据分发过程中不修改IP地址,只修改mac地址,由于实际处理请求的真实物理IP地址和数据请求目的IP地址一致,所以不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡带宽成为瓶颈。因此,DR模式具有较好的性能,也是目前大型网站使用最广泛的一种负载均衡手段。
配置准备
前端LVS采用主从模式,Nginx为后端realserver负债均衡。
服务
IP地址
LVS + keepalived + nginx
192.168.100.101
LVS + keepalived + nginx
192.168.100.102
Tomcat
192.168.100.103
Tomcat
192.168.100.104
配置主负载服务器
安装keeplived
yum安装
1
2
3
4
$ yum install -y curl gcc openssl-devel libnl3-devel net-snmp-devel #安装依赖包
$ yum install -y keepalived
$ systemctl start keepalived
$ systemctl enable keepalived
编译安装
1.官网下载Keeplived 的最新版本,解压并安装
1
2
3
4
5
6
7
$ wget https://www.keepalived.org/software/keepalived-2.0.7.tar.gz
$ tar xvf keepalived-2.0.7.tar.gz
$ cd keepalived-2.0.7
$ ./configure --prefix= /usr/local/keepalived
$ make && make install
$ systemctl start keepalived
$ systemctl enable keepalved
完成后会在以下路径生成:
1
2
3
/usr/local/etc/keepalived/keepalived.conf
/usr/local/etc/sysconfig/keepalived
/usr/local/sbin/keepalived
2.初始化及启动
1
2
3
4
5
6
7
8
9
10
11
12
# keepalived启动脚本变量引用文件,默认文件路径是/etc/sysconfig/,也可以不做软链接,直接修改启动脚本中文件路径即可(安装目录下)
$ cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/keepalived
# 将keepalived主程序加入到环境变量(安装目录下)
$ cp /usr/local/keepalived/sbin/keepalived /usr/sbin/keepalived
# keepalived启动脚本(源码目录下),放到/etc/init.d/目录下就可以使用service命令便捷调用
$ cp /usr/local/src/keepalived-2.0.7/keepalived/etc/init.d/keepalived /etc/init.d/keepalived
# 将配置文件放到默认路径下
$ mkdir /etc/keepalived
$ cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf
配置keepalived
配置Master服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs { #lvs组设置
router_id LVS1 #id_唯一标识
}
vrrp_instance VI_1 { #vrrp设置,VI_1自定义名称
state MASTER #master设置,必须大写
interface eth0 #网卡设置,绑定vip的子接口,lvs需要绑定在网卡上,realserver绑定在回环口。区别:lvs对访问为外,realserver为内不易暴露本机信息。
virtual_router_id 51 #router_id,vrrp唯一标识,一致
priority 100 #优先级,越大越优先
advert_int 1 #组播信息发送间隔,两个节点设置必须一样
authentication { #设置验证信息,两个节点必须一致
auth_type PASS
auth_pass 123456
}
virtual_ipaddress { #设置vip
192.168.100.200
}
}
virtual_server 192.168.100.200 80 { #设置vip连接下的realserver
delay_loop 1 #每1秒检测回环口
lb_algo rr #设置调度算法为默认rr轮询
lb_kind DR #设置lvs默认为DR直接路由模式。建议lvs都是内网ip部署,最后vip用路由器映射到外网,最为安全!
protocol TCP #启用TCP检测模式
real_server 192.168.100.101 80 { #realserver的ip地址
weight 1 #权重,最大越高,lvs就越优先访问。
TCP_CHECK { #TCP模式检测后端连接
connect_timeout 3 #超时3秒
retry 2 #重连次数2次
delay_before_retry 3 #重连间隔时间3秒
connect_port 80 #检测后端realserver的端口
}
}
real_server 192.168.100.102 80 {
weight 1
TCP_CHECK {
connect_timeout 3
retry 3
delay_before_retry 3
connect_port 80
}
}
}
配置Backup服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS2
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 80
advert_int 1
authentication {
auth_type PASS
auth_pass 123456 #与backup的认证密码
}
virtual_ipaddress {
192.168.100.200
}
}
virtual_server 192.168.100.200 80 {
delay_loop 1
lb_algo rr
lb_kind DR
protocol TCP
real_server 192.168.100.101 80 {
weight 1
TCP_CHECK {
connect_timeout 3
retry 2
delay_before_retry 3
connect_port 80
}
}
real_server 192.168.100.102 80 {
weight 1
TCP_CHECK {
connect_timeout 3
retry 3
delay_before_retry 3
connect_port 80
}
}
}
安装ipvsadm
yum安装
1
$ yum -y install ipvsadm
查看是否加载ip_vs模块
1
2
3
4
$ lsmod | grep ip_vs
ip_vs 145497 0
nf_conntrack 139224 1 ip_vs
libcrc32c 12644 3 xfs,ip_vs,nf_conntrack
如果没有显示手动加载
配置lvs网卡设置下的vip
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$ vim /etc/init.d/lvs
#!/bin/bash
#
# Script to start LVS DR real server.
# description: LVS DR real server
# chkconfig: 3 67 22
#
. /etc/rc.d/init.d/functions
VIP = 192.168.100.200 #这里根据须要改为本身的VIP地址
host = ` /bin/hostname`
case " $1 " in
start)
# Start LVS-DR real server on this machine.
/sbin/ifconfig lo down
/sbin/ifconfig lo up
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
/sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up
/sbin/route add -host $VIP dev lo:0
;;
stop)
# Stop LVS-DR real server loopback device(s).
/sbin/ifconfig lo:0 down
echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
;;
status)
# Status of LVS-DR real server.
islothere = ` /sbin/ifconfig lo:0 | grep $VIP `
isrothere = ` netstat -rn | grep "lo:0" | grep $VIP `
if [ ! " $islothere " -o ! "isrothere" ] ; then
# Either the route or the lo:0 device
# not found.
echo "LVS-DR real server Stopped."
else
echo "LVS-DR real server Running."
fi
;;
*)
# Invalid entry.
echo " $0 : Usage: $0 {start|status|stop}"
exit 1
;;
esac
运行脚本,并添加到开机启动
1
2
3
4
$ chmod +x /etc/init.d/lvs
$ service lvs start
$ chkconfig --add lvs
$ chkconfig lvs on
安装nginx
yum安装nginx
1
2
3
$ yum -y install nginx
$ systemctl start nginx
$ systemctl enable nginx
编译安装nginx
官网下载nginx 最新版本,并安装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ wget https://nginx.org/download/nginx-1.17.0.tar.gz
$ tar -zxf nginx-1.17.0.tar.gz
$ cd nginx-1.17.0
#添加用户和组
$ groupadd www
$ useradd -g www www
$ ./configure \
--user= www \
--group= www \
--prefix= /usr/local/nginx \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-threads
$ make && make install
验证安装
1
$ /usr/local/nginx/sbin/nginx -V
创建软连接
1
$ ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx
创建service脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
$ vim /etc/init.d/nginx
#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig: - 85 15
# description: NGINX is an HTTP(S) server, HTTP(S) reverse \
# proxy and IMAP/POP3 proxy server
# processname: nginx
# config: /usr/local/nginx/conf/nginx.conf
# config: /etc/sysconfig/nginx
# pidfile: /usr/local/nginx/logs/nginx.pid
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ " $NETWORKING " = "no" ] && exit 0
nginx = "/usr/local/nginx/sbin/nginx"
prog = $( basename $nginx )
NGINX_CONF_FILE = "/usr/local/nginx/conf/nginx.conf"
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
lockfile = /var/lock/subsys/nginx
make_dirs() {
# make required directories
user = ` $nginx -V 2>& 1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
if [ -z "`grep $user /etc/passwd`" ] ; then
useradd -M -s /bin/nologin $user
fi
options = ` $nginx -V 2>& 1 | grep 'configure arguments:' `
for opt in $options ; do
if [ ` echo $opt | grep '.*-temp-path' ` ] ; then
value = ` echo $opt | cut -d "=" -f 2`
if [ ! -d " $value " ] ; then
# echo "creating" $value
mkdir -p $value && chown -R $user $value
fi
fi
done
}
start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
make_dirs
echo -n $"Starting $prog : "
daemon $nginx -c $NGINX_CONF_FILE
retval = $?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $prog : "
killproc $prog -QUIT
retval = $?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
configtest || return $?
stop
sleep 1
start
}
reload() {
configtest || return $?
echo -n $"Reloading $prog : "
killproc $nginx -HUP
RETVAL = $?
echo
}
force_reload() {
restart
}
configtest() {
$nginx -t -c $NGINX_CONF_FILE
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >/dev/null 2>& 1
}
case " $1 " in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart| configtest)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart| try-restart)
rh_status_q || exit 0
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
exit 2
esac
设置开机自启
1
2
3
4
$ chmod a+x /etc/init.d/nginx
$ service nginx start
$ chkconfig --add nginx
$ chkconfig nginx on
测试LVS
查看LVS信息
1
2
3
4
5
6
7
$ 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.200:80 rr
-> 192.168.100.101:80 Route 1 0 0
-> 192.168.100.102:80 Route 1 0 0
通过浏览器多次访问http://192.168.100.200
通过访问发现负载均衡生效
关闭Master服务器上的nginx服务
发现依然可以访问,高可用生效
配置动静分离
安装Tomcat
配置JDK
1
2
3
4
5
6
7
8
9
10
11
12
$ wget https://repo.huaweicloud.com/java/jdk/8u181-b13/jdk-8u181-linux-x64.tar.gz
$ mkdir /usr/local/java/
$ tar -zxvf jdk-8u181-linux-x64.tar.gz -C /usr/local/java/
$ vim /etc/profile
# 在末尾添加
export JAVA_HOME = /usr/local/java/jdk1.8.0_181
export JRE_HOME = ${ JAVA_HOME } /jre
export CLASSPATH = .:${ JAVA_HOME } /lib:${ JRE_HOME } /lib
export PATH = ${ JAVA_HOME } /bin:$PATH
$ source /etc/profile
$ java -version
yum安装Tomcat
1
2
3
$ yum -y install tomcat
$ systemctl start tomcat
$ systemctl enable tomcat
编译安装Tomcat
官网下载Tomcat 的最新版本,解压并安装
1
2
3
4
$ wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-9/v9.0.46/bin/apache-tomcat-9.0.46.tar.gz
$ tar -zxvf apache-tomcat-9.0.0.M18.tar.gz
$ mkdir /usr/local/tomcat/
$ mv ./apache-tomcat-9.0.0.M18#usr/local/tomcat/
创建service脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$ vim /etc/init.d/tomcat
#!/bin/bash
#
# tomcat startup script for the Tomcat server
#
# chkconfig: 345 80 20
# description: start the tomcat deamon
#
# Source function library
. /etc/rc.d/init.d/functions
prog = tomcat
JAVA_HOME = /usr/local/java/jdk1.8.0_171
export JAVA_HOME
CATALANA_HOME = /usr/local/tomcat
export CATALANA_HOME
case " $1 " in
start)
echo "Starting Tomcat..."
$CATALANA_HOME /bin/startup.sh
;;
stop)
echo "Stopping Tomcat..."
$CATALANA_HOME /bin/shutdown.sh
;;
restart)
echo "Stopping Tomcat..."
$CATALANA_HOME /bin/shutdown.sh
sleep 2
echo -n "Starting Tomcat..."
$CATALANA_HOME /bin/startup.sh
;;
*)
echo "Usage: $prog {start|stop|restart}"
;;
esac
设置开机自启
1
2
3
4
chmod a+x /etc/init.d/tomcat
service tomcat start
chkconfig --add tomcat
chkconfig tomcat on
配置Nginx代理Tomcat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
$ vim /usr/local/nginx/conf/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location / {
proxy_pass http://blance;
}
}
upstream blance{
server 192.168.100.103:8080;
server 192.168.100.104:8080;
}
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"' ;
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
测试动静分离
通过浏览器多次访问https://192.168.100.200
两次访问到的IP不同,动静分离完成