Nginx一文精通:反向代理、负载均衡、动静分离

2021-08-16 16:42:57 浏览数 (1)

一、Nginx简介

1.1、Nginx概述

   Nginx(“engine x”)一个具有高性能的HTTP和反向代理的WEB服务器,同时也是一个POP3/SMTP/IMAP代理服务器,是由伊戈尔·赛索耶夫(俄罗斯人)使用C语言编写的,Nginx的第一个版本是2004年10月4号发布的0.1.0版本。另外值得一提的是伊戈尔·赛索耶夫将Nginx的源码进行了开源,这也为Nginx的发展提供了良好的保障。

1.2、名词解释

1.2.1、WEB服务器

   WEB服务器也叫网页服务器,英文名叫Web Server,主要功能是为用户提供网上信息浏览服务。

1.2.2、HTTP

   HTTP是超文本传输协议的缩写,是用于从WEB服务器传输超文本到本地浏览器的传输协议,也是互联网上应用最为广泛的一种网络协议。HTTP是一个客户端和服务器端请求和应答的标准,客户端是终端用户,服务端是网站,通过使用Web浏览器、网络爬虫或者其他工具,客户端发起一个到服务器上指定端口的HTTP请求。

1.2.3、 POP3/SMTP/IMAP

POP3(Post Offic Protocol 3):邮局协议的第三个版本。 SMTP(Simple Mail Transfer Protocol):简单邮件传输协议。 IMAP(Internet Mail Access Protocol):交互式邮件存取协议。

1.3、Nginx的作用

    Nginx 可以作为静态页面的 web 服务器,同时还支持 CGI 协议的动态语言,比如 perl、php等。但是不支持 java。Java 程序只能通过与 tomcat 配合完成。Nginx 专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率 ,能经受高负载的考验,有报告表明能支持高达 50,000 个并发连接数。

    Nginx 不仅可以实现动静分离、做反向代理,实现负载均衡。还能用作正向代理来进行上网等功能。

1.3.1、正向代理

    如果把局域网外的 Internet 想象成一个巨大的资源库,则局域网中的客户端要访问 Internet,则需要通过代理服务器来访问,这种代理服务就称为正向代理。

1.3.2、反向代理

    反向代理,其实客户端对代理是无感知的,因为客户端不需要任何配置就可以访问,我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器 IP 地址。

    比如用户要访问www.linstudy.cn,但是www.linstudy.cn悄悄地把这个请求交给后台N台服务器中的其中一台来做,这种方式就是反向代理了。

1.3.3、负载均衡

    客户端发送多个请求到服务器,服务器处理请求,有一些可能要与数据库进行交互,服务器处理完毕后,再将结果返回给客户端。

    我们首先想到的可能是升级服务器的配置,比如提高 CPU 执行频率,加大内存等提高机器的物理性能来解决此问题,但是我们知道摩尔定律的日益失效,硬件的性能提升已经不能满足日益提升的需求了。最明显的一个例子,天猫双十一当天,某个热销商品的瞬时访问量是极其庞大的,那么类似上面的系统架构,将机器都增加到现有的顶级物理配置,都是不能够满足需求的。那么怎么办呢?

    上面的分析我们去掉了增加服务器物理配置来解决问题的办法,也就是说纵向解决问题的办法行不通了,那么横向增加服务器的数量呢?这时候集群的概念产生了,单个服务器解决不了,我们增加服务器的数量,然后将请求分发到各个服务器上,将原先请求集中到单个服务器上的情况改为将请求分发到多个服务器上,将负载分发到不同的服务器,也就是我们 所说的负载均衡。

    使用负载均衡大致有以下几种方式:

  1. 使用硬件负载均衡策略,如使用F5,Array等负载均衡器。
  2. 使用软件进行负载均衡。
  3. 如使用阿里云服务器均衡SLB。
  4. 使用Nginx Keepalived。
  5. 其他软件负载均衡如LVS(Linux Virtual Server),haproxy等技术。

1.3.4、动静分离

    为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速度。降低原来单个服务器的压力。

