企业级Nginx负载均衡与keepalived高可用实战(一)Nginx篇

一、集群简介

1.一、什么是集群

  • 简单地说,集群就是指一组(若干个)相互独立的计算机,利用高速通讯网络组成的一个较大的计算机服务系统,每一个集群节点(即集群中的每台计算机)都是运行各自服务的独立服务器。这些服务器之间能够彼此通讯,协同向用户提供应用程序,系统资源和数据,并以单一系统的模式加以管理。当用户客户机请求集群系统时,集群给用户的感受就是一个单一独立的服务器,而实际上用户请求的是一组集群服务器。
  • 打开谷歌,百度的页面,看起来好简单,也许你以为用几分钟就能够制做出类似的网页,而实际上,这个页面的背后是由成千上万台服务器集群协同工做的结果。而这么多的服务器维护和管理,以及相互协调工做也许就是同窗们将来的工做职责了。
  • 若要用一句话描述集群,即一堆服务器合做作同一件事,这些机器可能须要整个技术团队架构,设计和统一协调管理,这些机器能够分布在一个机房,也能够分布在全国全球各个地区的多个机房。

1.2 为何要使用集群

      1. 高性能
                一些国家重要的计算密集型应用(如天气预报,核试验模拟等),须要计算机有很强的运算处理能力。以全世界现有的技术,即便是大型机,其计算能力也是有限的,很难单独完成此任务。由于计算时间可能会至关长,也许几天,甚至几年或更久。所以,对于这类复杂的计算业务,便使用了计算机集群技术,集中几十上百台,甚至成千上万台计算机进行计算。

        假如你配一个LNMP环境,每次只须要服务10个并发请求,那么单台服务器必定会比多个服务器集群要快。只有当并发或总请求数量超过单台服务器的承受能力时,服务器集群才会体现出优点。php

      2. 价格有效性
        • 一般一套系统集群架构,只须要几台或数十台服务器主机便可。与动辄价值上百万元的专用超级计算机相比便宜了不少。在达到一样性能需求的条件下,采用计算机集群架构比采用同等运算能力的大型计算机具备更高的性价比。
        • 早期的淘宝,支付宝的数据库等核心系统就是使用上百万元的小型机服务器。后因使用维护成本过高以及扩展设备费用成几何级数翻倍,甚至成为扩展瓶颈,人员维护也十分困难,最终使用PC服务器集群替换之,好比,把数据库系统从小机结合Oracle数据库迁移到MySQL开源数据库结合PC服务器上来。不但成本降低了,扩展和维护也更容易了。
      3. 可伸缩性
        当服务负载,压力增加时,针对集群系统进行较简单的扩展便可知足需求,且不会下降服务质量。
                一般状况下,硬件设备若想扩展性能,不得不增长新的CPU和存储器设备,若是加不上去了,就不得不够买更高性能的服务器,就拿咱们如今的服务器来说,能够增长的设备老是有限的。若是采用集群技术,则只须要将新的单个服务器加入现有集群架构中便可,从访问的客户角度来看,系统服务不管是连续性仍是性能上都几乎没有变化,系统在不知不觉中完成了升级,加大了访问能力,轻松地实现了扩展。集群系统中的节点数目能够增加到几千乃至上万个,其伸缩性远超过单台超级计算机。
      4. 高可用性
        • 单一的计算机系统总会面临设备损毁的问题,如CPU,内存,主板,电源,硬盘等,只要一个部件坏掉,这个计算机系统就可能会宕机,没法正常提供服务。在集群系统中,尽管部分硬件和软件也仍是会发生故障,但整个系统的服务能够是7*24小时可用的。
        • 集群架构技术可使得系统在若干硬件设备故障发生时仍能够继续工做,这样就将系统的停机时间减小到了最小。集群系统在提升系统可靠性的同时,也大大减少了系统故障带来的业务损失,目前几乎100%的互联网网站都要求7*24小时提供服务。
      5. 透明性
                多个独立计算机组成的松耦合集群系统构成一个虚拟服务器。用户或客户端程序访问集群系统时,就像访问一台高性能,高可用的服务器同样,集群中一部分服务器的上线,下线不会中断整个系统服务,这对用户也是透明的。
      6. 可管理性
                整个系统可能在物理上很大,但其实容易管理,就像管理一个单一映像系统同样。在理想情况下,软硬件模块的插入能作到即插即用。
      7. 可编程性
                在集群系统上,容易开发及修改各种应用程序。

1.3 集群的常见分类

计算机集群架构按功能和结构能够分红如下几类:css

  • 负载均衡集群,简称LBC或者LB
  • 高可用性集群,简称HAC
  • 高性能计算集群,简称HPC
  • 网格计算集群

提示:
负载均衡集群和高可用性集群是互联网行业经常使用的集群架构模式,也是咱们要学习的重点。html

负载均衡集群

  • 负载均衡集群为企业提供了更为实用,性价比更高的系统架构解决方案。负载均衡集群能够把不少客户集中的访问请求负载压力尽量平均地分摊在计算机集群中处理。客户访问请求负载一般包括应用程序处理负载和网络流量负载。这样的系统很是适合使用同一组应用程序为大量用户提供服务的模式,每一个节点均可以承担必定的访问请求负载压力,而且能够实现访问请求在各节点之间动态分配,以实现负载均衡。负载均衡集群运行时,通常是经过一个或多个前端负载均衡器将客户访问请求分发到后端的一组服务器上,从而达到整个系统的高性能和高可用性。通常高可用性集群和负载均衡集群会使用相似的技术,或同时具备高可用性与负载均衡的特色。

负载均衡集群的做用为:前端

  • 分摊用户访问请求及数据流量(负载均衡)
  • 保持业务连续性,即7*24小时服务(高可用性)。
  • 应用于Web业务及数据库从库等服务器的业务

负载均衡集群典型的开源软件包括LVS,Nginx,Haproxy等。以下图所示:java

提示:
不一样的业务会有若干秒的切换时间,DB业务明显长于Web业务切换时间。android

高可用性集群

通常是指在集群中任意一个节点失效的状况下,该节点上的全部任务会自动转移到其余正常的节点上。此过程并不影响整个集群的运行。nginx

  • 当集群中的一个节点系统发生故障时,运行着的集群服务会迅速做出反应,将该系统的服务分配到集群中其余正在工做的系统上运行。考虑到计算机硬件和软件的容错性,高可用性集群的主要目的是使集群的总体服务尽量可用。若是高可用性集群中的主节点发生了故障,那么这段时间内将由备节点代替它。备节点一般是主节点的镜像。当它代替主节点时,它能够彻底接管主节点(包括IP地址及其余资源)提供服务,所以,使集群系统环境对于用户来讲是一致的,既不会影响用户的访问。
  • 高可用性集群使服务器系统的运行速度和响应速度会尽量的快。他们常常利用在多台机器上运行的冗余节点和服务来相互跟踪。若是某个节点失败,它的替补者将在几秒钟或更短期内接管它的职责。所以,对于用户而言,集群里的任意一台机器宕机,业务都不会受影响(理论状况下)。

高可用性集群的做用为:git

  • 当一台机器宕机时,另一台机器接管宕机的机器的IP资源和服务资源,提供服务。
  • 经常使用于不易实现负载均衡的应用,好比负载均衡器,主数据库,主存储对之间。

高可用性集群经常使用的开源软件包括Keepalived,Heartbeat等,其架构图以下图所示:github

高性能计算集群

  高性能计算集群也称并行计算。一般,高性能计算集群涉及为集群开发的并行应用程序,以解决复杂的科学问题(天气预报,石油勘探,核反应模拟等)。高性能计算集群对外就好像一个超级计算机,这种超级计算机内部由数十至上万个独立服务器组成,而且在公共消息传递层上进行通讯以运行并行应用程序。在生产环境中实际就是把任务切成蛋糕,而后下发到集群节点计算,计算后返回结果,而后继续领新任务计算,如此往复。web

网格计算集群 

  因为不多用到,在此略

特别提示:
在互联网网站运维中,比较经常使用的就是负载均衡集群和高可用性集群

1.4 经常使用的集群软硬件介绍及选型

企业运维中常见的集群软硬件产品

互联网企业经常使用的开源集群软件有:Nginx,LVS,Haproxy,Keepalived,heartbeat。

互联网企业经常使用的商业集群硬件有:F5,Netscaler,Radware,A10等,工做模式至关于Haproxy的工做模式。

淘宝,赶集网,新浪等公司曾使用过Netscaler负载均衡产品。集群硬件Netscaler的产品图以下图所示:

对于集群软硬件产品如何选型

下面是我对同窗们的基本选择建议,更多的建议等你们学完负载均衡内容后再细分讲解。

  • 当企业业务重要,技术力量又薄弱,而且但愿出钱购买产品及获取更好的服务时,能够选择硬件负载均衡产品,如F5,Netscaler,Radware等,此类公司多为传统的大型非互联网企业,如银行,证券,金融业及宝马,奔驰公司等
  • 对于门户网站来讲,大多会并用软件及硬件产品来分担单一产品的风险,如淘宝,腾讯,新浪等。融资了的企业会购买硬件产品,如赶集等网站。
  • 中小型互联网企业,因为起步阶段无利润可赚或者利润很低,会但愿经过使用开源免费的方案来解决问题,所以会雇佣专门的运维人员进行维护。例如:51CTO等

相比较而言,商业的负载均衡产品成本高,性能好,更稳定,缺点是不能二次开发,开源的负载均衡软件对运维人员的能力要求较高,若是运维及开发能力强,那么开源的负载均衡软件是不错的选择,目前的互联网行业更倾向于使用开源的负载均衡软件。

