天天看点

使用Nginx1.9.9+Keepalived1.2.x搭建高可用负载均衡集群一 简介以及原理介绍二 nginx安装和配置三 Keepalived的安装和配置

(1)Nginx概念介绍:

Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。由俄罗斯的程序设计师Igor Sysoev所开发。其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等

(2)Keepalived概念介绍:

Keepalived的作用是检测服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器

(3)下面实例的简单网络拓扑图:

<a href="http://s4.51cto.com/wyfs02/M02/88/FE/wKiom1gEL7yBrD3FAACSP2q2wtw165.png" target="_blank"></a>

几个重要概念:

反向代理:指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器

负载均衡:将来自互联网的大量请求通过某种算法分配到多台应用服务器上执行,以此增加应用吞吐量、加强网络数据处理能力以及提高网络的灵活性和可用性

(4)原理介绍:

使用Nginx搭建高可用负载均衡集群,顾名思义就是使用Nginx充当反向代理服务器,将来自互联网的大量请求通过某种hash策略均匀地分配到内网中的多个应用节点。当某个应用节点因为某种原因变得不可用时,Nginx将会自动将该节点从这个服务的节点列表中剔除,直到该节点恢复正常

从上面的我画的这个网络拓扑图中可以看出,这里的具体业务就是一个H5应用了。至于这个应用是用Java来写的还是用PHP或者其他语言来写的都不是我们这里关心的重点,重点是我们知道这个H5应用分别运行在192.168.100.104和192.168.100.105的9080端口、192.168.100.106和192.168.100.107的9280端口就足够了

那么,从用户点击一条链接到返回对应视图到用户的浏览器,这个整个流程是如何通过Nginx来实现的呢?

这里,我就以用户点击H5应用的“首页”来简单叙述整个过程:

访问“首页”,如:http://h5.zifangsky.cn/index.html

通过DNS解析,h5.zifangsky.cn个域名被解析到整个应用集群的外网IP:xx.xx.xx.xx,也就是说在这一步请求的是:http://xx.xx.xx.xx/index.html

当然,这里的外网IP并没有解析到某一个具体的服务器,而是连接的路由器,因此接下来通过路由器的端口映射,这个请求就被指向192.168.100.100这个Keepalived生成的虚拟IP。因此这时相当于请求的是:http://192.168.100.100/index.html

这个虚拟IP对应于某个真实的Nginx服务器的IP(PS:关于Keepalived生成一个虚拟IP的作用以及如何对应到一台具体的服务器我会在下面再说),如:192.168.100.104,因此这时相当于请求的是:http://192.168.100.104/index.html

到了这一步,nginx将通过请求的域名、端口号以及URI地址等因素决定将该请求分配给哪个upstream(某个应用的节点列表),当然这里的节点列表包括104-107四个节点。此时,来自互联网的这个请求才通过nginx的某种hash策略被分配到一个具体的应用服务器,如:http://192.168.100.107:9280/h5/index.html

应用服务器执行完请求之后将结果原路返回给用户

用户浏览器根据返回数据包展示页面。到此,此次请求流程结束

看到这里,很多童鞋可能会有疑问:为什么在上面的网络拓扑图中安装了2个nginx,一个nginx不是也可以达到我们所需要的效果吗?为什么要用keepalived产生一个虚拟IP?为什么还要多此一举通过那个虚拟IP转一次?

其实原因很简单,那就是如果只用一台服务器装nginx来做反向代理服务器,那么这个集群的所有请求都将会通过这个nginx来转发,如果某一天这台装nginx的服务器突然宕机了,那将导致所有服务都没法使用了,直到nginx恢复正常工作

因此,为了避免这个问题的产生,一般需要安装两个nginx来做反向代理服务器。同时这两个nginx之间是一种主-备份策略的模式,也就是说当某一个nginx挂掉的时候,外网的所有请求可以自动转发到另一台nginx上去。那么怎么来实现这个目的呢?

这时,keepalived就派上用场了,keepalived的作用是:可以将多个IP绑定在一起,生成一个虚拟IP。其中,当有多个IP节点存在时,可以设置一个主节点以及多个备份节点。当keepalived启动时,将会在主节点上生成我们在配置文件中配置的虚拟IP,如果某一时刻keepalived检测到主节点不可用(PS:通过检测IP是否可以ping通、某个预先配置的端口是否打开等手段来检测)时,将会自动把该虚拟IP切换到其他备份节点上,至于切换到哪个备份节点是根据每个备份节点的权重来决定的(PS:可以在每个节点的keepalived配置文件中配置权重等参数)。因为来自外网的请求一直请求的是虚拟IP,因此只要不是所有的nginx节点同时挂掉,整个应用服务都是可用的,这样就保证了应用的高可用性

关于原理的介绍我就暂时说到这里了,下面我将以具体的实例来简单介绍具体应该如何安装和搭建

注:以上概念部分参考至百度百科

1 关闭SELinux:

查看SELinux的状态:

1

<code>[root@nmp01 src]</code><code># getenforce</code>

如果是开启状态,则

<code>[root@nmp01 src]</code><code># vim /etc/selinux/config</code>

修改如下:

2

3

<code>#SELINUX=enforcing #注释掉</code>

<code>#SELINUXTYPE=targeted #注释掉</code>

<code>SELINUX=disabled #增加</code>