1.4、常用的服务器对比

   Netcraft公司于1994年底在英国成立,多年来一直致力于互联网市场以及在线安全方面的咨询服务,其中在国际上最具影响力的当属其针对网站服务器、SSL市场所做的客观严谨的分析研究,公司官网每月公布的调研数据(Web Server Survey)已成为当今人们了解全球网站数量以及服务器市场分额情况的主要参考依据,时常被诸如华尔街杂志,英国BBC,Slashdot等媒体报道或引用。

   我们先来看一组数据,我们先打开Nginx的官方网站,找到Netcraft公司公布的数据,对当前主流服务器产品进行介绍。

   上面这张图展示了2019年全球主流Web服务器的市场情况,其中有Apache、Microsoft-IIS、google Servers、Nginx、Tomcat等,我们把几种常见的服务器来给大家简单介绍下。

1.4.1、IIS

   全称(Internet Information Services)即互联网信息服务,是由微软公司提供的基于windows系统的互联网基本服务。windows作为服务器在稳定性与其他一些性能上都不如类UNIX操作系统,因此在需要高性能Web服务器的场合下,IIS可能就会被"冷落"。

1.4.2、Tomcat

   Tomcat是一个运行Servlet和JSP的Web应用软件,Tomcat技术先进、性能稳定而且开放源代码,因此深受Java爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。但是Tomcat天生是一个重量级的Web服务器,对静态文件和高并发的处理比较弱。

1.4.3、Apache

   Apache的发展时期很长,同时也有过一段辉煌的业绩。从上图可以看出大概在2014年以前都是市场份额第一的服务器。Apache有很多优点,如稳定、开源、跨平台等。但是它出现的时间太久了,在它兴起的年代,互联网的产业规模远远不如今天,所以它被设计成一个重量级的、不支持高并发的Web服务器。在Apache服务器上,如果有数以万计的并发HTTP请求同时访问,就会导致服务器上消耗大量能存,操作系统内核对成百上千的Apache进程做进程间切换也会消耗大量的CUP资源,并导致HTTP请求的平均响应速度降低,这些都决定了Apache不可能成为高性能的Web服务器,这也促使了Lighttpd和Nginx的出现。

1.4.4、Lighttpd

   Lighttpd是德国的一个开源的Web服务器软件,它和Nginx一样,都是轻量级、高性能的Web服务器,欧美的业界开发者比较钟爱Lighttpd,而国内的公司更多的青睐Nginx,同时网上Nginx的资源要更丰富些。

1.5、Nginx的优点

1.5.1、速度更快、并发更高

   单次请求或者高并发请求的环境下,Nginx都会比其他Web服务器响应的速度更快。一方面在正常情况下,单次请求会得到更快的响应,另一方面,在高峰期(如有数以万计的并发请求),Nginx比其他Web服务器更快的响应请求。Nginx之所以有这么高的并发处理能力和这么好的性能原因在于Nginx采用了多进程和I/O多路复用(epoll)的底层实现。

1.5.2、配置简单,扩展性强

   Nginx的设计极具扩展性,它本身就是由很多模块组成,这些模块的使用可以通过配置文件的配置来添加。这些模块有官方提供的也有第三方提供的模块,如果需要完全可以开发服务自己业务特性的定制模块。

1.5.3、高可靠性

   Nginx采用的是多进程模式运行,其中有一个master主进程和N多个worker进程,worker进程的数量我们可以手动设置,每个worker进程之间都是相互独立提供服务,并且master主进程可以在某一个worker进程出错时,快速去"拉起"新的worker进程提供服务。

1.5.4、热部署

   现在互联网项目都要求以7*24小时进行服务的提供,针对于这一要求,Nginx也提供了热部署功能,即可以在Nginx不停止的情况下,对Nginx进行文件升级、更新配置和更换日志文件等功能。

1.5.5、成本低、BSD许可证

   BSD是一个开源的许可证,世界上的开源许可证有很多,现在比较流行的有六种分别是GPL、BSD、MIT、Mozilla、Apache、LGPL。

1.6、Nginx的功能特性及常用功能

   Nginx提供的基本功能服务从大体上归纳为基本HTTP服务、高级HTTP服务和邮件服务等三大类。

