61阅读

负载均衡解决方案-Centos双网卡bonding绑定实现负载均衡的方法

发布时间:2017-08-22 所属栏目:负载均衡

一 : Centos双网卡bonding绑定实现负载均衡的方法

为了提高系统的高可用性,我们可以将两个或多个网卡进行绑定,变为一个虚拟网卡,使用同一个ip地址,以保证一个链路断掉的时候,另一个链路能随时启动,提高系统的稳定性。

虚拟机中启用双网卡

wps_clip_image-9173

wps_clip_image-3313

Finish

双网卡工作的时候表现为一个虚拟网卡(bond0),该虚拟网卡也需要驱动,驱动名叫bonding

查看内核是否支持双网卡的绑定

vim  /boot/config-2.6.18-164.e15

wps_clip_image-22087

说明支持这种网络模式,并且BOUNDING是一个内置模块

进入

wps_clip_image-14579

wps_clip_image-11990

网卡绑定之后使用统一的ip,那么eth0和eth1就不需要设置ip就可以了

vim ifcfg-eth0

wps_clip_image-9640

vim ifcfg-eth1

wps_clip_image-24880

产生额外的网卡文件ifcfg-bond0

cp ifcfg-eth0  ifcfg-bond0

(虚拟网卡bond0需要地址)

vim ifcfg-bond0

wps_clip_image-4688

vim /etc/modprobe.conf  (为了让系统加载bonding模块)

在这个文件中添加

wps_clip_image-18615

wps_clip_image-10590

(延迟100毫秒进行bond0链路监测,mode=1表示主备模式)

vim  /etc/rc.d/rc.local (在开机脚本中指明bond0绑定的是eth0和eth1这两个网卡)

wps_clip_image-6212

init 6重启系统

wps_clip_image-944

dmesg   |grep bond0(查看主备模式的相关信息)

wps_clip_image-6400

或者cat /proc/net/bonding/bond0

wps_clip_image-4744

每隔一秒监控一次

Wtach -n 1 ‘cat /proc/net/bonding/bond’

wps_clip_image-30965

当eth0 down掉的时候备份链路eth1 自动启动

wps_clip_image-3663

当eth1 down掉的时候,eth0启动

wps_clip_image-28492

二 : 负载均衡(LB)详解

二、LB[www.61k.com]

LoadBalance就是把负载均衡分配到集群的各个节点,从而提高整体的吞吐能力。Oracle 10gRAC提供了两种手段来实现负载,其一是通过Connection Balancing,按照某种算法把用户分配到不同的节点;其二是通过service,在应用层面上进行分散。

Connection Balancing

Connection Balancing这种负载均衡是在用户连接这个层次上进行的,也就是在用户请求建立连接时,根据每个的负载决定把连接分配到哪个实例上。而一旦建立连接之后,会话的所有操作就都在这个实力上完成,而不会再分配给其他实例。

客户端均衡(Client-Side LB)

客户端均衡(Client-Side LB)是oracle 8i使用的方法,配置方法是在客户端的tnsnames.ora文件中加入LOAD_BALANCE=YES条目。当客户端发起连接时,会从地址列表中随机选取一个,再使用随机算法吧连接请求分散到各个实例。

一个Client-Side LB的TNS配置实例如下:

TAF_SERVER =

(DESCRIPTION =

(ADDRESS= (PROTOCOL = TCP)(HOST = felix1-vip)(PORT = 1521))

(ADDRESS= (PROTOCOL = TCP)(HOST = felix2-vip)(PORT = 1521))

(LOAD_BALANCE= yes)

(CONNECT_DATA =

(SERVER = DEDICATED)

(SERVICE_NAME = taf_server)

(FAILOVER_MODE =

(TYPE = SELECT)

(METHOD = BASIC)

(RETRIES = 180)

(DELAY = 5)

)

)

)

这种方法的缺点很明显,因为在分配连接时没有考虑每个节点的真是负载,最后分配结果不一定是平衡的;并且随机算法需要长时间片,如果在短时间内同时发起多个连接,这些连接有可能都被分配到一个节点上;甚至更坏的情况下,连接可能会被分配到故障节点上。因此Oracle又引入了服务器端(Server-Side LB)方式。

总结:客户端均衡的最大缺点就是不能根据各个实例的真实负载来分散用户连接

服务器端均衡(Server-Side)

服务器端负载均衡的实现依赖于listener(监听)手机的负载信息。在数据库运行过程中,PMON后台进程会手机系统的负载信息,然后登记到Listener中。最少一分钟,最多十分钟PMON就要做一次信息更新,并且如果节点的负载越高,更新频率就越高,以保证Listener能够掌握每个节点准确的负载情况。如果Listener关闭,PMON进程会每隔1妙检查Listener是否重启,除了这个自动的、定时的更新任务外,用户也可以实用altersystem register命令来手工进行这个过程。这个自动更新动作可以从listener的日志中看到。注意:实例启动时PMON进程进行的第一次登记过程叫做Server-Rgister,而后的更新过程叫做service-update;

TNSLSNR for Linux: Version 10.2.0.5.0 - Productionon 03-JUN-2014 11:51:54

Copyright (c) 1991, 2010, Oracle. All rights reserved.

System parameter file is/u01/oracle/10.2.0/db_1/network/admin/listener.ora

Log messages written to/u01/oracle/10.2.0/db_1/network/log/listener.log

Trace information written to/u01/oracle/10.2.0/db_1/network/trace/listener.trc

Trace level is currently 0

Started with pid=25371

Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=felix1)(PORT=1521)))

Listener completed notification to CRS on start

TIMESTAMP * CONNECT DATA [* PROTOCOL INFO] * EVENT[* SID] * RETURN CODE

03-JUN-2014 11:51:54 *(CONNECT_DATA=(CID=(PROGRAM=)(HOST=felix1)(USER=oracle))(COMMAND=status)(ARGUMENTS=64)(SERVICE=LISTENER)(VERSION=169870592))* status * 0

03-JUN-2014 11:52:15 * service_register * felix2 *0

03-JUN-2014 11:52:15 * service_register * felix1 *0

03-JUN-2014 11:52:15 * service_update * felix1 * 0

03-JUN-2014 11:52:15 * service_register * +ASM1 *0

Listener日志虽然记录了PMON进程的注册和更新动作,但是注册的内容却没有体现,要想获得这些内容,可以通过各种1025事件来获得,这个时间是跟中PMON活动的。

SQL> alter session set events '10257 trace namecontext forever,level 16';

Session altered.