如何选择开源集群软件产品

  • 中小企业互联网公司网站在并发访问和总访问量不是很大的状况下,建议首选Nginx负载均衡,理由是Nginx负载均衡配置简单,使用方便,安全稳定,社区活跃,使用的人逐渐增多,成为流行趋势,另一个实现负载均衡的相似产品为Haproxy(支持L4和L7负载,一样优秀,但社区不如Nginx活跃)。
  • 若是要考虑Nginx负载均衡的高可用功能,建议首选Keepalived软件,理由是安装和配置简单,使用方便,安全稳定,与Keepalived服务相似的高可用软件还有Heartbeat(使用比较复杂,并不建议初学者使用)
  • 若是是大型企业互联网公司,负载均衡产品可使用LVS+Keepalived在前端作四层转发(通常是主备或主主,若是须要扩展可使用DNS或前端使用OSPF),后端使用Nginx或者Haproxy作7层转发(能够扩展到百台),再后面是应用服务器,若是是数据库与存储的负载均衡和高可用,建议选择LVS+Heartbeat,LVS支持TCP转发且DR模式效率很高,Heartbeat能够配合drbd,不但能够进行VIP的切换,还能够支持块设备级别的数据同步(drbd),以及资源服务的管理。

1.5 Nginx负载均衡集群介绍

搭建负载均衡服务的需求

负载均衡集群提供了一种廉价,有效,透明的方法,来扩展网络设备和服务器的负载,带宽和吞吐量,同时增强了网络数据处理能力,提升了网络的灵活性和可用性。

搭建负载均衡服务的需求以下:

(1)把单台计算机没法承受的大规模并发访问或数据流量分担到多台节点设备上,分别进行处理,减小用户等待响应的时间,提高用户体验。
(2)单个重负载的运算分担到多台节点设备上作并行处理,每一个节点设备处理结束后,将结果汇总,返回给用户,系统处理能力获得大幅度提升。
(3)7*24小时的服务保证,任意一个或多个有限后面节点设备宕机,不能影响业务。

在负载均衡集群中,同组集群的全部计算机节点都应该提供相同的服务。集群负载均衡器会截获全部对该服务的入站请求。而后将这些请求尽量地平均地分配在全部集群节点上。

Nginx负载均衡集群介绍

  1. 反向代理与负载均衡概念简介
    • 严格地说,Nginx仅仅是做为Nginx Proxy反向代理使用的,由于这个反向代理功能表现的效果是负载均衡集群的效果,因此本文称之为Nginx负载均衡。那么,反向代理和负载均衡有什么区别呢?
    • 普通负载均衡软件,例如大名鼎鼎的LVS,其实功能只是对请求数据包的转发(也可能会改写数据包),传递,其中DR模式明显的特征是从负载均衡下面的节点服务器来看,接收到的请求仍是来自访问负载均衡器的客户端的真实用户,而反向代理就不同了,反向代理接收访问用户的请求后,会代理用户从新发起请求代理下的节点服务器,最后把数据返回给客户端用户,在节点服务器看来,访问的节点服务器的客户端用户就是反向代理服务器了,而非真实的网站访问用户。
    • 一句话,LVS等的负载均衡是转发用户请求的数据包,而Nginx反向代理是接收用户的请求而后从新发起请求去请求其后面的节点。
  2. 实现Nginx负载均衡的组件说明
    实现Nginx负载均衡的组件主要有两个,以下表:

     

1.6 快速实践Nginx负载均衡环境准备

本节先带同窗们一块儿操做实战,让同窗们对Nginx负载均衡有一个初步的概念,而后再继续深刻讲解Nginx负载均衡的核心知识应用。

上图是快速实践Nginx负载均衡的逻辑架构图

在上图中,全部用户的请求统一发送到Nginx负载均衡器,而后由负载均衡器根据调度算法来请求Web01和Web02

软硬件准备

  1. 硬件准备
    准备4台VM虚拟机(有物理服务器更佳),两台作负载均衡,两台作RS,以下表:
    HOSTNAME IP 说明
    lb01 192.168.103.121 Nginx主负载均衡器
    lb02 192.168.103.122 Nginx副负载均衡器
    web01 192.168.103.123 Web01服务器
    web02 192.168.103.124 Web02服务器
  2. 软件准备
    系统:CentOS6.5 x86_64
    软件:nginx-1.10.2.tar.gz
    修改hostname方便查看:
    hostname lb01
    hostname lb02
    hostname web01
    hostname web02

二、安装Nginx

2.一、安装web服务器

安装apache(不建议)(只是用来记录操做)

在 web01 与 web02 上安装 apache 

# 安装apache
[root@web01 ~]# yum install httpd -y
[root@web01 init.d]# service httpd start
[root@web02 ~]# yum install httpd -y
[root@web02 init.d]# service httpd start

# 查看是否启动
[root@web02 ~]# lsof -i :80
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
httpd   11393   root    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11394 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11395 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11396 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11397 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11409 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11410 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11411 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11412 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11413 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)
httpd   11414 apache    4u  IPv6 168729      0t0  TCP *:http (LISTEN)

# 修改index.html页内容
[root@web01 /]# echo 192.168.103.123 >/var/www/html/index.html
[root@web02 /]# echo 192.168.103.124 >/var/www/html/index.html

安装nginx

下面将在以上4台服务器上安装Nginx,这里只给出安装的命令部分。

  1. 安装上传下载组件
    # 安装上传下载组件
    [root@lb01 /]# yum install lrzsz -y
    [root@lb02 /]# yum install lrzsz -y
    [root@web01 /]# yum install lrzsz -y
    [root@web02 /]# yum install lrzsz -y
  2. 安装pcre与gcc环境依赖
    # 安装pcre与gcc环境依赖
    # lb01
    [root@lb01 tools]# yum -y install openssl openssl-devel pcre pcre-devel
    [root@lb01 tools]# rpm -qa openssl openssl-devel pcre pcre-devel
    [root@lb01 tools]# yum install gcc -y 
    # lb02
    [root@lb02 tools]# yum -y install openssl openssl-devel pcre pcre-devel
    [root@lb02 tools]# rpm -qa openssl openssl-devel pcre pcre-devel
    [root@lb02 tools]# yum install gcc -y 
    # web01
    [root@web01 /]# yum -y install openssl openssl-devel pcre pcre-devel
    [root@web01 /]# rpm -qa openssl openssl-devel pcre pcre-devel
    [root@web01 /]# yum install gcc -y 
    # web02
    [root@web02 /]# yum -y install openssl openssl-devel pcre pcre-devel
    [root@web02 /]# rpm -qa openssl openssl-devel pcre pcre-devel
    [root@web02 /]# yum install gcc -y 
  3. 安装Nginx
    # 上传nginx文件
    [root@lb01 ~]# mkdir -p /home/oldboy/tools
    [root@lb01 ~]# cd /home/oldboy/tools
    [root@lb01 tools]# rz -y
    [root@lb01 tools]# tar xf nginx-1.6.2.tar.gz
    [root@lb01 tools]# cd nginx-1.6.2/
    # 建立nginx用户
    [root@lb01 nginx-1.6.2]# useradd -M -s /sbin/nologin nginx
    # 安装编译
    [root@lb01 nginx-1.6.2]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module && make && make install
    # 创建ln连接
    [root@lb01 nginx-1.6.2]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
    # 启动nginx
    [root@lb01 nginx-1.6.2]# nginx
    # 中止nginx
    # [root@lb01 nginx-1.6.2]# nginx -s stop
    # 查看
    # [root@lb01 nginx-1.6.2]# lsof -i :80
    
    # 上传nginx文件
    [root@lb02 ~]# mkdir -p /home/oldboy/tools
    [root@lb02 ~]# cd /home/oldboy/tools
    [root@lb02 tools]# rz -y
    [root@lb02 tools]# tar xf nginx-1.6.2.tar.gz
    [root@lb02 tools]# cd nginx-1.6.2/
    # 建立nginx用户
    [root@lb02 nginx-1.6.2]# useradd -M -s /sbin/nologin nginx
    # 安装编译
    [root@lb02 nginx-1.6.2]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module && make && make install
    # 创建ln连接
    [root@lb02 nginx-1.6.2]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
    # 启动nginx
    [root@lb02 nginx-1.6.2]# nginx
    # 中止nginx
    # [root@lb02 nginx-1.6.2]# nginx -s stop
    # 查看
    # [root@lb02 nginx-1.6.2]# lsof -i :80

2.二、配置用于测试的Web服务