重启系统:

<code>[root@nmp01 src]</code><code># reboot</code>

2 安装编译工具:

4

<code>[root@nmp01 src]</code><code># yum update</code>

<code>[root@nmp01 src]</code><code># yum install wget make gcc gcc-c++ zlib-devel openssl openssl-devel pcre-devel gd kernel keyutils patch perl mhash</code>

<code>[root@nmp01 src]</code><code># yum install popt-devel -y</code>

3 系统约定:

软件源代码包存放位置:/usr/local/src

源码包编译安装位置:/usr/local/软件名字

默认系统就会加载/dev/shm ,它就是所谓的tmpfs,有人说跟ramdisk(虚拟磁盘),但不一样。象虚拟磁盘一样,tmpfs 可以使用您的

RAM,但它也可以使用您的交换分区来存储。而且传统的虚拟磁盘是个块设备,并需要一个 mkfs 之类的命令才能真正地使用它,tmpfs

是一个文件系统,而不是块设备;您只是安装它,它就可以使用了。

tmpfs有以下优势:

1)动态文件系统的大小,

2)tmpfs 的另一个主要的好处是它闪电般的速度。因为典型的 tmpfs 文件系统会完全驻留在 RAM 中,读写几乎可以是瞬间的。

3)tmpfs 数据在重新启动之后不会保留,因为虚拟内存本质上就是易失的。所以有必要做一些脚本做诸如加载,绑定的操作。

首先在/dev/shm建个tmp文件夹,然后与实际/tmp绑定

<code>[root@nmp01 src]</code><code># mkdir /dev/shm/tmp</code>

<code>[root@nmp01 src]</code><code># chmod 777 /dev/shm/tmp</code>

<code>[root@nmp01 src]</code><code># mount --bind /dev/shm/tmp /tmp</code>

4 下载软件:

<code>[root@nmp01 src]</code><code># cd /usr/local/src</code>

(1)下载nginx:

<code>[root@nmp01 src]</code><code># wget http://nginx.org/download/nginx-1.9.9.tar.gz</code>

(2)下载pcre (支持nginx伪静态):

<code>[root@nmp01 src]</code><code># wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.36.tar.gz</code>

(3)下载ngx_cache_purge(清除指定URL缓存):

<code>[root@nmp01 src]</code><code># wget http://labs.frickle.com/files/ngx_cache_purge-2.0.tar.gz</code>

(4)下载keepalived:

<code>[root@nmp01 src]</code><code># wget http://www.keepalived.org/software/keepalived-1.2.2.tar.gz</code>

注:由于这些软件包是我当初下载安装的,因此其他童鞋现在安装时可以考虑下载新版安装包

5 添加www用户以及www用户组:

<code>[root@nmp01 src]</code><code># groupadd www #添加www组</code>

<code>[root@nmp01 src]</code><code># useradd -g www www -s /bin/false</code>

6 安装pcre:

5

<code>[root@nmp01 src]</code><code># tar zxvf pcre-8.36.tar.gz</code>

<code>[root@nmp01 src]</code><code># cd /usr/local/src/pcre-8.38</code>

<code>[root@nmp01 pcre-8.38]</code><code># ./configure</code>

<code>[root@nmp01 pcre-8.38]</code><code># make</code>

<code>[root@nmp01 pcre-8.38]</code><code># make install</code>

7 安装nginx:

(1)解压缩:

<code>[root@nmp01 src]</code><code># tar -zxvf ngx_cache_purge-2.0.tar.gz</code>

<code>[root@nmp01 src]</code><code># tar -zxvf nginx-1.9.9.tar.gz</code>

<code>[root@nmp01 src]</code><code># cd nginx-1.9.9</code>

(2)编译安装:

<code>[root@nmp01 nginx-1.9.9]</code><code># ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_ssl_module --with-openssl=/usr/local/ssl --with-pcre=/usr/local/src/pcre-8.38 --addmodule=/usr/local/src/ngx_cache_purge-2.3 --with-http_gzip_static_module</code>

<code>[root@nmp01 nginx-1.9.9]</code><code># make &amp;&amp; make install</code>

<code>[root@nmp01 nginx-1.9.9]</code><code># chown www.www -R /usr/local/nginx/html #设置目录所有者</code>

注:如果不需要https证书的话,可以把“–with-http_ssl_module –with-openssl=/usr/local/ssl”删掉,否则需要安装openssl

附:openssl安装: i)下载地址: <a href="https://www.openssl.org/source/openssl-1.0.2h.tar.gz" target="_blank">https://www.openssl.org/source/openssl-1.0.2h.tar.gz</a> ii)安装: <code>[root@nmp01 src]</code><code># tar zxvf ./openssl-1.0.2h.tar.gz</code> <code>[root@nmp01 src]</code><code># cd ./openssl-1.0.2h</code> <code>[root@nmp01 src]</code><code># ./config enable-tlsext</code> <code>[root@nmp01 src]</code><code># make &amp;&amp; make install</code>

注:

编译时添加的“enable-tlsext”是为了提供对多个https证书的支持

(3)添加nginx启动脚本:

i)如果是redhat7.x或centos7.x的话,使用以下脚本:

<code>[root@prx03 init.d]</code><code># vim /usr/lib/systemd/system/nginx.service</code>

内容如下:

6

7

8

9

10

11

12

13

14