SQL>

获取跟踪文件:

CREATE OR REPLACE FUNCTION get_trace return varchar is

Resultvarchar2(4000);

begin

dbms_output.enable(1000000);

begin

for x in(SELECT d.VALUE

||'/'

||LOWER (RTRIM (i.INSTANCE, CHR (0)))

||'_ora_'

||p.spid

||'.trc'

trace_file_name

FROM (SELECT p.spid

FROM v$mystat m, v$session s,v$process p

WHERE m.statistic#= 1 AND s.SID= m.SID AND p.addr = s.paddr) p,

(SELECT t.INSTANCE

FROM v$thread t, v$parameter v

WHERE v.NAME = 'thread'

AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i,

(SELECT VALUE

FROM v$parameter

WHERE NAME = 'user_dump_dest')d) loop

Result:= Result || x.trace_file_name;

End loop;

End;

return(substr(Result, 1, 4000));

end get_trace;

select get_trace from dual;

GET_TRACE

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

/u01/oracle/admin/felix/udump/felix1_ora_27465.trc

PMON进程不仅回想本地的Listener注册,还可以向其他节点的listener注册。但到底要向何处注册,是由remote_listener和local_listener这两个参数决定。Local_Listener不用设置,而remote需要设置,参数值是一个tnsnames项。

SQL> show parameter listener

NAME TYPE VALUE

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

local_listener string LISTENER_FELIX1

remote_listener string LISTENERS_FELIX

SQL>

Tnsnames.ora中对应的LISTENERS_FELIX的内容如下:

LISTENERS_FELIX =

(ADDRESS_LIST=

(ADDRESS= (PROTOCOL = TCP)(HOST = felix1-vip)(PORT = 1521))

(ADDRESS= (PROTOCOL = TCP)(HOST = felix2-vip)(PORT = 1521))

)

有了PMON的自动注册机制后,集群的每个节点的Listener都掌握所有节点的负载状态,当收到客户端的连接请求时,就会把连接转给负载最小的节点,这个节点有可能是自己也可能是其他节点,也就是Listener会转发用户连接的请求listener的节点选择方法根据用户所请求的连接方式会有所不同:

a. 如果用户请求的是Dedicate专有连接,Listener首先选择负载最小的节点,如果多个节点负载相同,则从中选择负载最小的实例;

b. 如果用户请求的是shared server共享连接,除了做节点负载比较和实例负载比较之外,还要在所选实例上,选择最小的Dispatcher进行转发。

两种LB的配置方法:

对于client-Side LB,需要在客户的tnsnames条目中加入LOAD_BALANCE=YES。对于Server-Side LB,需要配置REMOTE_LISTENER这个参数。

在配置LB时有一点需要注意:需要从各个实例的listener文件中却掉缺省的SID_LIST_LISTENER_NAME条目,这样才能保证Listener获得的信息都是动态注册的,而不是从文件中读出的静态信息。

修改前:

[oracle@felix2 admin]$ cat listener.ora

# listener.ora.felix2 Network Configuration File:/u01/oracle/10.2.0/db_1/network/admin/listener.ora.felix2

# Generated byOracleconfiguration tools.

LISTENER_FELIX2 =

(DESCRIPTION_LIST =

(DESCRIPTION =

(ADDRESS = (PROTOCOL = TCP)(HOST = felix2-vip)(PORT = 1521)(IP = FIRST))

(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.102)(PORT = 1521)(IP =FIRST))

)

)

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

SID_LIST_LISTENER_FELIX2 =

(SID_LIST=

(SID_DESC =

(SID_NAME = PLSExtProc)

(ORACLE_HOME = /u01/oracle/10.2.0/db_1)

(PROGRAM = extproc)

)

)

[oracle@felix2 admin]$

修改后配置如下:

[oracle@felix2 admin]$ catlistener.ora

# listener.ora.felix2 Network Configuration File:/u01/oracle/10.2.0/db_1/network/admin/listener.ora.felix2

# Generated by Oracle configuration tools.

LISTENER_FELIX2 =

(DESCRIPTION_LIST =

(DESCRIPTION =

(ADDRESS = (PROTOCOL = TCP)(HOST = felix2-vip)(PORT = 1521)(IP = FIRST))

(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.102)(PORT = 1521)(IP =FIRST))

)

)

[oracle@felix2 admin]$

利用service分散负载

Connection Balancing方法的不足之处,Oracle的集群时“共享一切“的架构,所有节点都共享一份磁盘数据。实例间通过cachefusion机制进行数据同步,所以RAC的性能在很大程度上受限于cache fusion的性能。因此,要提高RAC的性能可以从两方面入手,一方面提高cache fusion的能力,这可以通过更好的互联设备,比如G级的Private network,或者使用Infiniband等DRA技术;另一方面,可以尽量减少cache fusion的流量,减少实例间的相互依赖。而service就是后一种思路基础上发展出来的。

先看一下与service非常相似的Partition技术。如果一个表中的数据量巨大,Oralce会建议采用了Partition Table,把数据按照一定的规律分散到多个物理段(Segment)中,这样访问数据时就限制在某些个局部的Segment上。

把“分散数据“思想机一部提升,在RAC环境中,如果能够把数据按照应用进行分离,考虑下面这个场景:一个ERP应用包括生产、销售、供应链管理多个模块。假设这个数据库采用了2节点的RAC在没有进行“数据分散”之前,两个用户都使用销售模块,那么这两个用户就可能被分配到两个节点上,在操作过程中,销售数据就要在cache fusion的作用下,不断在两个节点间传递,如果有来了另外两个生产模块的用户,这两个用户又被分配到两个节点上,在操作的过程中,生产部分的数据又要在Cache fusion的协助下在两个实力之间同步。

可见,如果仅有connectionbalance一种机制,表面上看起来用户是被分配到了不同的实例上,似乎负载被分散了。但是这种分散是没有结合每个用户的业务需求进行的,是一种纯技术手段(因此可以把它叫做纯技术手段分散)。

如果换一种解决思想,假如把销售模块的用户都分配到节点1上,生产模块的用户都分配到节点2上,在假设这两个模块之间的数据交叉不多,这是销售模块的数据都集中在节点1上,生产库模块的数据都集中在节点2上,cachefusion的工作量就会急剧减少,这就从根本上解决了性能的问题。

这个思想是借助于service分散负载的基本思想。通过把应用按照功能模块进行划分成Service,进而把每个service固定在某些RAC节点上,从而从根本上提供系统的性能。这种分散负载的方法不是仅靠DBA进行配置就能完成的,需要DBA和开发人员合作,在了解业务数据特点之后才能看到效果。