本小节将在两台NginxWeb服务器的节点上操做(web01与web02):配置并查看Web服务器的配置结果。

  1. 添加本地主机名(可选)
    // web01
    # 添加本地主机名
    [root@web01 /]# cd usr/local/nginx/conf/
    [root@web01 conf]# vim /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.103.123 www.yunjisuan.com
    192.168.103.123 bbs.yunjisuan.com
    
    // web02
    # 添加本地主机名
    [root@web02 /]# cd usr/local/nginx/conf/
    [root@web02 conf]# vim /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.103.124 www.yunjisuan.com
    192.168.103.124 bbs.yunjisuan.com
  2. 安装  telnet 可选

    // web01
    # 添加本地主机名
    # 安装telnet
    [root@web01 /]# yum install telnet nmap dos2unix -y
    
    // web02
    # 安装telnet
    [root@web02 /]# yum install telnet nmap dos2unix -y
  3. 配置nginx

    // web01
    # 配置nginx
    [root@web01 nginx-1.6.2]# cd /usr/local/nginx/conf/
    # 删除nginx.conf.default中的#|^$,并写入nginx.conf
    [root@web01 conf]# egrep -v "#|^$" nginx.conf.default
    [root@web01 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
    
    // web02
    # 安装telnet
    [root@web02 nginx-1.6.2]# cd /usr/local/nginx/conf/
    # 删除nginx.conf.default中的#|^$,并写入nginx.conf
    [root@web02 conf]# egrep -v "#|^$" nginx.conf.default
    [root@web02 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
  4. 修改  nginx.conf 

    // web01
    [root@web01 conf]# vim nginx.conf
    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        server {
            listen       80;
            server_name  bbs.yunjisuan.com;
            location / {
                root   html/bbs;
                index  index.html index.htm;
            }
        }
        server {
            listen       80;
            server_name  www.yunjisuan.com;
            location / {
                root   html/www;
                index  index.html index.htm;
            }
        }
    }
    
    // web02
    [root@web02 conf]# vim nginx.conf
    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
        server {
            listen       80;
            server_name  bbs.yunjisuan.com;
            location / {
                root   html/bbs;
                index  index.html index.htm;
            }
        }
        server {
            listen       80;
            server_name  www.yunjisuan.com;
            location / {
                root   html/www;
                index  index.html index.htm;
            }
        }
    }

    这里故意将www虚拟主机放在下面,便于用后面的参数配置测试效果

  5. 检查语法错误
    // web01
    [root@web01 conf]# nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
    
    // web02
    [root@web02 conf]# nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
  6. 从新加载nginx
    // web01
    [root@web01 conf]# nginx -s reload
    [root@web01 conf]# netstat -antup | grep nginx
    tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      17429/nginx: master 
    
    // web02
    [root@web02 conf]# nginx -s reload
    [root@web02 conf]# netstat -antup | grep nginx
    tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      17429/nginx: master 
  7. 填充测试文件数据
    // web01
    [root@web01 /]# mkdir /usr/local/nginx/html/{www,bbs}
    [root@web01 /]# echo "`hostname -I `www" >> /usr/local/nginx/html/www/index.html
    [root@web01 /]# cat /usr/local/nginx/html/www/index.html
    192.168.103.123 192.168.122.1 www
    [root@web01 /]# echo "`hostname -I `bbs" >> /usr/local/nginx/html/bbs/index.html
    [root@web01 /]# cat /usr/local/nginx/html/bbs/index.html
    192.168.103.123 192.168.122.1 bbs
    
    // web02
    [root@web01 /]# mkdir /usr/local/nginx/html/{www,bbs}
    [root@web01 /]# echo "`hostname -I `www" >> /usr/local/nginx/html/www/index.html
    [root@web01 /]# cat /usr/local/nginx/html/www/index.html
    192.168.103.124 192.168.122.1 www
    [root@web01 /]# echo "`hostname -I `bbs" >> /usr/local/nginx/html/bbs/index.html
    [root@web01 /]# cat /usr/local/nginx/html/bbs/index.html
    192.168.103.124 192.168.122.1 bbs
  8. 测试
    // web01
    [root@web01 /]# curl www.yunjisuan.com
    192.168.103.123 192.168.122.1 www
    [root@web01 /]# curl bbs.yunjisuan.com
    192.168.103.123 192.168.122.1 bbs
    
    
    // web02
    [root@web02 /]# curl www.yunjisuan.com
    192.168.103.124 192.168.122.1 www
    [root@web02 /]# curl bbs.yunjisuan.com
    192.168.103.124 192.168.122.1 bbs

2.三、实现一个简单的负载均衡

配置文档:http://nginx.org/en/docs/http/ngx_http_upstream_module.html

语法:

upstream backend {
    server backend1.example.com       weight=5;
    server backend2.example.com:8080;
    server unix:/tmp/backend3;

    server backup1.example.com:8080   backup;
    server backup2.example.com:8080   backup;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

测试:(本操做基于lb01和lb02)

  1. 添加本地主机名(可选)
    添加本地域名
    [root@lb01 conf]# vim /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.103.121 www.yunjisuan.com
  2. 安装 telnet (可选)

    # 安装telnet
    [root@lb01 conf]# yum install telnet nmap dos2unix -y
  3. 配置nginx
    # 配置nginx
    [root@lb01 nginx-1.6.2]# cd /usr/local/nginx/conf/
    # 删除nginx.conf.default中的#|^$,并写入nginx.conf
    [root@lb01 conf]# egrep -v "#|^$" nginx.conf.default
    [root@lb01 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
  4. 建立配置信息(notepad++中)
    upstream webpools {
        server 192.168.103.123       weight=5;
        server 192.168.103.124       weight=5;
    
        server 192.168.103.125  weight=5   backup;
    }
    
    server {
        location / {
            proxy_pass http://webpools;
        }
    }
  5. 修改 nginx.conf 
    [root@lb01 conf]# vim nginx.conf
    
    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
    
        upstream webpools { server 192.168.103.123:80       weight=5;
            server 192.168.103.124:80       weight=5;
    
            server 192.168.103.125:80  weight=5 backup; }
    
        server {
            listen       80;
            server_name  www.yunjisuan.com;
            location / {
                root   html;
                index  index.html index.htm;
     proxy_pass http://webpools;
            }
        }
    }

    注意:upstream名称不能包含下划线,不然会报以下错误

    <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
    <html><head>
    <title>400 Bad Request</title>
    </head><body>
    <h1>Bad Request</h1>
    <p>Your browser sent a request that this server could not understand.<br />
    </p>
    <p>Additionally, a 400 Bad Request
    error was encountered while trying to use an ErrorDocument to handle the request.</p>
    </body></html>
    View Code
  6. 检查语法错误
    [root@lb01 conf]# nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
  7. 从新加载nginx
    [root@lb01 conf]# nginx -s reload
  8. 测试

     

    [root@lb01 /]# curl www.yunjisuan.com
    192.168.103.123 192.168.122.1 bbs
    [root@lb01 /]# curl www.yunjisuan.com
    192.168.103.124 192.168.122.1 bbs
    [root@lb01 /]# curl www.yunjisuan.com
    192.168.103.123 192.168.122.1 bbs
    [root@lb01 /]# curl www.yunjisuan.com
    192.168.103.124 192.168.122.1 bbs

     

三、Nginx负载均衡核心组件介绍

3.0、Nginx主配置文件nginx.conf

  Nginx主配置文件nginx.conf是一个纯文本类型的文件(其余配置文件大多也是如此),它位于Nginx安装目录下的conf目录,整个配置文件是以区块的形式组织的。通常,每一个区块以一个大括号“{}”来表示,区块能够分为几个层次,整个配置文件中Main区位于最上层,在Main区下面能够有Events区,HTTP区等层级,在HTTP区中又包含有一个或多个Server区,每一个Server区中又可有一个或多个location区,整个Nginx配置文件nginx.conf的主体框架为:

[root@chensiqi conf]# egrep -v "#|^$" nginx.conf #去掉包含#号和空行的内容
worker_processes  1; #worker进程的数量
error_log  logs/error.log;  #错误日志(默认没开)
pid        logs/nginx.pid;  #进程号(默认没开)
events {    #事件区块开始
    worker_connections  1024;   #每一个worker进程支持的最大链接数
}           #事件区块结束
http {      #http区块开始
    include       mime.types;   #Nginx支持的媒体类型库文件包含
    default_type  application/octet-stream; #默认的媒体类型
    sendfile        on;     #开启高效传输模式
    keepalive_timeout  65;  #链接超时。
    server {      #网站配置区域(第一个server第一个虚拟主机站点)
        listen       80;    #提供服务的端口,默认80
        server_name  www.chensiqi.org; #提供服务的域名主机名
        location / {    #第一个Location区块开始
            root   html;  #站点的根目录(相对于nginx安装路径)
            index  index.html index.htm; #默认的首页文件,多个用空格分开
        }
        error_page 500 502 503 504  /50x.html;  #出现对应的http状态码时,使用50x.html回应客户
        location = /50x.html {  #Location区块开始,访问50x.html
            root   html;     #指定对应的站点目录为html
        }
    }
    server {      #网站配置区域(第二个server第二个虚拟主机站点)
        listen       80;    #提供服务的端口,默认80
        server_name  bbs.chensiqi.org; #提供服务的域名主机名
        location / {    #服务区块
            root   html;  #相对路径(nginx安装路径)
            index  index.html index.htm;
        }
        location = /50x.html { #发生错误访问的页面
            root   html;
        }
    }
}

整个nginx配置文件的核心框架以下:

worker_processes 1;
events {
    
    worker_connections 1024;

}
http {
    include mime.types;
    server {
        listen  80;
        server_name localhost;
        location / {
            root  html;
            index  index.html index.htm;
        }
    }
}

Nginx其余配置文件

  • 若是是配合动态服务(例如PHP服务),Nginx软件还会用到扩展的fastcgi相关配置文件,这个配置是经过在Nginx.conf主配置文件中嵌入include命令来实现的,不过默认状况是注释状态,不会生效。

  • fastcgi.conf配置文件的初始内容以下:

    [root@localhost conf]# cat fastcgi.conf
    
    fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_param  QUERY_STRING       $query_string;
    fastcgi_param  REQUEST_METHOD     $request_method;
    fastcgi_param  CONTENT_TYPE       $content_type;
    fastcgi_param  CONTENT_LENGTH     $content_length;
    
    fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
    fastcgi_param  REQUEST_URI        $request_uri;
    fastcgi_param  DOCUMENT_URI       $document_uri;
    fastcgi_param  DOCUMENT_ROOT      $document_root;
    fastcgi_param  SERVER_PROTOCOL    $server_protocol;
    fastcgi_param  REQUEST_SCHEME     $scheme;
    fastcgi_param  HTTPS              $https if_not_empty;
    
    fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
    fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
    
    fastcgi_param  REMOTE_ADDR        $remote_addr;
    fastcgi_param  REMOTE_PORT        $remote_port;
    fastcgi_param  SERVER_ADDR        $server_addr;
    fastcgi_param  SERVER_PORT        $server_port;
    fastcgi_param  SERVER_NAME        $server_name;
    
    # PHP only, required if PHP was built with --enable-force-cgi-redirect
    fastcgi_param  REDIRECT_STATUS    200;
  • fastcgi_params 默认配置文件的内容以下:
    [root@localhost conf]# cat fastcgi_params
    
    fastcgi_param  QUERY_STRING       $query_string;
    fastcgi_param  REQUEST_METHOD     $request_method;
    fastcgi_param  CONTENT_TYPE       $content_type;
    fastcgi_param  CONTENT_LENGTH     $content_length;
    
    fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
    fastcgi_param  REQUEST_URI        $request_uri;
    fastcgi_param  DOCUMENT_URI       $document_uri;
    fastcgi_param  DOCUMENT_ROOT      $document_root;
    fastcgi_param  SERVER_PROTOCOL    $server_protocol;
    fastcgi_param  REQUEST_SCHEME     $scheme;
    fastcgi_param  HTTPS              $https if_not_empty;
    
    fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
    fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;
    
    fastcgi_param  REMOTE_ADDR        $remote_addr;
    fastcgi_param  REMOTE_PORT        $remote_port;
    fastcgi_param  SERVER_ADDR        $server_addr;
    fastcgi_param  SERVER_PORT        $server_port;
    fastcgi_param  SERVER_NAME        $server_name;
    
    # PHP only, required if PHP was built with --enable-force-cgi-redirect
    fastcgi_param  REDIRECT_STATUS    200;

    上述未作注释的目录或文件是比较少用的,有关动态扩展配置后文讲到PHP服务时再来说解。

Nginx的功能模块说明

增长错误日志

error_log file level;

常见的日志级别【debug|info|notice|warn|error|crit|alert|emerg】
生产场景通常是warn|error|crit这三个级别之一,注意不要配置info等较低级别,会带来巨大磁盘I/O消耗。
error_log的默认值为:
# default:error_log logs/error.log error;

worker_processes  1;
error_log logs/error.log;    #很是简单,通常增长此行便可
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    include extra/www.conf;
    include extra/mail.conf;
    include extra/status.conf;

}