1.6.1、基本HTTP服务

   Nginx可以提供基本HTTP服务,可以作为HTTP代理服务器和反向代理服务器,支持通过缓存加速访问,可以完成简单的负载均衡和容错,支持包过滤功能,支持SSL等。他包含有以下几种服务:

  • 处理静态文件、处理索引文件以及支持自动索引。
  • 提供反向代理服务器,并可以使用缓存加上反向代理,同时完成负载 均衡和容错。
  • 提供对FastCGI、memcached等服务的缓存机制,,同时完成负载均 衡和容错。
  • 使用Nginx的模块化特性提供过滤器功能。Nginx基本过滤器包括gzip压缩、ranges支持、chunked响应、XSLT、SSI以及图像缩放 等。其中针对包含多个SSI的页面,经由FastCGI或反向代理,SSI过滤器可以并行处理。
  • 支持HTTP下的安全套接层安全协议SSL。
  • 支持基于加权和依赖的优先权的HTTP/2。

1.6.2、高级HTTP服务

  • 支持基于名字和IP的虚拟主机设置。
  • 支持HTTP/1.0中的KEEP-Alive模式和管线(PipeLined)模型连接。
  • 自定义访问日志格式、带缓存的日志写操作以及快速日志轮转。
  • 提供3xx~5xx错误代码重定向功能。
  • 支持重写(Rewrite)模块扩展。
  • 支持重新加载配置以及在线升级时无需中断正在处理的请求。
  • 支持网络监控。
  • 支持FLV和MP4流媒体传输。

1.6.3、邮件服务

   Nginx提供邮件代理服务也是其基本开发需求之一,主要包含以下特性:

  • 支持IMPA/POP3代理服务功能。
  • 支持内部SMTP代理服务功能。

二、Nginx的安装

2.1、安装

解压下载的tar.gz包

代码语言:javascript复制
# 可以加上 -C /usr/local 参数指定解压的位置
tar -zxvf ginx-1.6.2.tar.gz 

下载所需的依赖库文件

代码语言:javascript复制
yum install pcre -y
yum install pcre-devel -y
yum install zlib -y
yum install zlib-devel -y

进行configure配置,查看是否报错

代码语言:javascript复制
# 在根目录进行
./configure

编译安装

代码语言:javascript复制
make && make install

访问

    我们可以通过服务器的ip 端口(默认80)去访问Nginx。

三、Nginx 常用的命令和配置文件

3.1、Nginx常用命令

3.1.1、启动命令

代码语言:javascript复制
# 在Nginx的sbin目录下执行
./nginx

3.1.2、关闭命令

代码语言:javascript复制
# 在Nginx的sbin目录下执行
./nginx -s stop

3.1.3、重启Nginx

代码语言:javascript复制
# 在Nginx的sbin目录下执行
/nginx -s reload

3.2、Nginx的配置文件

    Nginx 安装目录下,其默认的配置文件都放在这个目录的 conf 目录下,而主配置文件nginx.conf 也在其中,后续对 Nginx 的使用基本上都是对此配置文件进行相应的修改。

   配置文件中有很多#, 开头的表示注释内容。

代码语言:javascript复制
#user  nobody;

#开启进程数 <=CPU数 
worker_processes  1;

#错误日志保存位置
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#进程号保存文件
#pid        logs/nginx.pid;

#每个进程最大连接数(最大连接=连接数x进程数)每个worker允许同时产生多少个链接,默认1024
events {
    worker_connections  1024;
}