在RAC环境下,Service并不是必须的,但是如果借助service对应用的划分,相信对整个系统性能的提升是大有裨益的。使用service还有另外一个好处:可以在数据库内部创建Service的TAF参数,如果在客户端通过service连接数据库,客户端tnsnames.ora中就不再需要FAIL-OVER的许多设置。

如果使用service方法,客户端配置需要使用service_name条目,例如下面的红字部分:

TAF_SERVER =

(DESCRIPTION =

(ADDRESS= (PROTOCOL = TCP)(HOST = felix1-vip)(PORT = 1521))

(ADDRESS= (PROTOCOL = TCP)(HOST = felix2-vip)(PORT = 1521))

(CONNECT_DATA =

(SERVER = DEDICATED)

(SERVICE_NAME = taf_server)

)

)

详细探究参考《大话RAC》张晓明 p238~242,讲的特别好!!!!

三 : Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解

   Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解

2013-09-04 14:45:43

标签:读写分离 URL重写 页面缓存 Nginx 反向代理

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://freeloda.blog.51cto.com/2033581/1288553

大纲

一、前言

二、环境准备

三、安装与配置Nginx

四、Nginx之反向代理

五、Nginx之负载均衡

六、Nginx之页面缓存

七、Nginx之URL重写

八、Nginx之读写分离

注,操作系统为 CentOS 6.4 x86_64 , Nginx 是版本是最新版的1.4.2,所以实验用到的软件请点击这里下载:http://yunpan.cn/QXIgqMmVmuZrm

一、前言

在前面的几篇博文中我们主要讲解了Nginx作为Web服务器知识点,主要的知识点有nginx的理论详解、nginx作为web服务器的操作讲解、nginx作为LNMP架构的讲解,不清楚的博友可以回头看看,在这一篇博客中我们主要讲解, nginx的反向代理、负载均衡、缓存、URL重写以及读写分离详解。好了,下面我们来具体说一说。

二、环境准备

1. 操作系统

CentOS 6.4 x86_64

2.软件版本

Nginx 1.4.2

3.实验拓扑

注,实验拓扑见下文。

4.安装yum源

1

2

3

[root@nginx ~]# rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

[root@web1 ~]# rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

[root@web2 ~]# rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

5.各节点时间同步

1

2

3

[root@nginx ~]# ntpdate 202.120.2.101

[root@web1 ~]# ntpdate 202.120.2.101

[root@web2 ~]# ntpdate 202.120.2.101

6.关闭防火墙与SELinux

1

2

3

4

5

6

7

8

9

10

11

12

[root@nginx ~]# service iptables stop

[root@nginx ~]# chkconfig iptables off

[root@nginx ~]# getenforce

Disabled

[root@web1 ~]# service iptables stop

[root@web1 ~]# chkconfig iptables off

[root@web1 ~]# getenforce

Disabled

[root@web2 ~]# service iptables stop

[root@web2 ~]# chkconfig iptables off

[root@web2 ~]# getenforce

Disabled

三、安装Nginx

1.解压

1

[root@nginx src]# tar xf nginx-1.4.2.tar.gz

2.新建nginx用户与组

1

2

3

4

[root@nginx src]# groupadd -g 108 -r nginx

[root@nginx src]# useradd -u 108 -r -g 108 nginx

[root@nginx src]# id nginx

uid=108(nginx) gid=108(nginx) 组=108(nginx)

3.准备编译配置文件

1

2

[root@nginx src]# yum install -y pcre-devel openssl-devel

[root@nginx nginx-1.4.2]# ./configure --prefix=/usr --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx/nginx.pid --lock-path=/var/lock/nginx.lock --user=nginx --group=nginx --with-http_ssl_module --with-http_flv_module --with-http_stub_status_module --with-http_gzip_static_module --http-client-body-temp-path=/var/tmp/nginx/client/ --http-proxy-temp-path=/var/tmp/nginx/proxy/ --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi --http-scgi-temp-path=/var/tmp/nginx/scgi --with-pcre

4.编译并安装

1

[root@nginx nginx-1.4.2]# make && make install

5.为nginx提供SysV init脚本

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

[root@nginx ~]# cat /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: /etc/nginx/nginx.conf

# config: /etc/sysconfig/nginx

# pidfile: /var/run/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/sbin/nginx"

prog=$(basename $nginx)

NGINX_CONF_FILE="/etc/nginx/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' -`

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

6.为此脚本赋予执行权限

1

[root@nginx ~]# chmod +x /etc/init.d/nginx

7.添加至服务管理列表,并让其开机自动启动

1

2

3

4

[root@nginx ~]# chkconfig --add nginx

[root@nginx ~]# chkconfig nginx on

[root@nginx ~]# chkconfig nginx --list

nginx 0:关闭 1:关闭 2:启用 3:启用 4:启用 5:启用 6:关闭

8.启动nginx

1

2

[root@nginx ~]# service nginx start

正在启动 nginx: [确定]

9.查看一下端口

1

2

[root@nginx ~]# netstat -ntlp | grep :80

tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 3889/nginx

10.测试一下



好了,Nginx安装与配置就到这里,下面我们来说一说Nginx的反向代理。

四、Nginx之反向代理

在配置nginx反向代理之间我们得先准备两台测试服务器,Web1与Web2。

1.安装httpd

1

2

[root@web1 ~]# yum install -y httpd

[root@web2 ~]# yum install -y httpd

2.提供测试页面

1

2

[root@web1 ~]# echo "<h1>web1.test.com</h1>" > /var/www/html/index.html

[root@web2 ~]# echo "<h1>web2.test.com</h1>" > /var/www/html/index.html

3.启动httpd服务

1

2

3

4

[root@web1 ~]# service httpd start

正在启动 httpd: [确定]

[root@web2 ~]# service httpd start

正在启动 httpd: [确定]

4.测试一下





5.简单说一下,正向代理与反向代理

(1).正向代理的概念

正向代理,也就是传说中的代理,他的工作原理就像一个跳板,简单的说,我是一个用户,我访问不了某网站,但是我能访问一个代理服务器,这个代理服务器呢,他能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容,代理服务器去取回来,然后返回给我。从网站的角度,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。

结论就是,正向代理 是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。

(2).反向代理的概念

继续举例:

例用户访问 http://www.61k.comreadme,但www.61k.com并不存在readme页面,他是偷偷从另外一台服务器上取回来,然后作为自己的内容返回用户,但用户并不知情。这里所提到的 www.61k.com这个域名对应的服务器就设置了反向代理功能。

结论就是,反向代理正好相反,对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容原本就是它自己的一样。

(3).两者区别

从用途上来讲:

正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。正向代理还可以使用缓冲特性减少网络使用率。反向代理的典型用途是将防火墙后面的服务器提供给Internet用户访问。反向代理还可以为后端的多台服务器提供负载平衡,或为后端较慢的服务器提供缓冲服务。另外,反向代理还可以启用高级URL策略和管理技术,从而使处于不同web服务器系统的web页面同时存在于同一个URL空间下。

从安全性来讲:

正向代理允许客户端通过它访问任意网站并且隐藏客户端自身,因此你必须采取安全措施以确保仅为经过授权的客户端提供服务。反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。

6.nginx 代理模块

http 代理官方中文文档:http://www.61k.comginx:nginx%E6%A8%A1%E5%9D%97%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C%E4%B8%AD%E6%96%87%E7%89%88:standardhttpmodules:httpproxy

说明:代理模块的指令有很多我这里只讲解重要的proxy_pass,想了解更多代理指令请参考官方中文文档。

这个模块可以转发请求到其他的服务器。HTTP/1.0无法使用keepalive(后端服务器将为每个请求创建并且删除连接)。nginx为浏览器发送HTTP/1.1并为后端服务器发送HTTP/1.0,这样浏览器就可以为浏览器处理keepalive。 如下例:

1

2

3

4

location / {

proxy_pass http://localhost:8000;

proxy_set_header X-Real-IP $remote_addr;

}

注意,当使用http proxy模块(甚至FastCGI),所有的连接请求在发送到后端服务器之前nginx将缓存它们,因此,在测量从后端传送的数据时,它的进度显示可能不正确。

实验拓扑:



7.配置http反向代理

1

2

3

4

5

6

[root@nginx ~]# cd /etc/nginx/

[root@nginx nginx]# cp nginx.conf nginx.conf.bak #备份一个原配置文件

[root@nginx nginx]# vim nginx.conf

location / {

proxy_pass http://192.168.18.201;

}

指令说明:proxy_pass

语法:proxy_pass URL默认值:no 使用字段:location, location中的if字段 这个指令设置被代理服务器的地址和被映射的URI,地址可以使用主机名或IP加端口号的形式,例如:proxy_pass http://localhost:8000/uri/;

8.重新加载一下配置文件

1

2

3

4

[root@nginx ~]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

9.测试一下



注,大家可以看到,当我们访问192.168.18.208时,被代理重新定向到Web1上。

10.查看一下Web服务器日志

1

2

3

4

5

6

7

8

9

10

11

[root@web1 ~]# tail /var/log/httpd/access_log

192.168.18.208 - - [04/Sep/2013:00:14:20 +0800] "GET /favicon.ico HTTP/1.0" 404 289 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