Nginx访问日志轮询切割

默认状况下Nginx会把全部的访问日志生成到一个指定的访问日志文件access.log里,但这样一来,时间长了就会致使日志个头很大,不利于日志的分析和处理,所以,有必要对Nginx日志,按天或按小时进行切割,使其分红不一样的文件保存。

[root@localhost nginx]# cat /server/scripts/cut_nginx_log.sh 
#!/bin/bash
#日志切割脚本可挂定时任务,天天00点整执行

Dateformat=`date +%Y%m%d`
Basedir="/usr/local/nginx"
Nginxlogdir="$Basedir/logs"
Logname="access"

[ -d $Nginxlogdir ] && cd $Nginxlogdir || exit 1
[ -f ${Logname}.log ] || exit 1
/bin/mv ${Logname}.log ${Dateformat}_${Logname}.log
$Basedir/sbin/nginx -s reload

[root@localhost nginx]# cat >>/var/spool/cron/root << KOF
#cut nginx access log by Mr.chen
00 00 * * * /bin/bash /server/scripts/cut_nginx_log.sh >/dev/null 2>&1

Nginx location

语法为:

location [ = | ~ | ~* | ^~ ] uri {

  ...

}

上图是对location语法的说明。上述语法中的URI部分是关键,这个URI能够是普通的字符串地址路径,或者是正则表达式,匹配成功则执行后面大括号里的相关命令。正则表达式的前面还能够有“~”或“~*”等特殊字符。

 

 

匹配这两种特殊字符“~”或“~*”的区别为:“~”用于区分大小写(大小写敏感)的匹配;“~*”用于不区分大小写的匹配。还能够用逻辑操做符“!”对上面的匹配取反,即“!~”和“!~*”。此外,“^~”的做用是先进行字符串的前缀匹配(必须之后边的字符串开头),若是能匹配到,就再也不进行其余location的正则匹配了。

location匹配示例

[root@localhost nginx]# cat /usr/local/nginx/conf/extra/www.conf 
    server {
        listen       80;
        server_name  www.yunjisuan.com;
       root    /var/www/html/wwwcom;
        location / {
          return 401;     
        }
       location = / {
          return 402;
       }
       location = /images/ {
          return 501;
       }
       location /documents/ {
          return 403;
       }
       location ^~ /images/ {
          return 404;
       }
       location ~* \.(gif|jpg|jpeg)$ {
          return 500;
       }
    }

匹配结果