<code>[Unit]</code>

<code>Description=nginx - high performance web server</code>

<code>Documentation=http:</code><code>//nginx</code><code>.org</code><code>/en/docs/</code>

<code>After=network.target remote-fs.target nss-lookup.target</code>

<code>[Service]</code>

<code>Type=forking</code>

<code>PIDFile=</code><code>/usr/local/nginx/logs/nginx</code><code>.pid</code>

<code>ExecStartPre=</code><code>/usr/local/nginx/sbin/nginx</code> <code>-t -c </code><code>/usr/local/nginx/conf/nginx</code><code>.conf</code>

<code>ExecStart=</code><code>/usr/local/nginx/sbin/nginx</code> <code>-c </code><code>/usr/local/nginx/conf/nginx</code><code>.conf</code>

<code>ExecReload=</code><code>/bin/kill</code> <code>-s HUP $MAINPID</code>

<code>ExecStop=</code><code>/bin/kill</code> <code>-s QUIT $MAINPID</code>

<code>PrivateTmp=</code><code>true</code>

<code>[Install]</code>

<code>WantedBy=multi-user.target</code>

给脚本添加执行权限:

<code>[root@prx03 init.d]</code><code># chmod a+x /usr/lib/systemd/system/nginx.service</code>

ii)如果是CentOS6.x或者redhat6.x的话使用下面这个脚本:

<code>[root@app01 ~]</code><code># vim /etc/init.d/nginx</code>

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

<code>#!/bin/sh</code>

<code>#</code>

<code># nginx - this script starts and stops the nginx daemon</code>

<code># chkconfig:   - 85 15</code>

<code># description: Nginx is an HTTP(S) server, HTTP(S) reverse \</code>

<code>#               proxy and IMAP/POP3 proxy server</code>

<code># processname: nginx</code>

<code># config:      /etc/nginx/nginx.conf</code>

<code># config:      /etc/sysconfig/nginx</code>

<code># pidfile:     /var/run/nginx.pid</code>

<code># Source function library.</code>

<code>. </code><code>/etc/rc</code><code>.d</code><code>/init</code><code>.d</code><code>/functions</code>

<code># Source networking configuration.</code>

<code>. </code><code>/etc/sysconfig/network</code>

<code># Check that networking is up.</code>

<code>[ </code><code>"$NETWORKING"</code> <code>= </code><code>"no"</code> <code>] &amp;&amp; </code><code>exit</code> <code>0</code>

<code>nginx=</code><code>"/usr/local/nginx/sbin/nginx"</code>

<code>prog=$(</code><code>basename</code> <code>$nginx)</code>

<code>NGINX_CONF_FILE=</code><code>"/usr/local/nginx/conf/nginx.conf"</code>

<code>[ -f </code><code>/etc/sysconfig/nginx</code> <code>] &amp;&amp; . </code><code>/etc/sysconfig/nginx</code>

<code>lockfile=</code><code>/var/lock/subsys/nginx</code>

<code>start() {</code>

<code>    </code><code>[ -x $nginx ] || </code><code>exit</code> <code>5</code>

<code>    </code><code>[ -f $NGINX_CONF_FILE ] || </code><code>exit</code> <code>6</code>

<code>    </code><code>echo</code> <code>-n $</code><code>"Starting $prog: "</code>

<code>    </code><code>daemon $nginx -c $NGINX_CONF_FILE</code>

<code>    </code><code>retval=$?</code>

<code>    </code><code>echo</code>

<code>    </code><code>[ $retval -</code><code>eq</code> <code>0 ] &amp;&amp; </code><code>touch</code> <code>$lockfile</code>

<code>    </code><code>return</code> <code>$retval</code>

<code>}</code>

<code>stop() {</code>

<code>    </code><code>echo</code> <code>-n $</code><code>"Stopping $prog: "</code>

<code>    </code><code>killproc $prog -QUIT</code>

<code>    </code><code>[ $retval -</code><code>eq</code> <code>0 ] &amp;&amp; </code><code>rm</code> <code>-f $lockfile</code>

<code>killall -9 nginx</code>

<code>restart() {</code>

<code>    </code><code>configtest || </code><code>return</code> <code>$?</code>

<code>    </code><code>stop</code>

<code>    </code><code>sleep</code> <code>1</code>

<code>    </code><code>start</code>

<code>reload() {</code>

<code>    </code><code>echo</code> <code>-n $</code><code>"Reloading $prog: "</code>

<code>    </code><code>killproc $nginx -HUP</code>

<code>RETVAL=$?</code>

<code>force_reload() {</code>

<code>    </code><code>restart</code>

<code>configtest() {</code>

<code>$nginx -t -c $NGINX_CONF_FILE</code>

<code>rh_status() {</code>

<code>    </code><code>status $prog</code>

<code>rh_status_q() {</code>

<code>    </code><code>rh_status &gt;</code><code>/dev/null</code> <code>2&gt;&amp;1</code>

<code>case</code> <code>"$1"</code> <code>in</code>

<code>    </code><code>start)</code>

<code>        </code><code>rh_status_q &amp;&amp; </code><code>exit</code> <code>0</code>

<code>    </code><code>$1</code>

<code>        </code><code>;;</code>

<code>    </code><code>stop)</code>

<code>        </code><code>rh_status_q || </code><code>exit</code> <code>0</code>

<code>        </code><code>$1</code>

<code>    </code><code>restart|configtest)</code>

<code>    </code><code>reload)</code>

<code>        </code><code>rh_status_q || </code><code>exit</code> <code>7</code>

<code>    </code><code>force-reload)</code>

<code>        </code><code>force_reload</code>

<code>    </code><code>status)</code>

<code>        </code><code>rh_status</code>

<code>    </code><code>condrestart|try-restart)</code>