192.168.18.208 - - [04/Sep/2013:00:14:20 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

192.168.18.208 - - [04/Sep/2013:00:14:20 +0800] "GET /favicon.ico HTTP/1.0" 404 289 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

192.168.18.138 - - [04/Sep/2013:00:14:45 +0800] "GET / HTTP/1.1" 200 23 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

192.168.18.138 - - [04/Sep/2013:00:14:48 +0800] "GET /favicon.ico HTTP/1.1" 404 289 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

192.168.18.208 - - [04/Sep/2013:00:14:55 +0800] "GET /favicon.ico HTTP/1.0" 404 289 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

192.168.18.208 - - [04/Sep/2013:00:15:05 +0800] "GET /favicon.ico HTTP/1.0" 404 289 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

192.168.18.208 - - [04/Sep/2013:00:15:13 +0800] "GET /favicon.ico HTTP/1.0" 404 289 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

192.168.18.208 - - [04/Sep/2013:00:15:16 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

192.168.18.208 - - [04/Sep/2013:00:15:16 +0800] "GET /favicon.ico HTTP/1.0" 404 289 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"

注,大家可以看到我们这里的客户的IP全是,nginx代理服务器的IP,并不是真实客户端的IP。下面我们修改一下,让日志的IP显示真实的客户端的IP。

11.修改nginx配置文件

1

2

3

4

location / {

proxy_pass http://192.168.18.201;

proxy_set_header X-Real-IP $remote_addr; #加上这一行

}

指令说明:proxy_set_header

语法:proxy_set_header header value

默认值: Host and Connection

使用字段:http, server, location

这个指令允许将发送到被代理服务器的请求头重新定义或者增加一些字段。这个值可以是一个文本,变量或者它们的组合。proxy_set_header在指定的字段中没有定义时会从它的上级字段继承。

12.重新加载一下配置文件

1

2

3

4

[root@nginx ~]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

13.测试并查看日志

1

2

3

4

5

6

7

8

9

10

11

[root@web1 ~]# tail /var/log/httpd/access_log

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.208 - - [03/Sep/2013:16:26:18 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

注,大家可以看到日志记录的还是代理的IP,没有显示真实客户端的IP,为什么呢?我们来看一下httpd的配置文件。

14.查看并修改httpd配置文件

[root@web1 ~]# vim /etc/httpd/conf/httpd.conf



注,大家可以这里记录日志的参数还是%h,下面我们修改一下参数。



注,这是修改后的参数,将h%修改为%{X-Real-IP}i,好的下面我们再来测试一下。

15.重启并测试

1

2

3

4

5

6

7

8

9

10

11

12

13

14

[root@web1 ~]# service httpd restart

停止 httpd: [确定]

正在启动 httpd: [确定]

[root@web1 ~]# tail /var/log/httpd/access_log

192.168.18.138 - - [03/Sep/2013:17:09:14 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [03/Sep/2013:17:09:14 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [03/Sep/2013:17:09:15 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [03/Sep/2013:17:09:15 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [03/Sep/2013:17:09:15 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [03/Sep/2013:17:09:15 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [03/Sep/2013:17:09:15 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [03/Sep/2013:17:09:15 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [03/Sep/2013:17:09:15 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [03/Sep/2013:17:09:15 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

注,大家可以看到现在的日志里记录的IP地址就是真实的客户端地址了。好了,到这里Nginx代理后端一台服务器就演示到这里,下面我们继续说。

五、Nginx之负载均衡

注,大家可以看到,由于我们网站是发展初期,nginx只代理了后端一台服务器,但由于我们网站名气大涨访问的人越来越多一台服务器实在是顶不住,于是我们加了多台服务器,那么多台服务器又怎么配置代理呢,我们这里以两台服务器为案例,为大家做演示。

1.upstream 负载均衡模块说明

案例:

下面设定负载均衡的服务器列表。

1

2

3

4

5

6

7

8

9

10

11

12

upstream test.net{

ip_hash;

server 192.168.10.13:80;

server 192.168.10.14:80 down;

server 192.168.10.15:8009 max_fails=3 fail_timeout=20s;

server 192.168.10.16:8080;

}

server {

location / {

proxy_pass http://test.net;

}

}

upstream是Nginx的HTTP Upstream模块,这个模块通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。在上面的设定中,通过upstream指令指定了一个负载均衡器的名称test.net。这个名称可以任意指定,在后面需要用到的地方直接调用即可。

2.upstream 支持的负载均衡算法

Nginx的负载均衡模块目前支持4种调度算法,下面进行分别介绍,其中后两项属于第三方调度算法。

轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。Weight 指定轮询权值,Weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。

ip_hash。每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。

fair。这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。

url_hash。此方法按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。

3.upstream 支持的状态参数

在HTTP Upstream模块中,可以通过server指令指定后端服务器的IP地址和端口,同时还可以设定每个后端服务器在负载均衡调度中的状态。常用的状态有:

down,表示当前的server暂时不参与负载均衡。

backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。

max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。

fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。

注,当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup。

4.实验拓扑



5.配置nginx负载均衡

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

[root@nginx ~]# vim /etc/nginx/nginx.conf

upstream webservers {

server 192.168.18.201 weight=1;

server 192.168.18.202 weight=1;

}

server {

listen 80;

server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {

proxy_pass http://webservers;

proxy_set_header X-Real-IP $remote_addr;

}

}

注,upstream是定义在server{ }之外的,不能定义在server{ }内部。定义好upstream之后,用proxy_pass引用一下即可。

6.重新加载一下配置文件

1

2

3

4

[root@nginx ~]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

7.测试一下





注,大家可以不断的刷新浏览的内容,可以发现web1与web2是交替出现的,达到了负载均衡的效果。

8.查看一下Web访问服务器日志

Web1:

1

2

3

4

5

6

7

8

9

10

11

[root@web1 ~]# tail /var/log/httpd/access_log

192.168.18.138 - - [04/Sep/2013:09:41:58 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:41:58 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:41:59 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:41:59 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:42:00 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:42:00 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:42:00 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:44:21 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:44:22 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:44:22 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

Web2:

先修改一下,Web服务器记录日志的格式。

1

2

3

4

5

[root@web2 ~]# vim /etc/httpd/conf/httpd.conf

LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

[root@web2 ~]# service httpd restart

停止 httpd: [确定]

正在启动 httpd: [确定]

接着,再访问多次,继续查看日志。

1

2

3

4

5

6

7

8

9

10

11

[root@web2 ~]# tail /var/log/httpd/access_log

192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:50:28 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:50:29 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

192.168.18.138 - - [04/Sep/2013:09:50:29 +0800] "GET / HTTP/1.0" 200 23 "-" "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"

注,大家可以看到,两台服务器日志都记录是192.168.18.138访问的日志,也说明了负载均衡配置成功。

9.配置nginx进行健康状态检查

max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。

fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用,进行健康状态检查。

1

2

3

4

5

[root@nginx ~]# vim /etc/nginx/nginx.conf

upstream webservers {

server 192.168.18.201 weight=1 max_fails=2 fail_timeout=2;

server 192.168.18.202 weight=1 max_fails=2 fail_timeout=2;

}

10.重新加载一下配置文件

1

2

3

4

[root@nginx ~]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

11.停止服务器并测试

1

2

3

先停止Web1,进行测试。

[root@web1 ~]# service httpd stop

停止 httpd: [确定]



注,大家可以看到,现在只能访问Web2,再重新启动Web1,再次访问一下。

1

2

[root@web1 ~]# service httpd start

正在启动 httpd: [确定]





注,大家可以看到,现在又可以重新访问,说明nginx的健康状态查检配置成功。但大家想一下,如果不幸的是所有服务器都不能提供服务了怎么办,用户打开页面就会出现出错页面,那么会带来用户体验的降低,所以我们能不能像配置LVS是配置sorry_server呢,答案是可以的,但这里不是配置sorry_server而是配置backup。

12.配置backup服务器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

[root@nginx ~]# vim /etc/nginx/nginx.conf

server {

listen 8080;

server_name localhost;

root /data/www.61k.com

index index.html;

}

upstream webservers {

server 192.168.18.201 weight=1 max_fails=2 fail_timeout=2;

server 192.168.18.202 weight=1 max_fails=2 fail_timeout=2;

server 127.0.0.1:8080 backup;

}

[root@nginx ~]# mkdir -pv /data/www.61k.com

[root@nginx errorpage]# cat index.html

<h1>Sorry......</h1>

13.重新加载配置文件

1

2

3

4

[root@nginx errorpage]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

14.关闭Web服务器并进行测试

1

2

3

4

[root@web1 ~]# service httpd stop

停止 httpd: [确定]

[root@web2 ~]# service httpd stop

停止 httpd: [确定]



注,大家可以看到,当所有服务器都不能工作时,就会启动备份服务器。好了,backup服务器就配置到这里,下面我们来配置ip_hash负载均衡。

15.配置ip_hash负载均衡

ip_hash,每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。(一般电子商务网站用的比较多)

1

2

3

4

5

6

7

[root@nginx ~]# vim /etc/nginx/nginx.conf

upstream webservers {

ip_hash;

server 192.168.18.201 weight=1 max_fails=2 fail_timeout=2;

server 192.168.18.202 weight=1 max_fails=2 fail_timeout=2;

#server 127.0.0.1:8080 backup;

}

注,当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能有backup。(有人可能会问,为什么呢?大家想啊,如果负载均衡把你分配到backup服务器上,你能访问到页面吗?不能,所以了不能配置backup服务器)

16.重新加载一下服务器

1

2

3

4

[root@nginx ~]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

17.测试一下



注,大家可以看到,你不断的刷新页面一直会显示的民Web2,说明ip_hash负载均衡配置成功。下面我们来统计一下Web2的访问连接数。

18.统计Web2的访问连接数

1

2

[root@web2 ~]# netstat -an | grep :80 | wc -l

304

注,你不断的刷新,连接数会越来越多。好了,nginx的负载均衡就全部演示到这里下面我们来说一说,页面缓存。

六、Nginx之页面缓存

1.指令说明

proxy_cache_path

语法:proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];

默认值:None

使用字段:http

指令指定缓存的路径和一些其他参数,缓存的数据存储在文件中,并且使用代理url的哈希值作为关键字与文件名。levels参数指定缓存的子目录数,例如:

1

proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;

文件名类似于:

1

/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c

levels指定目录结构,可以使用任意的1位或2位数字作为目录结构,如 X, X:X,或X:X:X 例如: “2”, “2:2”, “1:1:2“,但是最多只能是三级目录。

所有活动的key和元数据存储在共享的内存池中,这个区域用keys_zone参数指定。one指的是共享池的名称,10m指的是共享池的大小。

注意每一个定义的内存池必须是不重复的路径,例如:

1

2

3

proxy_cache_path /data/nginx/cache/one levels=1 keys_zone=one:10m;

proxy_cache_path /data/nginx/cache/two levels=2:2 keys_zone=two:100m;

proxy_cache_path /data/nginx/cache/three levels=1:1:2 keys_zone=three:1000m;

如果在inactive参数指定的时间内缓存的数据没有被请求则被删除,默认inactive为10分钟。一个名为cache manager的进程控制磁盘的缓存大小,它被用来删除不活动的缓存和控制缓存大小,这些都在max_size参数中定义,当目前缓存的值超出max_size指定的值之后,超过其大小后最少使用数据(LRU替换算法)将被删除。内存池的大小按照缓存页面数的比例进行设置,一个页面(文件)的元数据大小按照操作系统来定,如FreeBSD/i386下为64字节,FreeBSD/amd64下为128字节。

proxy_cache

语法:proxy_cache zone_name;

默认值:None

使用字段:http, server, location

设置一个缓存区域的名称,一个相同的区域可以在不同的地方使用。

在0.7.48后,缓存遵循后端的”Expires”, “Cache-Control: no-cache”, “Cache-Control: max-age=XXX”头部字段,0.7.66版本以后,”Cache-Control:“private”和”no-store”头同样被遵循。nginx在缓存过程中不会处理”Vary”头,为了确保一些私有数据不被所有的用户看到,后端必须设置 “no-cache”或者”max-age=0”头,或者proxy_cache_key包含用户指定的数据如$cookie_xxx,使用cookie的值作为proxy_cache_key的一部分可以防止缓存私有数据,所以可以在不同的location中分别指定proxy_cache_key的值以便分开私有数据和公有数据。

缓存指令依赖代理缓冲区(buffers),如果proxy_buffers设置为off,缓存不会生效。

proxy_cache_valid

语法:proxy_cache_valid reply_code [reply_code …] time;

默认值:None

使用字段:http, server, location

为不同的应答设置不同的缓存时间,例如:

1

2

proxy_cache_valid 200 302 10m;

proxy_cache_valid 404 1m;

为应答代码为200和302的设置缓存时间为10分钟,404代码缓存1分钟。

如果只定义时间:

1

proxy_cache_valid 5m;

那么只对代码为200, 301和302的应答进行缓存。

同样可以使用any参数任何应答。

1

2

3

proxy_cache_valid 200 302 10m;

proxy_cache_valid 301 1h;

proxy_cache_valid any 1m;

2.定义一个简单nginx缓存服务器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

[root@nginx ~]# vim /etc/nginx/nginx.conf

proxy_cache_path /data/nginx/cache/webserver levels=1:2 keys_zone=webserver:20m max_size=1g;

server {

listen 80;

server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {

proxy_pass http://webservers;

proxy_set_header X-Real-IP $remote_addr;

proxy_cache webserver;

proxy_cache_valid 200 10m;

}

}

3.新建缓存目录

1

[root@nginx ~]# mkdir -pv /data/nginx/cache/webserver

4.重新加载一下配置文件

1

2

3

4

[root@nginx webserver]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

5.下面我们来测试一下(谷歌浏览器)



注,大家用谷歌浏览器测试的时候,可以按F12调用开发工具,选择Network选项,我们可以看到,Response Headers,在这里我们可以看到,我们请求的是否是缓存,但现在还看不到,下面我们来配置一下,再来测试。

6. 缓存变量说明

$server_addr

服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。

$upstream_cache_status

0.8.3版本中其值可能为:

MISS 未命中

EXPIRED - expired。请求被传送到后端。

UPDATING - expired。由于proxy/fastcgi_cache_use_stale正在更新,将使用旧的应答。

STALE - expired。由于proxy/fastcgi_cache_use_stale,后端将得到过期的应答。

HIT 命中

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

[root@nginx ~]# vim /etc/nginx/nginx.conf

proxy_cache_path /data/nginx/cache/webserver levels=1:2 keys_zone=webserver:20m max_size=1g;

server {

listen 80;

server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

#增加两头部

add_header X-Via $server_addr;

add_header X-Cache $upstream_cache_status;

location / {

proxy_pass http://webservers;

proxy_set_header X-Real-IP $remote_addr;

proxy_cache webserver;

proxy_cache_valid 200 10m;

}

}

7.重新加载一下配置文件

1

2

3

4

[root@nginx ~]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

8.测试一下



注,从图中我们可以看到,我们访问的服务器是192.168.18.208,缓存命中。大家可以看到是不是很直观啊。下面我们看一下缓存目录。

9.查看一下缓存目录

1

2

3

[root@nginx ~]# cd /data/nginx/cache/webserver/f/63/

[root@nginx 63]# ls

681ad4c77694b65d61c9985553a2763f

注,缓存目录里确实有缓存文件。好了,nginx缓存配置就到这边了,更多配置请根据需要看配置文档。下面我们来说一下,URL重写。

七、Nginx之URL重写

1.URL重写模块(Rewrite)

摘要

这个模块允许使用正则表达式重写URI(需PCRE库),并且可以根据相关变量重定向和选择不同的配置。如果这个指令在server字段中指定,那么将在被请求的location确定之前执行,如果在指令执行后所选择的location中有其他的重写规则,那么它们也被执行。如果在location中执行这个指令产生了新的URI,那么location又一次确定了新的URI。这样的循环可以最多执行10次,超过以后nginx将返回500错误。

指令

break

语法:break

默认值:none

使用字段:server, location, if

完成当前设置的规则,停止执行其他的重写指令。

示例:

1

2

3

4

if ($slow) {

limit_rate 10k;

break;

}

if

语法:if (condition) { … }

默认值:none

使用字段:server, location

注意:在使用if指令之前请查看if is evil page并且尽量考虑用try_files代替。

判断一个条件,如果条件成立,则后面的大括号内的语句将执行,相关配置从上级继承。

可以在判断语句中指定下列值:

一个变量的名称;不成立的值为:空字符传”“或者一些用“0”开始的字符串。

一个使用=或者!=运算符的比较语句。

使用符号~*和~模式匹配的正则表达式:

~为区分大小写的匹配。

~*不区分大小写的匹配(firefox匹配FireFox)。

!~和!~*意为“不匹配的”。

使用-f和!-f检查一个文件是否存在。

使用-d和!-d检查一个目录是否存在。

使用-e和!-e检查一个文件,目录或者软链接是否存在。

使用-x和!-x检查一个文件是否为可执行文件。

正则表达式的一部分可以用圆括号,方便之后按照顺序用$1-$9来引用。

示例配置:

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

if ($http_user_agent ~ MSIE) {

rewrite ^(.*)$ /msie/$1 break;

}

if ($http_cookie ~* "id=([^;] +)(?:;|$)" ) {

set $id $1;

}

if ($request_method = POST ) {

return 405;

}

if (!-f $request_filename) {

break;

proxy_pass http://127.0.0.1;

}

if ($slow) {

limit_rate 10k;

}

if ($invalid_referer) {

return 403;

}

if ($args ~ post=140){

rewrite ^ http://example.com/ permanent;

}

内置变量$invalid_referer用指令valid_referers指定。

return

语法:return code

默认值:none

使用字段:server, location, if

这个指令结束执行配置语句并为客户端返回状态代码,可以使用下列的值:204,400,402-406,408,410, 411, 413, 416与500-504。此外,非标准代码444将关闭连接并且不发送任何的头部。

rewrite

语法:rewrite regex replacement flag

默认值:none

使用字段:server, location, if

按照相关的正则表达式与字符串修改URI,指令按照在配置文件中出现的顺序执行。

可以在重写指令后面添加标记。

如果替换的字符串以http://开头,请求将被重定向,并且不再执行多余的rewrite指令。

尾部的标记(flag)可以是以下的值:

last - 完成重写指令,之后搜索相应的URI或location。

break - 完成重写指令。

redirect - 返回302临时重定向,如果替换字段用http://开头则被使用。

permanent - 返回301永久重定向。

注意如果一个重定向是相对的(没有主机名部分),nginx将在重定向的过程中使用匹配server_name指令的“Host”头或者server_name指令指定的第一个名称,如果头不匹配或不存在,如果没有设置server_name,将使用本地主机名,如果你总是想让nginx使用“Host”头,可以在server_name使用“*”通配符(查看http核心模块中的server_name)。例如:

1

2

3

rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;

rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;

return 403;

但是如果我们将其放入一个名为/download/的location中,则需要将last标记改为break,否则nginx将执行10次循环并返回500错误。

1

2

3

4

5

location /download/ {

rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;

rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break;

return 403;

}

如果替换字段中包含参数,那么其余的请求参数将附加到后面,为了防止附加,可以在最后一个字符后面跟一个问号:

1

rewrite ^/users/(.*)$ /show?user=$1? last;

注意:大括号({和}),可以同时用在正则表达式和配置块中,为了防止冲突,正则表达式使用大括号需要用双引号(或者单引号)。例如要重写以下的URL:

1

/photos/123456

为:

1

/path/to/photos/12/1234/123456.png

则使用以下正则表达式(注意引号):

1

rewrite "/photos/([0-9] {2})([0-9] {2})([0-9] {2})" /path/to/photos/$1/$1$2/$1$2$3.png;

如果指定一个“?”在重写的结尾,Nginx将丢弃请求中的参数,即变量$args,当使用$request_uri或$uri&$args时可以在rewrite结尾使用“?”以避免nginx处理两次参数串。

在rewrite中使用$request_uri将www.61k.com写到example.com:

1

2

3

4

server {

server_name www.61k.com

rewrite ^ http://example.com$request_uri? permanent;

}

同样,重写只对路径进行操作,而不是参数,如果要重写一个带参数的URL,可以使用以下代替:

1

2

3

if ($args ^~ post=100){

rewrite ^ ? permanent;

}

注意$args变量不会被编译,与location过程中的URI不同(参考http核心模块中的location)。

rewrite_log

语法:rewrite_log on | off

默认值:rewrite_log off

使用字段:server, location, if

变量:无

启用时将在error log中记录notice 标记的重写日志。

set

语法:set variable value

默认值:none

使用字段:server, location, if

指令设置一个变量并为其赋值,其值可以是文本,变量和它们的组合。

你可以使用set定义一个新的变量,但是不能使用set设置$http_xxx头部变量的值。

uninitialized_variable_warn

语法:uninitialized_variable_warn on|off

默认值:uninitialized_variable_warn on

使用字段:http, server, location, if

开启或关闭在未初始化变量中记录警告日志。

事实上,rewrite指令在配置文件加载时已经编译到内部代码中,在解释器产生请求时使用。

这个解释器是一个简单的堆栈虚拟机,如下列指令:

1

2

3

4

5

6

7

8

location /download/ {

if ($forbidden) {

return 403;

}

if ($slow) {

limit_rate 10k;

}

rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;

将被编译成以下顺序:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

variable $forbidden

checking to zero

recovery 403

completion of entire code

variable $slow

checking to zero

checkings of regular excodession

copying "/"

copying $1

copying "/mp3/"

copying $2

copying ".mp3"

completion of regular excodession

completion of entire sequence

注意并没有关于limit_rate的代码,因为它没有提及ngx_http_rewrite_module模块,“if”块可以类似”location”指令在配置文件的相同部分同时存在。

如果$slow为真,对应的if块将生效,在这个配置中limit_rate的值为10k。

指令:

1

rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;

如果我们将第一个斜杠括入圆括号,则可以减少执行顺序:

1

rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;

之后的顺序类似如下:

1

2

3

4

5

6

7

checking regular excodession

copying $1

copying "/mp3/"

copying $2

copying ".mp3"

completion of regular excodession

completion of entire code

2.简单案例注,由于配置文件内容较多,为了让大家看着方便,我们备份一下配置文件,打开一个新的配置文件。1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

[root@nginx ~]# cd /etc/nginx/

[root@nginx nginx]# mv nginx.conf nginx.conf.proxy

[root@nginx nginx]# cp nginx.conf.bak nginx.conf

[root@nginx nginx]# vim /etc/nginx/nginx.conf

server {

listen 80;

server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {

root html;

index index.html index.htm;

rewrite ^/bbs/(.*)$ http://192.168.18.201/forum/$1;

}

}

准备forum目录与测试文件1

2

3

4

5

6

7

[root@web1 ~]# cd /var/www/html/

[root@web1 html]# ls

index.html

[root@web1 html]# mkdir forum

[root@web1 html]# cd forum/

[root@web1 forum]# vim index.html

<h1>forum page!</h1>

测试一下



好了,下面我们来测试一下rewrite重写。

3.重新加载一下配置文件1

2

3

4

[root@nginx 63]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

4.测试一下



注,大家可以从图中看出,status code 302指的是临时重定向,那就说明我们rewrite重写配置成功。大家知道302是临时重定向而301是永久重定向,那么怎么实现永久重定向呢。一般服务器与服务器之间是临时重定向,服务器内部是永久重定向。下面我们来演示一下永久重定向。

5.配置永久重定向

1

2

3

4

5

6

7

8

9

10

11

12

[root@nginx nginx]# vim /etc/nginx/nginx.conf

server {

listen 80;

server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {

root html;

index index.html index.htm;

rewrite ^/bbs/(.*)$ /forum/$1;

}

}

准备forum目录与测试文件1

2

3

4

5

6

7

[root@nginx ~]# cd /usr/html/

[root@nginx html]# ls

50x.html index.html

[root@nginx html]# mkdir forum

[root@nginx html]# cd forum/

[root@nginx forum]# vim index.html

<h1>192.168.18.208 forum page</h1>

6.重新加载一下配置文件

1

2

3

4

[root@nginx ~]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

7.测试一下



注,大家从图中可以看到,我们访问bbs/是直接帮我们跳转到forum/下,这种本机的跳转就是永久重定向也叫隐式重定向。好了,rewrite重定向我们就说到这里了,想要查询更多关于重定向的指令请参考官方文档。最后,我们来说一下读写分离。

八、Nginx之读写分离

1.实验拓扑



需求分析,前端一台nginx做负载均衡反向代理,后面两台httpd服务器。整个架构是提供BBS(论坛)服务,有一需求得实现读写分离,就是上传附件的功能,我们上传的附件只能上传到Web1,然后在Web1上利用rsync+inotify实现附件同步,大家都知道rsync+inotify只能是主向从同步,不能双向同步。所以Web1可进行写操作,而Web2只能进行读操作,这就带来读写分离的需求,下面我们就来说一下,读写分离怎么实现。

2.WebDAV功能说明

WebDAV (Web-based Distributed Authoring and Versioning) 一种基于 HTTP 1.1协议的通信协议。它扩展了HTTP 1.1,在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法,使应用程序可直接对Web Server直接读写,并支持写文件锁定(Locking)及解锁(Unlock),还可以支持文件的版本控制。这样我们就能配置读写分离功能了,下面我们来具体配置一下。

3.修改配置文件

1

2

3

4

5

6

7

8

9

10

11

12

13

[root@nginx nginx]# vim /etc/nginx/nginx.conf

server {

listen 80;

server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {

proxy_pass http://192.168.18.202;

if ($request_method = "PUT"){

proxy_pass http://192.168.18.201;

}

}

}

4.重新加载一下配置文件

1

2

3

4

[root@nginx ~]# service nginx reload

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

重新载入 nginx: [确定]

5.配置httpd的WebDAV功能

1

[root@web1 ~]# vim /etc/httpd/conf/httpd.conf



注,在<Directory "/var/www/html">下启用就行。

6.重新启动一下httpd

1

2

3

[root@web1 ~]# service httpd restart

停止 httpd: [确定]

正在启动 httpd: [确定]

7.测试一下

1

2

3

4

[root@nginx ~]# curl http://192.168.18.201

<h1>web1.test.com</h1>

[root@nginx ~]# curl http://192.168.18.202

<h1>web2.test.com</h1>

注,web1与web2访问都没问题。

1

2

3

4

5

6

7

8

9

10

[root@nginx ~]# curl -T /etc/issue http://192.168.18.202

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">

<html><head>

<title>405 Method Not Allowed</title>

</head><body>

<h1>Method Not Allowed</h1>

The requested method PUT is not allowed for the URL /issue.

<hr>

<address>Apache/2.2.15 (CentOS) Server at 192.168.18.202 Port 80</address>

</body></html>

注,我们上传文件到,web2上时,因为web2只人读功能,所以没有开户WebDAV功能,所以显示是405 Method Not Allowed。

1

2

3

4

5

6

7

8

9

10

11

[root@nginx ~]# curl -T /etc/issue http://192.168.18.201

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">

<html><head>

<title>403 Forbidden</title>

</head><body>

<h1>Forbidden</h1>

You don't have permission to access /issue

on this server.

<hr>

<address>Apache/2.2.15 (CentOS) Server at 192.168.18.201 Port 80</address>

</body></html>

注,我们在Web1开启了WebDAV功能,但我们目录是root目录是不允许apache用户上传的,所以显示的是403 Forbidden。下面我们给apache授权,允许上传。

1

[root@web1 ~]# setfacl -m u:apache:rwx /var/www/html/

下面我们再来测试一下,

1

2

3

4

5

6

7

8

9

10

[root@nginx ~]# curl -T /etc/issue http://192.168.18.201

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">

<html><head>

<title>201 Created</title>

</head><body>

<h1>Created</h1>

Resource /issue has been created.

<hr />

<address>Apache/2.2.15 (CentOS) Server at 192.168.18.201 Port 80</address>

</body></html>

注,大家可以看到我们成功的上传了文件,说明nginx读写分离功能配置完成。最后,我们来查看一下上传的文件。

1

2

3

4

5

6

[root@web1 ~]# cd /var/www/html/

[root@web1 html]# ll

总用量 12

drwxr-xr-x 2 root root 4096 9月 4 13:16 forum

-rw-r--r-- 1 root root 23 9月 3 23:37 index.html

-rw-r--r-- 1 apache apache 47 9月 4 14:06 issue

好了,到这里nginx的反向代理、负载均衡、页面缓存、URL重写及读写分离就全部讲解完成。希望大家有所收获,^_^……

本文出自 “Share your knowledge …” 博客,请务必保留此出处http://freeloda.blog.51cto.com/2033581/1288553
本文标题:负载均衡解决方案-Centos双网卡bonding绑定实现负载均衡的方法
本文地址: http://www.61k.com/1064518.html

61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1