[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com
402        #匹配了=的状况
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/
402         #匹配了=的状况
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/xxxx
401         #匹配不到默认匹配 /的状况
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/documents/
403         #匹配字符串
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/images/
501         #优先匹配=的状况
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/images/1.jpg
404         #匹配
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/documents/images/1.jpg
500         #匹配~*的状况

从多个location的配置匹配能够看出匹配的优先顺序

顺序 匹配标识的location 匹配说明
1 " location = / { " 精确匹配
2 " location ^~ /images/ { " 先进行字符串的前缀匹配,若是匹配到就不作正则匹配检查
3 " loction ~* \.(gif | jpg | jpeg)$ { " 正则匹配,*为不区分大小写
4 " location /documents/ { " 匹配常规字符串,模糊匹配,若是有正则检查,正则优先
5 " location / { " 全部location都不能匹配后的默认匹配原则

Nginx rewrite

和Apache等Web服务软件同样,Nginx rewrite的主要功能也是实现URL地址重写。Nginx的rewrite规则须要PCRE软件的支持,即经过Perl兼容正则表达式语法进行规则匹配。默认参数编译时,Nginx就会安装支持rewrite的模块,可是,也必需要有PCRE软件的支持。

  • rewrite指令语法
    指令语法:rewrite regex replacement 【flag】;
    默认值:none
    应用位置:server,location,if
    rewrite是实现URL重写的关键指令,根据regex(正则表达式)部分的内容,重定向到replacement部分,结尾是flag标记。下面是一个简单的URL rewrite跳转例子:
    rewrite ^/(.*) http://www.baidu.com/$1  permanent;

    在上述指令中,rewrite为固定关键字,表示开启一条rewrite匹配规则,regex部分是^(.*),这是一个正则表达式,表示匹配全部,匹配成功后跳转到http://www.baidu.com/$1 。这里的$1是取前面regex部分括号里的内容,结尾的permanent;是永久301重定向标记,即跳转到后面的http://www.baidu.com/$1 地址上。

  • regex经常使用正则表达式说明
  • rewrite指令的最后一项参数flag标记的说明



在以上的flag标记中,last和break用来实现URL重写,浏览器地址栏的URL地址不变,但在服务器端访问的程序及路径发生了变化。redirect和permanent用来实现URL跳转,浏览器地址栏会显示跳转后的URL地址。

last和break标记的实现功能相似,但两者之间有细微的差异,使用alias指令时必须用last标记,使用proxy_pass指令时要使用break标记。last标记在本条rewrite规则执行完毕后,会对其所在的server{...}标签从新发起请求,而break标记则会在本条规则匹配完成后,终止匹配,再也不匹配后面的规则。

Nginx rewrite 的企业应用场景

  • 能够调整用户浏览的URL,使其看起来更规范,合乎开发及产品人员的需求。
  • 为了让搜索引擎收录网站内容,并让用户体验更好,企业会将动态URL地址假装成静态地址提供服务
  • 网站换新域名后,让旧域名的访问跳转到新的域名上,例如:让京东的360buy换成了jd.com
  • 根据特殊变量,目录,客户端的信息进行URL跳转等。

Nginx rewrite 301 跳转

以往咱们是经过别名方式实现yunjisuan.com和www.yunjisuan.com访问同一个地址的,事实上,除了这个方式外,还可使用nginx rewrite 301 跳转的方式来实现。实现的配置以下:

[root@localhost nginx]# cat conf/extra/www.conf 
#www virtualhost by Mr.chen   
    server {
        listen       80;
        server_name  www.yunjisuan.com;
       root    /var/www/html/wwwcom;
        location / {
        index index.html index.htm;
        }
#   location = / {
#       return 402;
#   }
    location = /images/ {
        return 501;
    }
    location /documents/ {
        return 403;
    }
    location ^~ /images/ {
        return 404;
    }
    location ~* \.(gif|jpg|jpeg)$ {
        return 500;
    }
    
    }

    server{
        listen  80;
        server_name yunjisuan.com;
 rewrite ^/(.*)  http://www.yunjisuan.com/$1 permanent;
        #当用户访问yunjisuan.com及下面的任意内容时,都会经过这条rewrite跳转到www.yunjisuan.com对应的地址
    }

 

3.一、Nginx upstream模块

upstream模块介绍

  • Nginx的负载均衡功能依赖于 ngx_http_upsteam_module 模块,所支持的代理方式包括 proxy_passfastcgi_passuwsgi_passscgi_passmemcached_pass, and grpc_pass directives.等,新版Nginx软件支持的方式有所增长。本文主要讲解proxy_pass代理方式。
  • ngx_http_upstream_module模块容许Nginx定义一组或多组节点服务器组,使用时能够经过proxy_pass代理方式把网站的请求发送到事先定义好的对应Upstream组的名字上,具体写法为“proxy_pass http:// www_server_pools”,其中www_server_pools就是一个Upstream节点服务器组名字。
  • ngx_http_upstream_module模块官方地址为:http://nginx.org/en/docs/http/ngx_http_upstream_module.html

upstream模块语法

upstream模块的语法至关简单,这里直接上范例给同窗们讲。

范例1:基本的upstream配置案例

upstream www_server_pools {

    # upstream是关键字必须有,后面的www_server_pools为一个Upstream集群组的名字,能够本身起名,调用时就用这个名字
    server 192.168.103.123:80 weight=5;
    server 192.168.103.124:80 weight=10;
    server 192.168.103.125:80 weight=15;    
#server关键字是固定的,后面能够接域名(门户会用)或IP。若是不指定端口,默认是80端口。weight表明权重,数值越大被分配的请求越多,结尾有分号,别忘了 }

范例2:较完整的upstream配置案例

upstream blog_server_pool {

    server 192.168.103.123;   #这行标签和下行是等价的
    server 192.168.103.124:80 weight=1 max_fails=1 fail_timeout=10s;       #这行标签和上一行是等价的,此行多余的部分就是默认配置,不写也能够。

    server 192.168.103.125:80 weight=1 max_fails=2 fail_timeout=20s backup;

    #   server最后面能够加不少参数,具体参数做用看下文的表格

}

范例3:使用域名及socket的upstream配置案例

upstream backend {

    server backend1.example.com weight=5;
    server backend2.example.com:8080;   #域名加端口。转发到后端的指定端口上
    server unix:/tmp/backend3;  #指定socket文件

    #提示:server后面若是接域名,须要内网有DNS服务器或者在负载均衡器的hosts文件作域名解析。

    server 192.168.103.123;
    server 192.168.103.124:8080;
    server backup1.example.com:8080 backup;

    #备份服务器,等上面指定的服务器都不可访问的时候会启动,backup的用法和Haproxy中用法同样

    server backup2.example.com:8080 backup;

}

若是是两台Web服务器作高可用,常规方案就须要keepalived配合,那么这里使用Nginx的backup参数经过负载均衡功能就能够实现Web服务器集群了,对于企业应用来讲,能作集群就不作高可用。

upstream模块相关说明

upstream模块的内容应放于nginx.conf配置的http{}标签内,其默认调度节点算法是wrr(weighted round-robin,即权重轮询)

下图为upstream模块内部server标签部分参数说明

提示:
以上参数与专业的Haproxy参数很相似,但不如Haproxy的参数易懂。

来看个示例,以下:

upstream backend {

server backend1.example.com weight=5; #若是就是单个Server,不必设置权重
server 127.0.0.1:8080 max_fail=5 fail_timeout=10s;
#当检测次数等于5的时候,5次连续检测失败后,间隔10s再从新检测。
server unix:/tmp/backend3;
server backup1.example.com:8080 backup; #热备机器设置

}

须要特别说明的是,若是是Nginx代理Cache服务,可能须要使用hash算法,此时若宕机,可经过设置down参数确保客户端用户按照当前的hash算法访问,这一点很重要。示例配置以下:

upstream backend {

ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;

}

注意:ip_hash不能与backup共同使用

下面是Haproxy负载均衡器server标签的配置示例。

#开启对后端服务器的健康检测,经过GET /test/index.php来判断后端服务器的健康状况
server php_server_1 192.168.103.123:80 cookie 1 check inter 2000 rise 3 fall 3 weight 2
server php_server_2 192.168.103.124:80 cookie 2 check inter 2000 rise 3 fall 3 weight 1
server php_server_bak 192.168.103.125:80 cookie 3 check inter 1500 rise 3 fall 3 backup

上述命令的说明以下:

  • weight:调节服务器的请求分配权重。
  • check:开启对该服务器健康检查。
  • inter:设置连续两次的健康检查间隔时间,单位毫秒,默认值2000
  • rise:指定多少次连续成功的健康检查后,便可认定该服务器处于可用状态。
  • fall:指定多少次不成功的健康检查后,即认为服务器为宕机状态,默认值3.
  • maxconn:指定可被发送到该服务器的最大并发链接数。

upstream模块调度算法

调度算法通常分为两类:

  • 第一类为静态调度算法,即负载均衡器根据自身设定的规则进行分配,不须要考虑后端节点服务器的状况,例如:rr,wrr,ip_hash等都属于静态调度算法。
  • 第二类为动态调度算法,即负载均衡器会根据后端节点的当前状态来决定是否分发请求,例如:链接数少的优先得到请求,响应时间短的优先得到请求。例如:least_conn,fair等都属于动态调度算法。

下面介绍一下常见的调度算法

  • rr轮询(默认调度算法,静态调度算法)
      按客户端请求顺序把客户端的请求逐一分配到不一样的后端节点服务器,这至关于LVS中的rr算法,若是后端节点服务器宕机(默认状况下Nginx只检测80端口),宕机的服务器会被自动从节点服务器池中剔除,以使客户端的用户访问不受影响。新的请求会分配给正常的服务器。
  • wrr(权重轮询,静态调度算法)
      在rr轮询算法的基础上加上权重,即为权重轮询算法,当使用该算法时,权重和用户访问成正比,权重值越大,被转发的请求也就越多。能够根据服务器的配置和性能指定权重值大小,有效解决新旧服务器性能不均带来的请求分配问题。
  • ip_hash(静态调度算法)(会话保持)
      每一个请求按客户端IP的hash结果分配,当新的请求到达时,先将其客户端IP经过哈希算法哈希出一个值,在随后的客户端请求中,客户IP的哈希值只要相同,就会被分配至同一台服务器,该调度算法能够解决动态网页的session共享问题,但有时会致使请求分配不均,即没法保证1:1的负载均衡,由于在国内大多数公司都是NAT上网模式,多个客户端会对应一个外部IP,因此,这些客户端都会被分配到同一节点服务器,从而致使请求分配不均。LVS负载均衡的-p参数,Keepalived配置里的persistence_timeout 50参数都相似这个Nginx里的ip_hash参数,其功能均可以解决动态网页的session共享问题。
    咱们来看一个示例,以下:
    upstream yunjisuan_lb{
    
        ip_hash;
        server 192.168.0.223:80;
        server 192.168.0.224:8080;
    
    }
    
    upstream backend{
    
        ip_hash;
        server backend1.example.com;
        server backend2.example.com;
        server backend3.example.com down;
        server backend4.example.com;
    
    }

    注意:
    当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能有weight和backup,即便有也不会生效。

  • fair(动态调度算法)
            此算法会根据后端节点服务器的响应时间来分配请求,响应时间短的优先分配。这是更加智能的调度算法。此种算法能够根据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx自己不支持fair调度算法,若是须要使用这种调度算法,必须下载Nginx相关模块upstream_fair
    示例以下:
    upstream yunjisuan_lb{
    
        server 192.168.103.123;
        server 192.168.103.124;
        fair;
    
    }
  • least_conn
          least_conn算法会根据后端节点的链接数来决定分配状况,哪一个机器链接数少就分发。
    除了上面介绍的这些算法外,还有一些第三方调度算法,例如:url_hash,一致性hash算法等,介绍以下。
  • url_hash算法(web缓存节点)
      与ip_hash相似,这里是根据访问URL的hash结果来分配请求的,让每一个URL定向到同一个后端服务器,后端服务器为缓存服务器时效果显著。在upstream中加入hash语句,server语句中不能写入weight等其余的参数,hash_method使用的是hash算法。url_hash按访问URL的hash结果来分配请求,使每一个URL定向到同一个后端服务器,能够进一步提升后端缓存服务器的效率命令率。Nginx自己是不支持url_hash的,若是须要使用这种调度算法,必须安装Nginx的hash模块软件包
    url_hash(web缓存节点)和ip_hash(会话保持)相似。示例配置以下:
    upstream yunjisuan_lb {
    
        server squid1:3128;
        server squid2:3128;
        hash $request_uri;
        hash_method crc32;
    
    }
  • 一致性hash算法
      一致性hash算法通常用于代理后端业务为缓存服务(如Squid,Memcached)的场景,经过将用户请求的URI或者指定字符串进行计算,而后调度到后端的服务器上,此后任何用户查找同一个URI或者指定字符串都会被调度到这一台服务器上,所以后端的每一个节点缓存的内容都是不一样的,一致性hash算法能够解决后端某个或几个节点宕机后,缓存的数据动荡最小,一致性hash算法知识比较复杂,详细内容能够参考百度上的相关资料,这里仅仅给出配置示例:
    http {
        upstream test {
    
            consistent_hash $request_uri;
            server 127.0.0.1:9001 id=1001 weight=3;
            server 127.0.0.1:9002 id=1002 weight=10;
            server 127.0.0.1:9003 id=1003 weight=20;
    
        }
    }

    虽然Nginx自己不支持一致性hash算法,但Nginx得分支Tengine支持。详细可参考http://tengine.taobao.org/document_cn/http_upstream_consistent_hash_cn.html

3.二、http_proxy_module模块

proxy_pass指令介绍

  proxy_pass指令属于 ngx_http_proxy_module 模块,此模块能够将请求转发到另外一台服务器,在实际的反向代理工做中,会经过location功能匹配指定的URI,而后把接收到的符合匹配URI的请求经过proxy_pass抛给定义好的upstream节点池。该指令官方地址1见:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

下面proxy_pass的使用案例:

  • 将匹配URI为name的请求抛给http://127.0.0.1/remote/.
    location /name/ {
    
        proxy_pass http://127.0.0.1/remote/;
    
    }
  • 将匹配URI为some/path的请求抛给http://127.0.0.1
    location /some/path/ {
    
        proxy_pass http://127.0.0.1;
    
    }
  • 将匹配URI为name的请求应用指定的rewrite规则,而后抛给http://127.0.0.1
    location /name/ {
    
        rewrite /name/( [^/]+ )  /username=$1 break;
        proxy_pass http://127.0.0.1;
    
    }

http proxy模块参数

Nginx的代理功能是经过http proxy模块来实现的。默认在安装Nginx时已经安装了http proxy模块,所以可直接使用http proxy模块。下面详细解释模块1中每一个选项表明的含义,见下表:

3.2.一、Nginx负载均衡配置实战(上接2.3节)

主机名 IP地址 角色说明
lb01 192.168.103.121 nginx主负载均衡
lb02 192.168.103.122 nginx从负载均衡
Web01 192.168.103.123 nginx web01服务器
Web02 192.168.103.124 nginx web02服务器

 

查看lb01的配置文件以下:

// lb01
[root@lb01 /]# cat /usr/local/nginx/conf/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    
    upstream webpools {
        #默认调度算法wrr,即权重轮询算法
        #虽然定义的www服务器池可是这个服务器池也能够做为BBS等业务的服务器池。由于节点服务器的虚拟主机都是根据访问的主机头字段区分的。
        
        #若是就是单个Server,不必设置权重
        server 192.168.103.123:80       weight=5 max_fails=1 fail_timeout=60s; #当检测次数等于1的时候,1次连续检测失败后,间隔60s再从新检测。
        server 192.168.103.124:80       weight=5;

        server 192.168.103.124:80  weight=5   backup; #热备机器设置
    }

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
        proxy_pass http://webpools; #经过proxy_pass功能把用过户的请求交给上面反向代理upstream定义的webpools服务器池处理。
        }
    }
}

如今配置hosts解析到代理服务器lb01上,从新加载服务,访问测试