<code>            </code><code>;;</code>

<code>    </code><code>*)    </code>

<code>      </code><code>echo</code> <code>$</code><code>"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"</code>  

<code>        </code><code>exit</code> <code>2</code>

<code>esac</code>

同样给脚本添加可执行权限:

<code>[root@app01 ~]</code><code># chmod a+x /etc/init.d/nginx</code>

关闭80端口进程:

<code>[root@app01 init.d]</code><code># fuser -k 80/tcp</code>

<code>[root@app01 init.d]</code><code># systemctl daemon-reload</code>

将nginx添加到开机自启:

<code>[root@app01 ~]</code><code># chkconfig nginx on</code>

(4)启动nginx:

<code>[root@app01 ~]</code><code># service nginx start</code>

如果nginx能够顺利启动的话,那么nginx的安装就完成了,剩下就是nginx的配置了

8 配置和优化nginx:

(1)关闭nginx:

<code>[root@app01 ~]</code><code># service nginx stop</code>

(2)新建目录vhost:

<code>[root@app01 ~]</code><code># cd /usr/local/nginx/conf</code>

<code>[root@app01 conf]</code><code># mkdir vhost</code>

注:nginx可以监听来自多个域名或者同一域名不同端口的多种请求,对这些请求进行反向代理都将在这个目录中配置

(3)配置nginx:

添加以下4个文件(在/usr/local/nginx/conf目录下),如果原文件存在则覆盖

i)gzip.conf:

<code>#网页GZIP压缩设置</code>

<code>#2012.4.2</code>

<code> </code><code>#可通过http://tool.chinaz.com/Gzips/检测压缩情况</code>

<code> </code><code>#启动预压缩功能,对所有类型的文件都有效</code>

<code>gzip_static on;    #开启nginx_static后,对于任何文件都会先查找是否有对应的gz文件</code>

<code>#找不到预压缩文件,进行动态压缩</code>

<code>gzip on;</code>

<code> </code><code>gzip_min_length   1k;  #设置最小的压缩值,单位为bytes.超过设置的min_length的值会进行压缩,小于的不压缩.</code>

<code>gzip_comp_level   3;   #压缩等级设置,1-9,1是最小压缩,速度也是最快的;9刚好相反,最大的压缩,速度是最慢的,消耗的CPU资源也多</code>

<code>gzip_buffers      16 64k;   #设置系统的缓存大小,以存储GZIP压缩结果的数据流,它可以避免nginx频烦向系统申请压缩空间大小</code>

<code>gzip_types text/plain application/x-javascript text/css text/javascript;</code>

<code> </code><code>#关于gzip_types,如果你想让图片也开启gzip压缩,那么用以下这段吧:</code>

<code>#gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php image/jpeg image/gif image/png;</code>

<code> </code><code>#gzip公共配置</code>

<code>gzip_http_version 1.1;      #识别http的协议版本(1.0/1.1)</code>

<code> </code><code>gzip_proxied      any;      #设置使用代理时是否进行压缩,默认是off的</code>

<code>gzip_vary         on;       #和http头有关系,加个vary头,代理判断是否需要压缩</code>

<code>gzip_disable "MSIE [1-6]."; #禁用IE6的gzip压缩</code>

这个文件是配置gzip压缩的

ii)proxy.conf:

<code>proxy_temp_path   /tmp/proxy_temp;</code>

<code> </code><code>proxy_cache_path  /tmp/proxy_cache levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=3g;</code>

<code> </code><code>client_body_buffer_size  512k;     #原为512k</code>

<code> </code><code>proxy_connect_timeout    50;       #代理连接超时</code>

<code>proxy_read_timeout       600;      #代理发送超时</code>

<code>proxy_send_timeout       600;      #代理接收超时</code>

<code>proxy_buffer_size        128k;     #代理缓冲大小,原为32k</code>

<code> </code><code>proxy_buffers           16 256k;   #代理缓冲,原为4 64k</code>

<code> </code><code>proxy_busy_buffers_size 512k;      #高负荷下缓冲大小,原为128k</code>

<code> </code><code>proxy_temp_file_write_size 1024m;  #proxy缓存临时文件的大小原为128k</code>

<code> </code><code>#proxy_ignore_client_abort  on;    #不允许代理端主动关闭连接</code>

<code>proxy_next_upstream error timeout invalid_header http_500 http_503 http_404 http_502 http_504;</code>

这个文件是关于代理的一些配置

iii)nginx.conf:

<code>user  www www;</code>

<code> </code><code>worker_processes  32;   # 工作进程数,为CPU的核心数或者两倍</code>

<code> </code><code>error_log   logs/error.log  crit; # debug|info|notice|warn|error|crit</code>

<code> </code><code>pid        logs/nginx.pid;</code>

<code> </code><code>events {</code>

<code>    </code><code>use epoll;                            #Linux最常用支持大并发的事件触发机制</code>

<code>    </code><code>worker_connections  65535;</code>

<code> </code><code>}</code>