http {
	#文件扩展名与文件类型映射表
    include       mime.types;
	#默认文件类型
    default_type  application/octet-stream;

	#日志文件输出格式 这个位置相于全局设置
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

	#请求日志保存位置
    #access_log  logs/access.log  main;
	
	#打开发送文件
    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
	#连接超时时间
    keepalive_timeout  65;

	#打开gzip压缩
    #gzip  on;
	
	#设定请求缓冲
	#client_header_buffer_size 1k;
	#large_client_header_buffers 4 4k;
	
	#设定负载均衡的服务器列表
	#upstream myproject {
		#weigth参数表示权值,权值越高被分配到的几率越大
		#max_fails 当有#max_fails个请求失败,就表示后端的服务器不可用,默认为1,将其设置为0可以关闭检查
		#fail_timeout 在以后的#fail_timeout时间内nginx不会再把请求发往已检查出标记为不可用的服务器
	#}
	
    #webapp
    #upstream myapp {   
  	# server 192.168.122.133:8080 weight=1 max_fails=2 fail_timeout=30s;   
	# server 192.168.122.134:8080 weight=1 max_fails=2 fail_timeout=30s;   
    #} 

    #配置虚拟主机,基于域名、ip和端口
    server {
		#监听端口
        listen       80;
		#监听域名
        server_name  localhost;

        #charset koi8-r;
		
		#nginx访问日志放在logs/host.access.log下,并且使用main格式(还可以自定义格式)
        #access_log  logs/host.access.log  main;

		#返回的相应文件地址   
        location / {
            #设置客户端真实ip地址
            #proxy_set_header X-real-ip $remote_addr;		
			#负载均衡反向代理
			#proxy_pass http://myapp;
			
			#返回根路径地址(相对路径:相对于/usr/local/nginx/)
            root   html;
			#默认访问文件
            index  index.html index.htm;
        }

		#配置反向代理tomcat服务器:拦截.jsp结尾的请求转向到tomcat
        #location ~ .jsp$ {
        #    proxy_pass http://192.168.122.133:8080;
        #}		
		
        #error_page  404              /404.html;
        # redirect server error pages to the static page /50x.html
        #
		
		#错误页面及其返回地址
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ .php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ .php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /.ht {
        #    deny  all;
        #}
    }
	
	#虚拟主机配置:
	server {
		listen 1234;
		server_name wolfcode.cn;
		location / {
		#正则表达式匹配uri方式:在/usr/local/nginx/wolfcode.cn下 建立一个test123.html 然后使用正则匹配
		#location ~ test {
			## 重写语法:if return (条件 = ~ ~*)
			#if ($remote_addr = 192.168.122.1) {
			#       return 401;
			#}		
			
			#if ($http_user_agent ~* firefox) {
			#	   rewrite ^.*$ /firefox.html;
			#	   break;
			#}			
						
			root wolfcode.cn;
			index index.html;
		}
		
		#location /goods {
		#		rewrite "goods-(d{1,5}).html" /goods-ctrl.html;
		#		root wolfcode.cn;
		#		index index.html;
		#}
		
		#配置访问日志
		access_log logs/wolfcode.cn.access.log main;
	}
	


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

    我们去掉所有以 # 开头的段落,精简之后的内容如下:

代码语言:javascript复制
...              #全局块

events {         #events块
   ...
}

http      #http块
{
    ...   #http全局块
    server        #server块
    { 
        ...       #server全局块
        location [PATTERN]   #location块
        {
            ...
        }
        location [PATTERN] 
        {
            ...
        }
    }
    server
    {
      ...
    }
    ...     #http全局块
}

3.2.1、全局块

    从配置文件开始到 events 块之间的内容,主要会设置一些影响 nginx 服务器整体运行的配置指令,主要包括配置运行 Nginx 服务器的用户(组)、允许生成的 worker process 数,进程 PID 存放路径、日志存放路径和类型以及配置文件的引入等。

    比如第一行的worker_processes 1;,这是 Nginx 服务器并发处理服务的关键配置,worker_processes 值越大,可以支持的并发处理量也越多,但是会受到硬件、软件等设备的制约

3.2.2、events块

    events 块涉及的指令主要影响 Nginx 服务器与用户的网络连接,常用的设置包括是否开启对多 work process下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个 word process 可以同时支持的最大连接数等。

    比如下面这段配置,就表示每个 work process 支持的最大连接数为 1024,这部分的配置对 Nginx 的性能影响较大,在实际中应该灵活配置。

代码语言:javascript复制
events {
    worker_connections  1024;
}

3.2.3、http块

    这算是 Nginx 服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里。

    可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。

    http 块也可以包括 http 全局块、server 块。

3.2.3.1、http全局块

    http 全局块配置的指令包括文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。

3.2.3.2、server块

    这块和虚拟主机有密切关系,虚拟主机从用户角度看,和一台独立的硬件主机是完全一样的,该技术的产生是为了节省互联网服务器硬件成本。

    每个 http 块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机,而每个 server 块也分为全局 server 块,以及可以同时包含多个 locaton 块。

代码语言:javascript复制
server {
        listen    80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
}
3.2.3.2.1、全局server块

    最常见的配置是本虚拟机主机的监听配置和本虚拟主机的名称或 IP 配置

3.2.3.2.2、location块

    一个 server 块可以配置多个 location 块。这块的主要作用是基于 Nginx 服务器接收到的请求字符串(例如 server_name/uri-string),对虚拟主机名称(也可以是 IP 别名)之外的字符串(例如 前面的 /uri-string)进行匹配,对特定的请求进行处理。地址定向、数据缓存和应答控制等功能,还有许多第三方模块的配置也在这里进行。

3.2.4、location配置

    location支持多种语法规则:

  1. = 开头表示精确匹配。
  2. ^~开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。
  3. ~ 开头表示区分大小写的正则匹配。
  4. ~* 开头表示不区分大小写的正则匹配。
  5. !~!~*分别为区分大小写不匹配及不区分大小写不匹配 的正则。
  6. /通用匹配,任何请求都会匹配到。

    既然有多种匹配规则,那么就肯定是有匹配的顺序:首先匹配 =,其次匹配^~, 其次是按文件中顺序的正则匹配,最后是交给 / 通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。

3.3、Nginx服务的信号控制

   Nginx之所以有高性能,其实也和它的架构模式有关。Nginx默认采用的是多进程的方式来工作的,当将Nginx启动后,我们通过ps -ef | grep nginx命令可以查看。

   Nginx后台进程中包含一个master进程和多个worker进程,master进程主要用来管理worker进程,包含接收外界的信息,并将接收到的信号发送给各个worker进程,监控worker进程的状态,当worker进程出现异常退出后,会自动重新启动新的worker进程。而worker进程则是专门用来处理用户请求的,各个worker进程之间是平等的并且相互独立,处理请求的机会也是一样的。

四、Nginx实现反向代理

    使用 nginx 反向代理,根据访问的路径跳转到不同端口的服务中。nginx 监听端口为 9001,实现下面的效果:

  1. 访问 http://127.0.0.1:9001/edu/ 直接跳转到 127.0.0.1:8081
  2. 访问 http://127.0.0.1:9001/vod/ 直接跳转到 127.0.0.1:8082

准备两个 tomcat,一个 8001 端口,一个 8002 端口,并准备好测试的页面

修改 nginx 的配置文件,在 http 块中添加 server{}

代码语言:javascript复制
server {
	listen 9001;
	server_name localhost;
	
	location ~ /edu/ {
		proxy_pass http://localhost:8001;
	}
	
	location ~ /vod/ {
		proxy_pass http://localhost:8002;
	}
}

五、Nginx实现负载均衡

5.1、负载均衡简介

    随着互联网信息的爆炸性增长,负载均衡(load balance)已经不再是一个很陌生的话题,顾名思义,负载均衡即是将负载分摊到不同的服务单元,既保证服务的可用性,又保证响应足够快,给用户很好的体验。

    快速增长的访问量和数据流量催生了各式各样的负载均衡产品,很多专业的负载均衡硬件提供了很好的功能,但却价格不菲,这使得负载均衡软件大受欢迎,nginx 就是其中的一个,在 linux 下有 Nginx、LVS、Haproxy 等等服务可以提供负载均衡服务

5.2、在nginx.conf进行配置

代码语言:javascript复制
http{
	upstream myserver{
		ip_hash;
		server 192.168.10.1:80880 weight=1;
		server 192.168.10.2:80880 weight=1;
	}
	server{
		location /{
			# 这里http后面名字要和上面的upstream后面的一样
			proxy_pass http://myserver;
			proxy_connect

5.3、负载均衡策略

    Nginx 提供了几种分配方式(策略):

  1. 轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。
  2. weight:代表权重,权重默认为1,权重越高,被分配的客户端就越多。
  3. ip_hash:每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决 session 的问题。
  4. 随机

六、Nginx实现动静分离

6.1、概述

    Nginx 动静分离简单来说就是把动态跟静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义上说应该是动态请求跟静态请求分开,可以理解成使用 Nginx处理静态页面,Tomcat 处理动态页面。动静分离从目前实现角度来讲大致分为两种:

  1. 纯粹把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案。
  2. 动态跟静态文件混合在一起发布,通过 nginx 来分开。

6.2、配置文件配置

在配置文件方面,重点是配置location。

代码语言:javascript复制
	location /www/ {
		root /data/;
		index index.html index.html;
	}
	location /image/ {
		root /data/;
		autoindex on;
	}

   最后检查 Nginx 配置是否正确即可,然后测试动静分离是否成功,之需要删除后端tomcat服务器上的某个静态文件,查看是否能访问,如果可以访问说明静态资源 nginx 直接返回了,不走后端 tomcat 服务器。

0 人点赞