[root@lb01 /]# tail -2 /etc/hosts
192.168.103.121 www.yunjisuan.com
192.168.103.121 bbs.yunjisuan.com
[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload
[root@lb01 /]# tail -2 /etc/hosts
192.168.103.121 www.yunjisuan.com
192.168.103.121 bbs.yunjisuan.com
[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload
[root@lb01 /]# curl www.yunjisuan.com
192.168.103.123 192.168.122.1 bbs
[root@lb01 /]# curl www.yunjisuan.com
192.168.103.124 192.168.122.1 bbs

从测试结果能够看出,已经实现了反向代理,负载均衡功能,可是有一个特殊问题,出来的结果并非带有www的字符串,而是bbs的字符串,根据访问结果,咱们推测是访问了Web节点下bbs的虚拟主机,明明代理的是www虚拟主机,为何结果是访问了后端的bbs虚拟主机了呢?问题又该如何解决?请同窗们继续往下看。

反向代理多虚拟主机节点服务器企业案例

上一节代理的结果不对,究其缘由是当用户访问域名时确实是携带了www.yunjisuan.com主机头请求Nginx反向代理服务器,可是反向代理向下面节点从新发起请求时,默认并无在请求头里告诉节点服务器要找哪台虚拟主机,因此,Web节点服务器接收到请求后发现没有主机头信息,所以,就把节点服务器的第一个虚拟主机发给了反向代理了(节点上第一个虚拟主机放置的是故意这样放置的bbs)。解决这个问题的方法,就是当反向代理向后从新发起请求时,要携带主机头信息,以明确告诉节点服务器要找哪一个虚拟主机。具体的配置很简单,就是在Nginx代理www服务虚拟主机配置里增长以下一行配置便可:

proxy_set_header host $host;

在代理向后端服务器发送的http请求头中加入host字段信息后,若后端服务器配置有多个虚拟主机,它就能够识别代理的是哪一个虚拟主机。这是节点服务器多虚拟主机时的关键配置。整个Nginx代理配置为:

// lb01
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream webpools {
        #若是就是单个Server,不必设置权重
        server 192.168.103.123:80       weight=5 max_fails=1 fail_timeout=60s; #当检测次数等于1的时候,1次连续检测失败后,间隔60s再从新检测。
        server 192.168.103.124:80       weight=5;

        server 192.168.103.124:80  weight=5   backup; #热备机器设置
    }

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://webpools;
            proxy_set_header host $host;    #在代理向后端服务器发送的http请求头中加入host字段信息,用于当后端服务器配置有多个虚拟主机时,能够识别代理的是哪一个虚拟主机。这是节点服务器多虚拟主机时的关键配置。
        }
    }
}

此时,再从新加载Nginx服务,并用curl测试检查,结果以下:

[root@lb01 /]# curl www.yunjisuan.com
192.168.103.123 192.168.122.1 www
[root@lb01 /]# curl www.yunjisuan.com
192.168.103.124 192.168.122.1 www
[root@lb01 /]# curl bbs.yunjisuan.com
192.168.103.123 192.168.122.1 bbs
[root@lb01 /]# curl bbs.yunjisuan.com
192.168.103.124 192.168.122.1 bbs

能够看到此次访问的结果和访问的域名就彻底对应上了,这样代理多虚拟主机的节点服务器就不会出问题了

通过反向代理后的节点服务器记录用户IP企业案例

修改 nginx.config 记录日志

// web01
[root@web01 conf]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"';
    server {
        listen       80;
        server_name  bbs.yunjisuan.com;
        location / {
            root   html/bbs;
            index  index.html index.htm;
        }
        access_log logs/access_bbs.log main;
    }
        server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html/www;
            index  index.html index.htm;
        }
        access_log logs/access_www.log main;
    }
}


// web02
[root@web02 conf]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"';
    server {
        listen       80;
        server_name  bbs.yunjisuan.com;
        location / {
            root   html/bbs;
            index  index.html index.htm;
        }
        access_log logs/access_bbs.log main;
    }
        server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html/www;
            index  index.html index.htm;
        }
        access_log logs/access_www.log main;
    }
}

完成了反向代理WWW服务后,天然很开心,可是,不久后你用其余客户端做为客户端测试时,就会发现一个问题,节点服务器对应的WWW虚拟主机的访问日志的第一个字段记录的并非客户端的IP,而是反向代理服务器的IP,最后一个字段也是“-”!

例如:使用任意windows客户端计算机( 192.168.103.204 ),访问已经解析好代理IP的www.yunjisuan.com后,去节点服务器www服务日志查看,就会发现以下日志:

[root@web02 logs]# tail -2 /usr/local/nginx/logs/access_www.log
192.168.103.121--[29/Aug/2019:17:29:23 +0800]"GET / HTTP/1.0"200 34 "-""curl/7.29.0""-"
192.168.103.121--[29/Aug/2019:17:29:33 +0800]"GET / HTTP/1.0"200 34 "-""curl/7.29.0""-"

Web01节点服务器对应的WWW虚拟主机的访问日志的第一个字段记录的并非客户端的IP而是反向代理服务器自己的IP(192.168.103.121),最后一个字段也是一个“-”,那么如何解决这个问题?其实很简单,一样是增长以下一行参数:

proxy_set_header X-Forwarded-For $remote_addr;
#这是反向代理时,节点服务器获取用户真实IP的必要功能配置

解决上述问题的整个Nginx代理配置为:

//lb01
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream webpools {
        #若是就是单个Server,不必设置权重
        server 192.168.103.123:80       weight=5 max_fails=1 fail_timeout=60s; #当检测次数等于1的时候,1次连续检测失败后,间隔60s再从新检测。
        server 192.168.103.124:80       weight=5;

        server 192.168.103.124:80  weight=5   backup; #热备机器设置
    }

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://webpools;
            proxy_set_header host $host;    #在代理向后端服务器发送的http请求头中加入host字段信息,用于当后端服务器配置有多个虚拟主机时,能够识别代理的是哪一个虚拟主机。这是节点服务器多虚拟主机时的关键配置。
            proxy_set_header X-Forwarded-For $remote_addr; #在代理向后端服务器发送的http请求头中加入X-Forwarded-For字段信息,用于后端服务器程序,日志等接收记录真实用户的IP,而不是代理服务器的IP
        }
    }
}

从新加载Nginx反向代理服务:

[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload

特别注意,虽然反向代理已经配好了,可是节点服务器须要的访问日志若是要记录用户的真实IP,还必须进行日志格式配置,这样才能把代理传过来的X-Forwarded-For头信息记录下来,具体配置为:

// web01
[root@web01 /]# vim usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"';
    #就是这里的“$http_x_forwarded_for”参数,若是但愿在第一行显示,能够替换掉第一行的$remote_addr变量。
    server {
        listen       80;
        server_name  bbs.yunjisuan.com;
        location / {
            root   html/bbs;
            index  index.html index.htm;
        }
        access_log logs/access_bbs.log main;
    }
        server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html/www;
            index  index.html index.htm;
        }
        access_log logs/access_www.log main;
    }
}



// web02
[root@web02 /]# vim usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"';
    #就是这里的“$http_x_forwarded_for”参数,若是但愿在第一行显示,能够替换掉第一行的$remote_addr变量。
    server {
        listen       80;
        server_name  bbs.yunjisuan.com;
        location / {
            root   html/bbs;
            index  index.html index.htm;
        }
        access_log logs/access_bbs.log main;
    }
        server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html/www;
            index  index.html index.htm;
        }
        access_log logs/access_www.log main;
    }
}
View Code

完成Web01,Web02节点服务器的日志配置后,就能够检查了,注意,不要用curl从反向代理上检查,最好换一个客户端检查,这样才能看到效果。这里使用Windows客户端计算机(IP为192.168.103.204)访问已经解析好代理IP的www.yunjisuan.com,以下图所示:

// web01
[root@web01 /]# tail -2 /usr/local/nginx/logs/access_bbs.log 
192.168.103.121--[29/Aug/2019:18:02:38 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"
192.168.103.121--[29/Aug/2019:18:02:42 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"



// web02
[root@web02 /]# tail -2 /usr/local/nginx/logs/access_bbs.log 
192.168.103.121--[29/Aug/2019:18:02:41 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"
192.168.103.121--[29/Aug/2019:18:02:44 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"

其中,日志里的192.168.103.121为反向代理的IP,对应Nginx日志格式里的$remote_addr变量,而日志结尾的192.168.103.204对应的时日志格式里的“$http_x_forwarded_for”变量,即接收了前面反向代理配置中“proxy_set_header X-Forwarded-For $remote_addr;”参数X-Forwarded-For的IP了。
关于X-Forwarded-For的详细说明,可见http://en.wikipedia.org/wiki/X-Forwwawrded-For。下图是反向代理相关重要基础参数的总结,供同窗们参考。

 

 

与反向代理配置相关的更多参数说明

除了具备多虚拟主机代理以及节点服务器记录真实用户IP的功能外,Nginx软件还提供了至关多的做为反向代理和后端节点服务器对话的相关控制参数,具体见前面在讲解proxy模块时提供的图表。

相信同窗们对这些参数有了必定了解了,因为参数众多,最好把这些参数放到一个配置文件里,而后用include方式包含到虚拟主机配置里,效果以下:

//lb01
# 建立配置文件
[root@lb01 /]# vim /usr/local/nginx/conf/proxy.conf

proxy_set_header host $host;
proxy_set_header x-forwarded-for $remote_addr;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;

#修改配置
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream webpools {
        #若是就是单个Server,不必设置权重
        server 192.168.103.123:80       weight=5 max_fails=1 fail_timeout=60s; #当检测次数等于1的时候,1次连续检测失败后,间隔60s再从新检测。
        server 192.168.103.124:80       weight=5;

        server 192.168.103.124:80  weight=5   backup; #热备机器设置
    }

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            root   html;
            index  index.html index.htm;
            proxy_pass http://webpools;
 include proxy.conf;
        }
    }
}

# 从新加载
[root@lb01 /]# nginx -s reload

更多Nginx反向代理参数说明
http://nginx.org/en/docs/http/ngx_http_proxy_module.html

四、根据URL中的目录地址实现代理转发

案例背景:

经过Nginx实现动静分离,即经过Nginx反向代理配置规则实现让动态资源和静态资源及其余业务分别由不一样的服务器解析,以解决网站性能,安全,用户体验等重要问题。

下图为企业常见的动静分离集群架构图,此架构图适合网站前端只使用同一个域名提供服务的场景,例如,用户访问的域名是www.yunjisuan.com,而后,当用户请求www.yunjisuan.com/upload/xx地址时候,代理会分配请求到上传服务器池处理数据;当用户请求www.yunjisuan.com/static/xx地址的时候,代理会分配请求到静态服务器池请求数据;当用户请求www.yunjisuan.com/xx地址的时候,即不包含上述指定的目录地址路径时,代理会分配请求到默认的动态服务器池请求数据(注意:上面的xx表示任意路径)。

4.一、准备:案例配置实战

先进行企业案例需求梳理:

  • 当用户请求www.yunjisuan.com/upload/xx地址时,实现由upload上传服务器池处理请求。
  • 当用户请求www.yunjisuan.com/static/xx地址时,实现由静态服务器池处理请求。
  • 除此之外,对于其余访问请求,全都由默认的动态服务器池处理请求。

了解了需求后,就能够进行upstream模块服务器池的配置了。

//lb01
#static_pools为静态服务器池,有一个服务器,地址为192.168.103.123,端口为80.
upstream staticpools {
    server 192.168.103.123:80 weght=1;
}

#upload_pools为上传服务器池,有一个服务器地址为192.168.103.124,端口为80.
upstream uploadpools {

    server 192.168.103.124:80 weight=1;

}

#default_pools为默认的服务器池,即动态服务器池,有一个服务器,地址为192.168.103.125,端口为80.
upstream defaultpools {
    server 192.168.103.125:80 weight=1;
}

#提示:须要增长一台测试Web节点Web03(ip:192.168.103.125),配置与Web01,Web02同样。

下面利用location或if语句把不一样的URI(路径)请求,分给不一样的服务器池处理,具体配置以下。

方案1:以location方案实现

//lb01
#将符合static的请求交给静态服务器池static_pools,配置以下:
location /static/ {
    proxy_pass http://staticpools;
    include proxy.conf;
}

#将符合upload的请求交给上传服务器池upload_pools,配置以下:
location /upload/ {
    proxy_pass http://uploadpools;
    include proxy.conf;
}

#不符合上述规则的请求,默认所有交给动态服务器池default_pools,配置以下:
location / {
    proxy_pass http://defaultpools;
    include proxy.conf;
}

方案2:以if语句实现。

[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf

worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  www.yunjisuan.com;
        location / {
            if ($request_uri ~* "^/static/(.*)$")
            {   
                proxy_pass http://staticpools/$1;
            }   

            if ($request_uri ~* "^/upload/(.*)$")
            {   
                proxy_pass http://uploadpools/$1;
 }  
            proxy_pass http://defaultpools;
            include proxy.conf;
        }
    }
}

 