<code> </code><code>http {</code>

<code>     </code><code>include       mime.types;             #设定mime类型,类型由mime.type文件定义</code>

<code>     </code><code>default_type  application/octet-stream;</code>

<code>    </code><code>log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '</code>

<code>                      </code><code>'$status $body_bytes_sent "$http_referer" '</code>

<code>                      </code><code>'"$http_user_agent" "$http_x_forwarded_for"';</code>

<code>    </code><code>log_format zifangsky_log '$remote_addr – $remote_user [$time_local] "$request" '</code>

<code>                      </code><code>'"$http_user_agent" "$http_x_forwarded_for" '</code>

<code>                      </code><code>'"$upstream_addr" "$upstream_cache_status" "$upstream_status" "$upstream_response_time" "$cookie_jsessionid"';</code>

<code>    </code><code>log_format h5_log '$remote_addr – $remote_user [$time_local] "$request" '</code>

<code>                      </code><code>'"$http_user_agent" "$http_x_forwarded_for" "$proxy_add_x_forwarded_for"';</code>

<code>     </code><code>access_log  logs/access.log  main; </code>

<code>     </code><code>#设定请求缓冲</code>

<code>     </code><code>server_names_hash_bucket_size 256;    #增加,原为128</code>

<code>     </code><code>client_header_buffer_size 256k;       #增加,原为32k</code>

<code>     </code><code>large_client_header_buffers 4 256k;   #增加,原为32k</code>

<code>     </code><code>#size limits</code>

<code>     </code><code>client_max_body_size          50m;    #允许客户端请求的最大的单个文件字节数</code>

<code>     </code><code>client_header_timeout         3m;</code>

<code>     </code><code>client_body_timeout           3m;</code>

<code>     </code><code>send_timeout                  3m;</code>

<code>     </code><code>sendfile                      on;</code>

<code>     </code><code>tcp_nopush                    on;  #防止网络阻塞 </code>

<code>     </code><code>keepalive_timeout             120;  #长连接超时时间,单位是秒 </code>

<code>     </code><code>tcp_nodelay                   on;  #防止网络阻塞 </code>

<code>     </code><code>server_tokens                 off;    #不显示nginx版本信息</code>

<code>     </code><code>autoindex off;</code>

<code>    </code><code>limit_conn_zone $binary_remote_addr zone=perip:10m; #添加limit_zone,限制同一IP并发数</code>

<code>    </code><code>#fastcgi_intercept_errors on;        #开启错误页面跳转</code>

<code>    </code><code>add_header X-Frame-Options SAMEORIGIN;</code>

<code>    </code><code>include  gzip.conf;    #压缩配置文件</code>

<code>    </code><code>include  proxy.conf;    #proxy_cache参数配置文件</code>

<code>    </code><code>include  vhost/*.conf;    #nginx虚拟主机包含文件目录</code>

<code>    </code><code>include  mysvrhost.conf;    #后端WEB服务器列表文件</code>

这个文件是nginx的主配置文件,可以看到最后几行引入了其他的一些配置文件

iv)mysvrhost.conf:

<code>upstream h5 {</code>

<code>   </code><code>ip_hash;  #会话保持</code>

<code>   </code><code>server 192.168.100.104:9080 max_fails=1 fail_timeout=60s;</code>

<code>   </code><code>server 192.168.100.105:9080 max_fails=1 fail_timeout=60s;</code>

<code>   </code><code>server 192.168.100.106:9280 max_fails=1 fail_timeout=60s;</code>

<code>   </code><code>server 192.168.100.107:9280 max_fails=1 fail_timeout=60s;</code>

可以发现,在这个文件中就是配置好一个应用具体有哪些服务器节点。其中第一行的 ip_hash nginx的其中一种分发请求的策略了,显而易见就是根据请求的IP来决定一次请求让哪个应用服务器来处理

目前,nginx一般支持以下四种负载均衡的算法,分别是:

round-robin    循环轮询算法,同时也是nginx默认的负载均衡算法

ip-hash    根据请求的客户端IP地址来决定当前请求应该交给哪个应用服务器

least-connected    最少连接算法,即:每次都找连接数最少的服务器来转发请求

weighted    权重算法,会根据每个应用节点的权重来分发请求,权重大的会多分发一点请求,权重小的会少分发一点请求

关于这四种算法的简单例子如下:

(a)round-robin:

nginx默认的负载均衡算法

<code>http {</code>

<code>    </code><code>upstream h5_server {</code>

<code>        </code><code>server 192.168.100.104:9080;</code>

<code>        </code><code>server 192.168.100.105:9080;</code>

<code>    </code><code>}</code>

<code>    </code><code>server {</code>

<code>        </code><code>listen 80;</code>

<code>        </code><code>location / {</code>

<code>            </code><code>proxy_pass http://h5_server/h5;</code>

<code>        </code><code>}</code>

使用此种配置,nginx在接收到请求之后将按顺序把请求分发给104和105服务器,其策略是:如果第1个请求分发给了104,那么第2个请求就分发给105,第3个请求给104,后面的以此类推

(b)ip-hash:

根据请求的客户端IP地址来决定当前请求应该交给哪个应用服务器,使用ip-hash算法时nginx会确保来自同IP的请求都分发到同一服务器上。要想使用ip-hash只需要在对应的upstream中添加上ip-hash即可

<code>   </code><code>ip_hash;</code>

<code>   </code><code>server 192.168.100.104:9080;</code>

<code>   </code><code>server 192.168.100.105:9080;</code>

(c)least-connected:

每次都找连接数最少的服务器来转发请求

<code>   </code><code>least_conn;</code>

(d)weighted:

根据每个应用节点的权重来分发请求,权重大的会多分发一点请求,权重小的会少分发一点请求

<code>   </code><code>server 192.168.100.104:9080 weight=4;</code>

上面配置的意思是说,nginx在收到请求后,大概每5个请求会分4个请求给104,剩下的一个才分给105

(4)配置实际处理H5应用的配置文件h5.conf:

<code>[root@app01 conf]</code><code># cd vhost/</code>

<code>[root@app01 conf]</code><code># vim h5.conf</code>

其内容是:

<code>server {</code>

<code>        </code><code>server_name h5.zifangsky.cn;</code>

<code>        </code><code>location =/</code>

<code>         </code><code>{</code>

<code>               </code><code>proxy_redirect off;</code>

<code>               </code><code>proxy_set_header        Host $host;</code>

<code>               </code><code>proxy_set_header        X-Real-IP $remote_addr;</code>

<code>               </code><code>proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;</code>

<code>               </code><code>proxy_pass http://h5/h5;</code>

<code>               </code><code>allow  192.168.0.0/16;</code>

<code>               </code><code>deny all;</code>

<code>         </code><code>}</code>

<code>        </code><code>location /h5</code>

<code>         </code><code>location /h5/.*\.(jpg|png|gif|css|js)$</code>

<code>               </code><code>proxy_cache cache_one;</code>

<code>               </code><code>proxy_cache_valid 200 302 304 1h; #200、302、304错误状态码保存1小时</code>

<code>               </code><code>proxy_cache_valid 301 1d; #301错误状态码保存1天</code>

<code>               </code><code>proxy_cache_valid any 1m; #其余的保存1分钟</code>

<code>               </code><code>#以域名、URI、参数组合成Web缓存的Key值,存储缓存内容到二级缓存目录内</code>

<code>               </code><code>proxy_cache_key $host$uri$is_args$args;</code>

<code>               </code><code>expires 15d; #设置失效时间为30天</code>

<code>         </code><code># 查看nL缓存</code>

<code>         </code><code>location ~ /purge(/.*)</code>

<code>              </code><code># 设置只允许指定的IP或IP段才可以清除URL缓存</code>

<code>              </code><code>allow  127.0.0.1;</code>

<code>              </code><code>deny all;</code>

<code>              </code><code>proxy_cache_purge  cache_one  $host$1$is_args$args;</code>

<code>         </code><code>location /NginxStatus</code>

<code>              </code><code>allow  192.168.0.0/16;</code>

<code>              </code><code>stub_status             on;</code>

<code>              </code><code>access_log              off;</code>

<code>              </code><code>auth_basic              "NginxStatus";</code>

<code>         </code><code>access_log logs/access_h5.log  zifangsky_log;</code>

<code>         </code><code>error_page 404  /404.html;</code>

<code>         </code><code>error_page   500 502 503 504 /404.html;</code>

<code>         </code><code>location = /404.html {</code>

<code>               </code><code>proxy_pass http://h5/h5/error/404.jsp;</code>

<code>         </code><code>limit_conn perip 500;  #同一ip并发数为500,超过会返回503</code>

需要说明的是,上面的location限定了域名后面的哪些请求分发到哪些应用服务器中去处理,比如说请求的是后台路径,那么完全是可以让其他服务器节点的对应web应用来响应的,当然也可以限制访问IP。其次是上面配置的“/NginxStatus”在浏览器中访问 http://h5.zifangsky.cn/NginxStatus 时就可以查看当前nginx的连接数等nginx状态参数

(5)设置proxy_cache参数配置:

<code>[root@app01 ~]</code><code># cd /tmp</code>

<code>[root@app01 ~]</code><code># mkdir -p /tmp/proxy_temp #proxy_temp_dir与proxy_cache_dir这两个文件夹必须在同一个分区</code>

<code>[root@app01 ~]</code><code># mkdir -p /tmp/proxy_cache #proxy_cache_dir与proxy_temp_dir这两个文件夹必须在同一个分区</code>

<code>[root@app01 ~]</code><code># chown www.www -R /tmp/proxy_temp /tmp/proxy_cache #设置目录所有者</code>

<code>[root@app01 ~]</code><code># chmod -R 777 /tmp/proxy_temp /tmp/proxy_cache #设置目录权限</code>

(6)nginx优化设置基本的TCP配置 :

<code>[root@app01 ~]</code><code># vim /etc/sysctl.conf</code>

<code>net.ipv4.ip_forward = 0  </code>

<code>net.ipv4.conf.default.rp_filter = 1 </code>

<code>net.ipv4.conf.default.accept_source_route = 0 </code>

<code>kernel.sysrq = 0 </code>

<code>kernel.core_uses_pid = 1 </code>

<code>net.ipv4.tcp_syncookies = 1 </code>

<code>kernel.msgmnb = 65536 </code>

<code>kernel.msgmax = 65536 </code>

<code>kernel.shmmax = 68719476736 </code>

<code>kernel.shmall = 4294967296 </code>

<code>net.ipv4.tcp_max_tw_buckets = 6000 </code>

<code>net.ipv4.tcp_sack = 1 </code>

<code>net.ipv4.tcp_window_scaling = 1 </code>

<code>net.ipv4.tcp_rmem = 4096 87380 4194304  </code>

<code>net.ipv4.tcp_wmem = 4096 16384 4194304  </code>

<code>net.core.wmem_default = 8388608 </code>

<code>net.core.rmem_default = 8388608 </code>

<code>net.core.rmem_max = 16777216 </code>

<code>net.core.wmem_max = 16777216 </code>

<code>net.core.netdev_max_backlog = 262144 </code>

<code>#net.core.somaxconn = 262144 </code>

<code>net.ipv4.tcp_max_orphans = 3276800 </code>

<code>net.ipv4.tcp_max_syn_backlog = 262144 </code>

<code>net.ipv4.tcp_timestamps = 0 </code>

<code>net.ipv4.tcp_synack_retries = 1 </code>

<code>net.ipv4.tcp_syn_retries = 1 </code>

<code>net.ipv4.tcp_tw_recycle = 1 </code>

<code>net.ipv4.tcp_tw_reuse = 1 </code>

<code>net.ipv4.tcp_mem = 94500000 915000000 927000000  </code>

<code>net.ipv4.tcp_fin_timeout = 1 </code>

<code>net.ipv4.tcp_keepalive_time = 30 </code>

<code>#net.ipv4.ip_local_port_range = 1024 65000 #允许系统打开的端口范围</code>

使配置立即生效:

<code>[root@prx02 ~]</code><code># /sbin/sysctl -p</code>

9 测试nginx能够正常启动:

<code>[root@prx02 ~]</code><code># service nginx start</code>

如果nginx能够正常启动的话,那么到此nginx的配置和优化就已经全部完成了,下面将开始keepalived的安装和配置

(1)安装:

<code>[root@prx02 ~]</code><code># cd /usr/local/src</code>

<code>[root@prx02 ~]</code><code># tar zxvf keepalived-1.2.2.tar.gz</code>

<code>[root@prx02 ~]</code><code># cd keepalived-1.2.2</code>

<code>[root@prx02 ~]</code><code># ./configure</code>

<code>[root@prx02 ~]</code><code># make &amp;&amp; make install</code>

(2)将keepalived 以服务方式启动:

<code>[root@prx02 ~]</code><code># cp /usr/local/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/  </code>

<code>[root@prx02 ~]</code><code># cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig</code>

<code>[root@prx02 ~]</code><code># mkdir /etc/keepalived</code>

<code>[root@prx02 ~]</code><code># cp /usr/local/etc/keepalived/keepalived.conf /etc/keepalived/</code>

<code>[root@prx02 ~]</code><code># cp /usr/local/sbin/keepalived /usr/sbin</code>

<code>[root@prx02 ~]</code><code># chkconfig keepalived on</code>

(3)修改keepalived配置文件:

i)设置192.168.100.104为虚拟IP的主节点:

<code>[root@prx02 ~]</code><code># vim /etc/keepalived/keepalived.conf</code>

其内容如下:

<code>! Configuration File </code><code>for</code> <code>keepalived</code>

<code>global_defs {</code>

<code>   </code><code>notification_email {</code>

<code>   </code><code>[email protected]</code>

<code>   </code><code>}</code>

<code>   </code><code>notification_email_from [email protected]</code>

<code>   </code><code>smtp_server mail.zifangsky.cn</code>

<code>  </code><code># smtp_connect_timeout 30</code>

<code>   </code><code>router_id LVS_DEVEL</code>

<code>vrrp_script chk_http_port {</code>

<code>    </code><code>script </code><code>"/etc/keepalived/nginx_pid.sh"</code>   <code># 检查nginx状态的脚本</code>

<code>    </code><code>interval 2  </code>

<code>    </code><code>weight 3</code>

<code>vrrp_instance VI_1 {</code>

<code>    </code><code>state MASTER                 </code><code>#状态,位主,从机使用BACKUP </code>

<code>    </code><code>interface eth0                   </code><code>#绑定虚拟IP的网络接口</code>

<code>    </code><code>virtual_router_id 65          </code><code>#VRRP组名,两个节点的设置必须一样,以指明各个节点属于同一VRRP组</code>

<code>    </code><code>priority 100                      </code><code>#权重,哪权重高,那个就是主的,所以MASTER的权重必须高于BACKUP</code>

<code>    </code><code>advert_int 1                       </code><code>#组播信息发送间隔,两个节点设置必须一样</code>

<code>    </code><code>authentication {</code>

<code>        </code><code>auth_type PASS             </code><code>#主从机子通信的加密方式,两台必须一样</code>

<code>        </code><code>auth_pass www.zifangsky.cn             </code><code>#主从机子通信的加密密码,两台必须一样</code>

<code>      </code><code>mcast_src_ip 192.168.100.104   </code><code>#本机IP </code>

<code>    </code><code>virtual_ipaddress {</code>

<code>        </code><code>192.168.100.100                 </code><code>#指定虚拟IP, 两个节点设置必须一样</code>

<code>    </code><code>track_script {</code>

<code>    </code><code>chk_http_port                 </code><code>#监控脚本,chk_http_port对应的是第3行的vrrp_script chk_http_port</code>

<code>virtual_server 192.168.100.100  { </code>

<code>    </code><code>delay_loop 6 </code>

<code>    </code><code>lb_algo rr </code>

<code>    </code><code>lb_kind DR </code>

<code>    </code><code>persistence_timeout 50 </code>

<code>    </code><code>protocol TCP </code>

<code>    </code><code>real_server 192.168.100.104 80 { </code>

<code>        </code><code>weight 3 </code>

<code>        </code><code>TCP_CHECK { </code>

<code>            </code><code>connect_timeout 10 </code>

<code>            </code><code>nb_get_retry 3 </code>

<code>            </code><code>delay_before_retry 3 </code>

<code>            </code><code>connect_port 80 </code>

<code>        </code><code>} </code>

<code>    </code><code>} </code>

<code>    </code><code>real_server 192.168.100.105 80 { </code>

从上面的配置可以看出,主节点和备份节点的virtual_router_id值必须一样,同时主节点的priority值必须比备份节点的priority值要高

这里设置了一个虚拟IP:192.168.100.100

包括两个真实服务器节点,一个主节点:192.168.100.104 ,一个备份节点:192.168.100.105

同时设置了keepalived的连接端口和监听端口都是80,也就是监听nginx的80端口的服务是否挂掉,如果挂掉则将192.168.100.100这个IP自动切换到另一台服务器上去(192.168.100.100这个IP默认在192.168.100.104上)

启动keepalived,并查看虚拟IP是否已经绑定:

<code>[root@prx02 ~]</code><code># service keepalived start</code>

<code>[root@prx02 ~]</code><code># ip add list</code>

<a href="http://s2.51cto.com/wyfs02/M02/88/FE/wKiom1gEMznhF2f2AADHmzqvIzU497.png" target="_blank"></a>

如果命令结果显示有192.168.100.100这个IP的话,那说明192.168.100.104上的keepalived已经配置安装好了

ii)设置192.168.100.105为虚拟IP的备份节点:

注:192.168.100.105上的keepalived安装除了这一步的配置文件之外,其他跟192.168.100.104上的安装步骤一样,因此这里就不多说了

<code>    </code><code>state BACKUP                 </code><code>#状态,位主,从机使用BACKUP </code>

<code>    </code><code>priority 50                      </code><code>#权重,哪权重高,那个就是主的,所以MASTER的权重必须高于BACKUP</code>

<code>      </code><code>mcast_src_ip 192.168.100.105   </code><code>#本机IP </code>

注:这里只修改了3个地方,第一个地方是将“MASTER”改成了“BACKUP”,表明是备份节点;第二个地方是修改了权重,修改成了比100小的50;第三个地方是修改了本机IP

<a href="http://s3.51cto.com/wyfs02/M02/88/FB/wKioL1gEM3aDXhcsAAC4V7eu_Dk773.png" target="_blank"></a>

结果显而易见,先启动“MASTER”的keepalived然后再启动“BACKUP”的keepalived,因此“BACKUP”所在的服务器是不会绑定192.168.100.100这个虚拟IP的

(4)添加检查nginx状态的脚本,当nginx停止运行时,会自动将nginx启动(104和105都需要添加这个脚本):

<code>[root@prx02 ~]</code><code># vim /etc/keepalived/nginx_pid.sh</code>

<code>#!/bin/bash</code>

<code>#version 0.0.1</code>

<code>A=`</code><code>ps</code> <code>-C nginx --no-header |</code><code>wc</code> <code>-l`</code>

<code>if</code> <code>[ $A -</code><code>eq</code> <code>0 ];</code><code>then</code>

<code>#  /usr/sbin/nginx</code>

<code>      </code><code>service nginx start</code>

<code>              </code><code>sleep</code> <code>3</code>

<code>                </code><code>if</code> <code>[ `</code><code>ps</code> <code>-C nginx --no-header |</code><code>wc</code> <code>-l` -</code><code>eq</code> <code>0 ];</code><code>then</code>

<code>#                       killall keepalived</code>

<code>                        </code><code>service  keepalived stop</code>

<code>fi</code>

<code>[root@prx02 ~]</code><code># chmod  a+x  /etc/keepalived/nginx_pid.sh</code>

到此,keepalived的安装和配置已经全部结束

问:如何测试keepalived的虚拟IP(192.168.100.100)可以自动在两个服务器之间漂移?

很简单,只需要以下几步即可验证:

去掉104和105上的/etc/keepalived/nginx_pid.sh这个脚本的执行权限(PS:因为不去掉的话停掉nginx时因为这个脚本nginx会自动重启)

停掉104的nginx(service nginx stop)

等几秒钟之后,分别在104和105上执行:ip add list

可以发现192.168.100.100这个虚拟IP已经从104上漂移到105上去了

启动104的nginx(service nginx start)

等几秒钟之后,分别在104和105上再次执行:ip add list

可以发现192.168.100.100这个虚拟IP又从105上漂移回到104上去了

到此,“使用Nginx1.9.9+Keepalived1.2.x搭建高可用负载均衡集群”的详细安装和配置就已经结束了

本文转自 pangfc 51CTO博客,原文链接:http://blog.51cto.com/983836259/1862540,如需转载请自行联系原作者

继续阅读