从新加载配置生效,以下:

[root@lb01 /]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload

暂时不要马上测试成果,为了实现上述代理的测试,还须要在Web01和Web02上作节点的测试配置,才能更好地展现测试效果。
以Web01做为static静态服务,地址端口为:192.168.103.123:80,须要事先配置一个用于测试静态的地址页面,并测试访问,肯定它会返回正确结果。操做步骤以下:

// web01
[root@web01 /]# mkdir -p /usr/local/nginx/html/www/static
[root@web01 /]# echo "static_pools www" >> /usr/local/nginx/html/www/static/index.html
[root@web01 /]# mkdir -p /usr/local/nginx/html/bbs/static
[root@web01 /]# echo "static_pools bbs" >> /usr/local/nginx/html/bbs/static/index.html
[root@web01 /]# curl http://www.yunjisuan.com/static/index.html      #这里的www.yunjisuan.com是解析过的Web01的本地IP
static_pools www
[root@web01 /]# curl http://bbs.yunjisuan.com/static/index.html      #这里的bbs.yunjisuan.com是解析过的Web01的本地IP
static_pools bbs
#提示:测试的静态地址为http://www.yunjisuan.com/static/index.html,注意,是带static路径的地址。

以Web02做为upload上传服务,地址端口为:192.168.103.124:80,须要事先配置一个用于测试上传服务的地址页面,并测试访问,肯定它会返回正确结果。操做步骤以下:

// web02
[root@web02 ~]# mkdir -p /usr/local/nginx/html/www/upload/
[root@web02 ~]# echo "upload_pools www" >> /usr/local/nginx/html/www/upload/index.html
[root@web02 ~]# mkdir -p /usr/local/nginx/html/bbs/upload
[root@web02 ~]# echo "upload_pools bbs" >> /usr/local/nginx/html/bbs/upload/index.html
[root@web02 ~]# curl http://www.yunjisuan.com/upload/index.html      #这里的www.yunjisuan.com是解析过的Web02的本地IP
upload_pools www
[root@web02 ~]# curl http://bbs.yunjisuan.com/upload/index.html      #这里的bbs.yunjisuan.com是解析过的Web02的本地IP
upload_pools bbs
#提示:测试的上传地址为http://www.yunjisuan.com/upload/index.html,注意,是带upload路径的地址。

在Web03做为动态服务节点,地址端口为192.168.103.125:80,一样须要事先配置一个默认的地址页面,并测试访问,肯定它会返回正确结果。操做步骤以下:

[root@web03 /]# cd /usr/local/nginx/html/www
[root@web03 www]# echo "default_pools" > index.html
[root@web03 www]# curl http://www.yunjisuan.com
default_pools

以上准备了上台Web节点服务器,分别加入到了upstream定义的不一样服务器池,表明三组不一样的业务集群组,从本机经过hosts解析各自的域名,而后测试访问,其地址与实际访问的内容输出请对照下表:

节点 IP及端口 测试地址 字符串为表明业务
web01 192.168.103.123:80 http://www.yunjisuan.com/static/index.html static_pools
web02 192.168.103.124:80 http://www.yunjisuan.com/upload/index.html upload_pools
web03 192.168.103.125:80 http://www.yunjisuan.com default_pools

使用客户端计算机访问测试时,最好选用集群之外的机器,这里先在浏览器客户端的hosts文件里把www.yunjisuan.com解析到Nginx反向代理服务器的IP,而后访问上述URL,看代理是否是把请求正确地转发到了指定的服务器上。若是能够获得与上表对应的内容,表示配置的Nginx代理分发的彻底正确,由于若是分发请求到错误的机器上就没有对应的URL页面内容,输出会是404错误。 

[root@lb01 /]# curl http://www.yunjisuan.com/static/index.html
static_pools www
[root@lb01 /]# curl http://www.yunjisuan.com/upload/index.html
upload_pools www
[root@lb01 /]# curl http://www.yunjisuan.com
default_pools

实际配置以下:

// lb01
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # static_pools为静态服务器池,有一个服务器,地址为192.168.103.123,端口为80. upstream staticpools { server 192.168.103.123:80 ; } # upload_pools为上传服务器池,有一个服务器地址为192.168.103.124,端口为80. upstream uploadpools { server 192.168.103.124:80 ; } # default_pools为默认的服务器池,即动态服务器池,有一个服务器,地址为192.168.103.125,端口为80. upstream defaultpools { server 192.168.103.125:80 ; } server { listen 80; server_name www.yunjisuan.com; location /static/ { proxy_pass http://staticpools; include proxy.conf; } location /upload/ { proxy_pass http://uploadpools; include proxy.conf; } location / { proxy_pass http://defaultpools; include proxy.conf; } } }

 

根据URL目录地址转发的应用场景

  • 根据HTTP的URL进行转发的应用状况,被称为第7层(应用层)的负载均衡,而LVS的负载均衡通常用于TCP等的转发,所以被称为第4层(传输层)的负载均衡。
  • 在企业中,有时但愿只用一个域名对外提供服务,不但愿使用多个域名对应同一个产品业务,此时就须要在代理服务器上经过配置规则,使得匹配不一样规则的请求会交给不一样的服务器池处理。这类业务有:
  • 业务的域名没有拆封或者不但愿拆分,但但愿实现动静分离,多业务分离,这在前面已经讲解过案例了。
  • 不一样的客户端设备(例如:手机和PC端)使用同一个域名访问同一个业务网站,就须要根据规则将不一样设备的用户请求交给后端不一样的服务器处理,以便获得最佳用户体验。这也是很是重要的,接下来,我就带同窗们看看这类的相关案例。

五、根据客户端的设备(user_agent)转发实践需求

  在企业中,为了让不一样的客户端设备用户访问有更好的体验,须要在后端架设不一样服务器来知足不一样的客户端访问,例如:移动客户端访问网站,就须要部署单独的移动服务器及程序,体验才能更好,并且移动端还分苹果,安卓,Ipad等,在传统的状况下,通常用下面的办法解决这个问题。

  • 常规4层负载均衡解决方案架构
      在常规4层负载均衡架构下,可使用不一样的域名来实现这个需求,例如,人为分配好让移动端用户访问wap.yunjisuan.com,PC客户端用户访问www.yunjisuan.com,经过不一样域名来引导用户到指定的后端服务器,该解决方案的架构图以下:

     

       此解决方案的最大问题就是不一样客户端的用户要记住对应的域名!而绝大多数用户只会记住www.yunjisuan.com,不会记住wap.yunjisuan.com,这样一来就会致使用户体验不是很好。有没有办法让全部客户端用户只访问一个统一的www.yunjisuan.com这个地址,还能让不一样客户端设备都能有更好的访问体验呢?固然有!那就是下面的第7层负载均衡解决方案。

  • 第7层负载均衡解决方案
      在第7层负载均衡架构下,就能够不须要人为拆分域名了,对外只须要用一个域名,例如www.yunjisuan.com,经过获取用户请求中的设备信息(利用$http_user_agent获取),根据这些信息转给后端合适的服务器处理,这个方案最大好处就是不须要让用户记忆多个域名了,用户只须要记住主网站地址www.yunjisuan.com,剩下的由网站服务器处理,这样的思路大大地提高了用户访问体验,这是当前企业网站很是经常使用的解决方案。
    下面咱们就来说解此方案,下图描述了上述解决方案相应的架构逻辑图

5.一、根据客户端设备(user_agent)转发请求实践

这里仍是使用static_pools,upload_pools做为本次实验的后端服务器池。下面先根据计算机客户端浏览器的不一样设置对应的匹配规则。(因为没有合适的实验验证环境,这里仅做需求实现的细节讲解)

//lb01
location / {
    if ($http_user_agent ~* "MSIE")
    # 若是请求的浏览器为微软IE浏览器(MSIE),则让请求由static_pools池处理
    {
        proxy_pass http://staticpools;
    }
    if ($http_user_agent ~* "Chrome")
    # 若是请求的浏览器为谷歌浏览器(Chrome),则让请求由upload_pools池处理
    {
        proxy_pass http://uploadpools;
    }
    # 其余客户端,由default_pools处理
    proxy_pass http://defaultpools;
    include proxy.conf;
}

 

 

除了针对浏览器外,上述“$http_user_agent”变量也可针对移动端,好比安卓,苹果,Ipad设备进行匹配,去请求指定的服务器,具体细节配置以下:

//lb01
location / {
    if ($http_user_agent ~* "android")
    {
        proxy_pass http://android_pools;    #这里是android服务器池
    }
    if ($http_user_agent ~* "iphone")
    {
        proxy_pass http://iphone_pools;    #这里是iphone服务器池
    }
    proxy_pass http://pc_pools;     #这里是默认的pc服务器池
    include extra/proxy.conf;
}
  • 这部分的测试同窗们能够回家经过局域网的Wifi功能来实现,用手机等链接到wifi,而后访问服务器的IP测试就能够了。测试时,请用节点的第一个虚拟主机请求测试,这样就不须要本地hosts域名解析了,由于手机端测试作hosts解析也不容易,固然有公网的域名和服务器测试最佳,这部分的配合和测试与浏览器设备实践几乎同样,所以,这里的测试就留给同窗们了,看看能不能达到你想的测试效果?
  • 此外,查找移动设备的user_agent对应的具体名称时,仍是先用对应的设备经过IP地址访问节点服务器,而后看访问日志,注意IP访问只找第一个虚拟主机的网站。
192.168.0.110--[28/Jul/2017:02:12:10 -0400]"GET / HTTP/1.1"200 18 "-""Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)""-" 
#PCwindows访问日志

192.168.0.106--[28/Jul/2017:02:12:22 -0400]"GET / HTTP/1.1"200 18 "-""Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.0 Mobile/14G60 Safari/602.1""-"

#苹果iphone6手机设备访问的日志。

六、根据文件扩展名实现代理转发

除了根据URI路径及user_agent转发外,还能够实现根据文件扩展名进行转发(这里仅以细节配置做为讲解内容,如需测试请同窗们自行实验)

相关server配置

#先看看location方法的匹配规则,以下:
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
    proxy_pass http://static_pools;
    include proxy.conf;
}

#下面是if语句方法的匹配规则:
if ($request_uri ~* ".*\.(php|php5)$")
{
    proxy_pass http://php_server_pools;
}

if ($request_uri ~* ".*\.(jsp|jsp*|do|do*)$")
{
    proxy_pass http://java_server_pools;
}

根据扩展名转发的应用场景

可根据扩展名实现资源的动静分离访问,如图片,视频等请求静态服务器池,PHP,JSP等请求动态服务器池。

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
    proxy_pass http://static_pools;
    include proxy.conf;
}

location ~ .*\.(php|php3|php5)$ {
    proxy_pass http://dynamic_pools;
    include proxy.conf
}

在开发没法经过程序实现动静分离的时候,运维能够根据资源实体进行动静分离,而不依赖于开发,具体实现策略是先把后端的服务器分红不一样的组。注意,每组服务器的程序都是相同的,由于开发没有把程序拆开,分组后,在前端代理服务器上经过讲解过的路径,扩展名进行规则匹配,从而实现请求的动静分离。

七、Nginx负载均衡检测节点状态

淘宝技术团队开发了一个Tengine(Nginx的分支)模块Nginx_upstream_check_module,用于提供主动式后端服务器健康检查。经过它能够检测后端realserver的健康状态,若是后端realserver不可用,则全部的请求就不会转发到该节点上。
Tengine原生支持这个模块,而Nginx则须要经过打补丁的方式将该模块添加到Nginx中。补丁下载地址:https://github.com/yaoweibin/nginx_upstream_check_module。下面介绍如何使用这个模块。

  1. 安装nginx_upstream_check_module模块
    #系统已经安装了nginx-1.10.2软件
    [root@lb01 ~]# /usr/local/nginx/sbin/nginx -V
    nginx version: nginx/1.10.2
    
    #下载补丁包
    [root@lb01 ~]# wget https://codeload.github.com/786744873/nginx_upstream_check_module/zip/master
    [root@lb01 ~]# unzip master
    [root@lb01 ~]# ls
    anaconda-ks.cfg  install.log  install.log.syslog  master  nginx-1.10.2.tar.gz  nginx_upstream_check_module-master
    [root@lb01 nginx-1.10.2]# mv ~/nginx_upstream_check_module-master /usr/src/
    
    #由于是对源程序打补丁,因此还须要Nginx源程序
    [root@lb01 ~]# cd /usr/src/nginx-1.10.2/
    [root@lb01 nginx-1.10.2]# patch -p0 < /usr/src/nginx_upstream_check_module-master/check_1.9.2+.patch
    patching file src/http/modules/ngx_http_upstream_hash_module.c
    patching file src/http/modules/ngx_http_upstream_ip_hash_module.c
    patching file src/http/modules/ngx_http_upstream_least_conn_module.c
    patching file src/http/ngx_http_upstream_round_robin.c
    patching file src/http/ngx_http_upstream_round_robin.h
    
    #备份源安装程序
    [root@lb01 nginx-1.10.2]# cd /usr/local/
    [root@lb01 local]# ls
    bin  etc  games  include  lib  lib64  libexec  nginx  sbin  share  src
    [root@lb01 local]# mv nginx{,.ori}
    [root@lb01 local]# ls
    bin  etc  games  include  lib  lib64  libexec  nginx.ori  sbin  share  src
    [root@lb01 local]# cd /usr/src/nginx-1.10.2/
    
    #从新进行编译,编译的参数要和之前一致,最后加上 --add-module=/usr/src/nginx_upstream_check_module-master/
    
    [root@lb01 nginx-1.10.2]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --add-module=/usr/src/nginx_upstream_check_module-master/
    [root@lb01 local]# /usr/local/nginx/sbin/nginx -V
    nginx version: nginx/1.10.2
    built by gcc 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) 
    built with OpenSSL 1.0.1e-fips 11 Feb 2013
    TLS SNI support enabled
    configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --add-module=/usr/src/nginx_upstream_check_module-master/
    
    #拷贝源配置文件到当前Nginx的安装目录下
    [root@lb01 local]# pwd
    /usr/local
    [root@lb01 local]# cp nginx.ori/conf/nginx.conf nginx/conf/
    cp: overwrite `nginx/conf/nginx.conf'? y
    [root@lb01 local]# cp nginx.ori/conf/proxy.conf nginx/conf/
    [root@lb01 local]# /usr/local/nginx/sbin/nginx -t
    nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
  2. 配置Nginx健康检查,以下:
    [root@lb01 local]# vim nginx/conf/nginx.conf
    
    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
    
        # static_pools为静态服务器池,有一个服务器,地址为192.168.103.123,端口为80.
        upstream staticpools {
            server 192.168.103.123:80 ;
            check interval=3000 rise=2 fall=5 timeout=1000 type=http;   #对static服务器池开启健康监测
        }
    
        # upload_pools为上传服务器池,有一个服务器地址为192.168.103.124,端口为80.
        upstream uploadpools {
            server 192.168.103.124:80 ;
            check interval=3000 rise=2 fall=5 timeout=1000 type=http;   #对static服务器池开启健康监测
        }
    
        # default_pools为默认的服务器池,即动态服务器池,有一个服务器,地址为192.168.103.125,端口为80.
        upstream defaultpools {
            server 192.168.103.125:80 ;
            check interval=3000 rise=2 fall=5 timeout=1000 type=http;   #对static服务器池开启健康监测
        }
    
        server {
            listen       80;
            server_name  www.yunjisuan.com;
            location / {
                if ($http_user_agent ~* "MSIE")
                #若是请求的浏览器为微软IE浏览器(MSIE),则让请求由static_pools池处理
                {
                    proxy_pass http://staticpools;
                }
                if ($http_user_agent ~* "Chrome")
                #若是请求的浏览器为谷歌浏览器(Chrome),则让请求由upload_pools池处理
                {
                    proxy_pass http://uploadpools;
                }
                proxy_pass http://defaultpools;
                include proxy.conf;
            }
            location /status {
                check_status;           #启动健康检查模块
                access_log off;         #关闭此location的访问日志记录
            }
    
        }
    }
  3. 重启lb1的nginx服务
    注意此处必须重启Nginx,不能从新加载

    [root@lb01 local]# killall nginx
    [root@lb01 local]# /usr/local/nginx/sbin/nginx
    [root@lb01 local]# netstat -antup | grep nginx
    tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      20908/nginx: master 

    check interval=3000 rise=2 fall=5 timeout=1000 type=http;
    上面配置的意思时,对static_pools这个负载均衡条目中的全部节点,每隔3秒检测一次,请求2次正常则标记realserver状态为up,若是检测5次都失败,则标记realserver的状态为down,超时时间为1秒,检查的协议是HTTP。
    详细用法见官网:http://tengine.taobao.org/document_cn/http_upstream_check_cn.html

    访问页面时,显示以下图所示:

     

     关闭任意一个RS节点后(3个Web服务器任选一个关闭nginx服务)

proxy_next_upstream 参数补充

当Nginx接收后端服务器返回proxy_next_upstream参数定义的状态码时,会将这个请求转发给正常工做的后端服务器,例如500,502,503,504,此参数能够提高用户的访问体验,具体配置以下:

server {
    listen 80;
    server_name www.yunjisuan.com;
    location / {
        proxy_pass http://static_pools;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        include proxy.conf;
    }
}
相关文章
相关标签/搜索