Nginx知识汇总


目录
1 Nginx概述
2 使用
3 反向代理
4 负载均衡
5 重写
6 Nginx的其他用法
7 一个HTTP到Nginx处理的过程
8 Nginx解决跨域问题
9 Nginx配置防盗链
10 对比F5

参考资料

更多推荐:

Nginx概述

概念

nginx是一款高性能的http服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定,所以现在很多知名的公司都在使用nginx。

应用场景

(1)http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。

(2)虚拟主机。可以实现在一台服务器虚拟出多个网站。例如个人网站使用的虚拟主机。

(3)反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。

img

原理

(1)nginx 是事件驱动的服务器。

(2)nginx 采用的是多进程,(每个进程都是)单线程

(3)nginx 采用 IO 多路复用的事件模型。在Linux操作系统下,Nginx使用epoll事件模型(得益于此,Nginx在Linux操作系统下效率相当高)。在OpenBSD或FreeBSD操作系统上采用类似于epoll的事件模型kqueue。

Nginx 支持 select、poll、kqueue、epoll、rtsig 和 /dev/poll。当然,你不用特别指定事件模型,Nginx 会自动选择最佳。

epoll模型参考连接:select、poll和epoll模型 - 知乎

优缺点

(1)优点:

​ · 高性能

​ · 资源消耗低

​ · 模块化设计

​ · 模块编写简单

​ · 配置文件简洁

img

常见模块参考链接:Nginx常用模块及作用 - Room、C - 博客园

(2)缺点:( nginx 性能提升的代价是降低了其他方面)

​ · 稳定性,不如 apache 和 Windows Server 下的 Nginx

​ · 没有像 Apache 使用.htaccess 那样的访问设置

​ · 添加模块复杂(在版本 1.9.11 中增加了动态模块加载。但模块需要与 Nginx 同时编译)

nginx.conf配置文件

配置结构

events {
}
http {
  server {
  }
}

基本语法

配置文件的语法规则:

  1. 配置文件由指令与指令块构成;
  2. 每条指令以 ; 分号结尾,指令与参数间以空格符号分隔;
  3. 指令块以 {} 大括号将多条指令组织在一起;
  4. include 语句允许组合多个配置文件以提升可维护性;
  5. 使用 # 符号添加注释,提高可读性;
  6. 使用 $ 符号使用变量;
  7. 部分指令的参数支持正则表达式;

指令分类

① 简单指令 Simple Directives

如listen :80;,是由 名称(listen)-参数(:80)-分号(;) 构成。

简单指令只能包含在上下文指令中。(最高层的简单指令可以理解成在一个隐藏的上下文指令中)

② 上下文指令 Context Directives

server{  
}

指令继承

指令总是向下继承,除非有内部重名的会覆盖外层。这跟编程语言变量作用域的规则一样。

一些具体指令

(1)worker_processes

· 格式:worker_processes 1;

· 指定工作进程数。推荐 auto,它会自动检测逻辑CPU内核数。如果 cpu 使用了超线程技术,例如双核4线程,可以设置为4。

· 拓展:

物理cpu数:主板上实际插入的cpu数量。

cpu核数:单块CPU上面能处理数据的芯片组的数量,如双核、四核等。

逻辑cpu数:一般情况下,逻辑cpu=物理CPU数×cpu核数。

(2)Events 上下文指令

· Events 这个上下文指令只能在配置文件里出现一次。

· 格式:

events{
  worker_connections 512;
}

· worker_connections 单个工作进程可以允许同时建立连接的数量(此为调优的重要参数)。如果往上调整太多,记得有可能需要同时调整操作系统的最大打开文件数限制(ulimit)。

location

img

server 块可以包含多个 location 块,location 指令用于匹配 uri,语法:

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

指令后面:

  1. = 精确匹配路径,用于不含正则表达式的 uri 前,如果匹配成功,不再进行后续的查找;
  2. ^~ 用于不含正则表达式的 uri; 前,表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找;
  3. ~ 表示用该符号后面的正则去匹配路径,区分大小写;
  4. ~* 表示用该符号后面的正则去匹配路径,不区分大小写。跟 ~ 优先级都比较低,如有多个location的正则能匹配的话,则使用正则表达式最长的那个;

如果 uri 包含正则表达式,则必须要有 ~~* 标志。

Nginx内置变量

Nginx 有一些常用的全局变量,可以在配置的任何位置使用它们,如下表:

全局变量名 功能
$host 请求信息中的 Host,如果请求中没有 Host 行,则等于设置的服务器名,不包含端口
$request_method 客户端请求类型,如 GETPOST
$remote_addr 客户端的 IP 地址
$args 请求中的参数
$arg_PARAMETER GET 请求中变量名 PARAMETER 参数的值,例如:$http_user_agent(Uaer-Agent 值), $http_referer
$content_length 请求头中的 Content-length 字段
$http_user_agent 客户端agent信息
$http_cookie 客户端cookie信息
$remote_addr 客户端的IP地址
$remote_port 客户端的端口
$http_user_agent 客户端agent信息
$server_protocol 请求使用的协议,如 HTTP/1.0HTTP/1.1
$server_addr 服务器地址
$server_name 服务器名称
$server_port 服务器的端口号
$scheme HTTP 方法(如http,https)

进程模型

img

(1)master进程

· 接收来自外界的信号

· 向各worker进程发送信号

· 监控worker进程运行状态

· 当worker退出后,会自动重新启动新的worker进程

(2)worker进程

· 采用单线程,非阻塞的事件模型

· 监听端口及处理客户端请求

使用

静态访问

Web server很重要一部分工作就是提供静态页面的访问,例如images, html page。nginx可以通过不同的配置,根据request请求,从本地的目录提供不同的文件返回给客户端。

server {    
  listen   80;    
  server_name localhost;    
  location / {      
    root html;      
    index index.html index.htm;    
  }    
  error_page 500 502 503 504 /50x.html;    
  location = /50x.html {      
    root html;    
  }
} 

动静分离

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

动静分离

一般来说,都需要将动态资源和静态资源分开,由于 Nginx 的高并发和静态资源缓存等特性,经常将静态资源部署在 Nginx 上。如果请求的是静态资源,直接到静态资源目录获取资源,如果是动态资源的请求,则利用反向代理的原理,把请求转发给对应后台应用去处理,从而实现动静分离。

使用前后端分离后,可以很大程度提升静态资源的访问速度,即使动态服务不可用,静态资源的访问也不会受到影响。

反向代理

下面详细介绍

负载均衡

下面详细介绍

跨域问题

下面详细介绍

反向代理

概念

(1)正向代理:类似于跳板机,代理访问外部资源,类似于海外代购

(2)反向代理:将请求转发(重新发起请求)给内部网络的服务器,对外表现为一个服务器(保证内网的安全,阻止web攻击),类似于明星经纪人

img

区别可以简单概括为:

正向代理与反向代理

作用

(1)实现动态Web应用程序

(2)负载均衡

(3)保护服务器内网的真实IP地址

配置实例

实际使用中,可以将请求转发到本机另一个服务器上,也可以根据访问的路径跳转到不同端口的服务中。

比如我们监听 9001 端口,然后把访问不同路径的请求进行反向代理:

  1. 把访问 http://127.0.0.1:9001/edu 的请求转发到 http://127.0.0.1:8080
  2. 把访问 http://127.0.0.1:9001/vod 的请求转发到 http://127.0.0.1:8081

这种要怎么配置呢,首先同样打开主配置文件,然后在 http 模块下增加一个 server 块:

server {
  listen 9001;
  server_name *.sherlocked93.club;

  location ~ /edu/ {
    proxy_pass http://127.0.0.1:8080;
  }
  
  location ~ /vod/ {
    proxy_pass http://127.0.0.1:8081;
  }
}
复制代码

反向代理还有一些其他的指令,可以了解一下:

  1. proxy_set_header:在将客户端请求发送给后端服务器之前,更改来自客户端的请求头信息。
  2. proxy_connect_timeout:配置Nginx与后端代理服务器尝试建立连接的超时时间。
  3. proxy_read_timeout:配置Nginx向后端服务器组发出read请求后,等待相应的超时时间。
  4. proxy_send_timeout:配置Nginx向后端服务器组发出write请求后,等待相应的超时时间。
  5. proxy_redirect:用于修改后端服务器返回的响应头中的Location和Refresh。

负载均衡

概念

负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。

负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务

img

分类

Nginx负载平衡实际上是反向代理的一种。

upstream 指令进行负载均衡配置。

HTTP 负载均衡

(1)默认算法:Round Robin(轮询)

http {  
  upstream ub {     
    server 10.117.0.1:3010;     
    server 10.117.0.2:3010;     
    server 10.117.0.3:3010;  
  }    
 server {     
    location / {         
      proxy_pass http://ub; 
    }  
  }
}

Round Robin(轮询)还可以加上服务器权重

http {  
  upstream ub {     
    server 10.117.0.1:3010 weight =5;     
    server 10.117.0.2:3010 weight =3;     
    server 10.117.0.3:3010 weight =1;  
  }    
  server {     
    location / {         
      proxy_pass http://ub; 
    }  
  }
}

解释:服务器收到请求数的比重是 5:3:1

(2)Least Connections(最少连接数)

http {   
  upstream ub {       
    least_conn;       
      server 10.117.0.1:3010;       
    	server 10.117.0.2:3010;       
    	server 10.117.0.3:3010;   
  }
  server {
    location / {
      proxy_pass http://ub;
    }
  }
}

(3)Least Time(最短时间)【仅适用于 NGINX Plus】

http {  
  upstream ub {     
    hash $request_uri consistent;     
    server 10.117.0.1:3010;     
    server 10.117.0.2:3010;     
    server 10.117.0.3:3010;  
  }    
  server {     
    location / {         
      proxy_pass http://ub; 
    }  
  }
}

注:肯定比上面的都好使,毕竟是 NGINX Plus 才有的收费功能。

(4)IP Hash(IP哈希)

http {  
  upstream ub {     
    ip_hash;     
    server10.117.0.1:3010;     
    server10.117.0.2:3010;     
    server10.117.0.3:3010;  
  }    
  server {     
    location / {        
      proxy_pass http://ub; 
    }  
  }
}

(5)Generic Hash(通用哈希)

http {  
  upstream ub {     
    hash $request_uri consistent;     
    server 10.117.0.1:3010;     
    server 10.117.0.2:3010;     
    server 10.117.0.3:3010;  
  }    
  server {     
    location / {         
      proxy_pass http://ub; 
    }  
  }
}

解释:等于把上面 ip hash 变成了 $request_uri hash。

TCP 负载均衡

nginx 开源版 1.9.0 支持 TCP 负载平衡。

(1)写法

stream{
  upstream backend{ 
    server 127.0.0.1:8089; 
    server 127.0.0.2:1935; 
    server 127.0.0.3:1935; 
  }
  server{ 
    listen 80; 
    proxy_pass backend; }
}

· 跟 HTTP 负载均衡写法的异同:

· stream block 取代 http block(stream 表示 TCP/UDP 流量

· upstream 写法不变

· proxy_pass 属于 server 而不是 location,server 也不存在 location。

(2)优缺点

· 优点:性能好。直接转发原始TCP数据包,没有数据解析;如果是 HTTPS ,也免去了 SSL 层的损耗。

· 缺点:功能损失。例如无法通过 proxy_set_header 改写/注入 HTTP 标头

[拓展] 既然 proxy_set_header 无法用,那 TCP 代理怎么传递客户端的原始 IP 信息呢?

可以使用 proxy protocol。

proxy protocol 是 HAProxy 的作者 Willy Tarreau 于 2010 年开发和设计的一个 Internet 协议,通过为 tcp 添加一个很小的头信息,来方便的传递客户端信息(协议栈、源IP、目的IP、源端口、目的端口等)。其本质是在三次握手结束后由代理在连接中插入了一个携带了原始连接四元组信息的数据包。

具体例子参考:https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/

proxy protocol 也可以用在 HTTP 负载均衡上。

邮件协议的负载均衡

# 邮件流量

mail{}

宕机轮训配置规则

server {    
  listen    80;    
  server_name  www.itmayiedu.com;    
  location / {      
    proxy_pass  http://backserver;      
    index  index.html index.htm;      
    proxy_connect_timeout 1;      
    proxy_send_timeout 1;      
    proxy_read_timeout 1;    
  }
}

Nginx解决跨域问题

img

Tomcat同一个服务器,在jsp页面或其他java代码跳转页面时,域名必须相同(同一个web应用),用nginx搭建网关系统,可实现跨域跳转。

使用反向代理解决跨域

在前端服务地址为 fe.sherlocked93.club 的页面请求 be.sherlocked93.club 的后端服务导致的跨域,可以这样配置:

server {
  listen 9001;
  server_name fe.sherlocked93.club;

  location / {
    proxy_pass be.sherlocked93.club;
  }
}

这样就将对前一个域名 fe.sherlocked93.club 的请求全都代理到了 be.sherlocked93.club,前端的请求都被我们用服务器代理到了后端地址下,绕过了跨域。

这里对静态文件的请求和后端服务的请求都以 fe.sherlocked93.club 开始,不易区分,所以为了实现对后端服务请求的统一转发,通常我们会约定对后端服务的请求加上 /apis/ 前缀或者其他的 path 来和对静态资源的请求加以区分,此时我们可以这样配置:

# 请求跨域,约定代理后端服务请求path以/apis/开头
location ^~/apis/ {
    # 这里重写了请求,将正则匹配中的第一个分组的path拼接到真正的请求后面,并用break停止后续匹配
    rewrite ^/apis/(.*)$ /$1 break;
    proxy_pass be.sherlocked93.club;
  
    # 两个域名之间cookie的传递与回写
    proxy_cookie_domain be.sherlocked93.club fe.sherlocked93.club;
}

这样,静态资源我们使用 fe.sherlocked93.club/xx.html,动态资源我们使用 fe.sherlocked93.club/apis/getAwo,浏览器页面看起来仍然访问的前端服务器,绕过了浏览器的同源策略,毕竟我们看起来并没有跨域。

也可以统一一点,直接把前后端服务器地址直接都转发到另一个 server.sherlocked93.club,只通过在后面添加的 path 来区分请求的是静态资源还是后端服务,看需求了。

配置 header 解决跨域

当浏览器在访问跨源的服务器时,也可以在跨域的服务器上直接设置 Nginx,从而前端就可以无感地开发,不用把实际上访问后端的地址改成前端服务的地址,这样可适性更高。

比如前端站点是 fe.sherlocked93.club,这个地址下的前端页面请求 be.sherlocked93.club 下的资源,比如前者的 fe.sherlocked93.club/index.html 内容是这样的:

<html>
<body>
    <h1>welcome fe.sherlocked93.club!!<h1>
    <script type='text/javascript'>
    var xmlhttp = new XMLHttpRequest()
    xmlhttp.open("GET", "http://be.sherlocked93.club/index.html", true);
    xmlhttp.send();
    </script>
</body>
</html>

很明显这里是跨域请求,在浏览器中直接访问 http://be.sherlocked93.club/index.html 是可以访问到的,但是在 fe.sherlocked93.club 的 html 页面访问就会出现跨域。

/etc/nginx/conf.d/ (mac下是/usr/local/etc/nginx/servers)文件夹中新建一个配置文件,对应二级域名 be.sherlocked93.club

# be.sherlocked93.club.conf

server {
  listen       80;
  server_name  be.sherlocked93.club;
  
	add_header 'Access-Control-Allow-Origin' $http_origin;   # 全局变量获得当前请求origin,带cookie的请求不支持*
	add_header 'Access-Control-Allow-Credentials' 'true';    # 为 true 可带上 cookie
	add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';  # 允许请求方法
	add_header 'Access-Control-Allow-Headers' $http_access_control_request_headers;  # 允许请求的 header,可以为 *
	add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
	
  if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Max-Age' 1728000;   # OPTIONS 请求的有效期,在有效期内不用发出另一条预检请求
		add_header 'Content-Type' 'text/plain; charset=utf-8';
		add_header 'Content-Length' 0;
    
		return 204;                  # 200 也可以
	}
  
	location / {
		root  /usr/share/nginx/html/be;
		index index.html;
	}
}

重写

概念

rewrite 是 nginx 的重写模块,即ngx_http_rewrite_module。主要功能是改写请求URI,是Nginx默认安装的模块。rewrite模块会根据PCRE正则匹配重写URI,然后发起内部跳转再匹配location,或者直接做30x重定向返回客户端。

目的

· 通知用户他们正在请求的资源现在位于其他位置

· 控制处理流程等等

涉及命令

· return 和 rewrite,之前介绍的 try_files 也可以部分做到

· 重写模块同时也涉及了 break,if,set 等其它命令

return

(1)介绍

· 语法:

return URL; # 外部重定向return code URL;return code [text];

可以将 return 指令放置在 server 或 location 中。

(2)demo

return https: //baidu.com; # 默认 302
return 301 https: //baidu.com; # 必须是支持重定向的响应码,比如 200 就不行
return 200 "okokok"; # 修改不了响应行文本,原因未知

rewrite

(1)介绍

语法:rewrite regex replacement [flag];

可以将 rewrite 指令放置在 server 或 location 中。

(2)参数

① regex 为正则表达式

② flag 取值如下:

img

注意,rewrite 后 url 就会变了,下一个 rewrite 识别的就是改过的 url

③ replacement 为重写的值

如果 replacement 以协议头开头(如:http://,https:// 或 $scheme),则效果相当于 flag = redirect。

如果想在 replacement 中抛弃之前路径的请求参数,可以在最后加了个 ?,如

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

(3)demo

以 flag = 无 为例:

location / {rewrite ^/user/(.*)$ /show/$1;rewrite ^/show/(.*)$ /hide/$1;}location /show {return200;}location /hide {return201;}

访问 https://example.com/user/a.jpg

1、/user/a.jpg 被 location / 捕获

2、第一个 rewrite 把 /user/a.jpg 改写成 /show/a.jpg

注意,这时的路径已经被改写成 /show/a.jpg 了。

3、第二个 rewrite 把 /show/a.jpg 改写成 /hide/a.jpg

4、下面没有命令了,执行内部重定向

5、/hide/a.jpg 被 location /hide 捕获,返回 201

注:诸如 $1 和 $2 这种变量,表示正则表达式匹配的第 N 个参数.

(4)死循环

某些情况下,rewrite 重定向后,可能又会执行 rewrite,然后循环往复,进入死循环。

为了避免这种情况,nginx 会在循环 10 次时之后,直接返回 500 异常

其他命令

(1)set —— 设置变量

set $var1 "hello world";return 200 "response ok $var1";

(2)if —— 判断条件

if 比 rewrite 的正则匹配更灵活。

实例

注意:rewrite 因为有正则,所以比 return 更加影响性能(if 语句也如是),且可读性差,所以如果能用 return 就用 return。

(1)从旧网址重定向到新网址

server{
  listen 80;
  listen 443 ssl;
  server_name www.old-name.com old-name.com;
  return 301 $scheme://www.new-name.com$request_uri;# 不推荐rewrite ^$scheme://www.new-name.com$request_uri permanent; 
}

(2)强制所有请求使用 HTTPS

server{   
  listen   80;
  server_name www.domain.com;
  return 301 https://www.domain.com$request_uri;# 不推荐
  if($scheme!="https") { 
    rewrite ^ https://www.mydomain.com$request_uri permanent; 
  }
}

(3)添加/删除 www 前缀

# add 
'www'server{
  listen 80;
  listen 443 ssl;
  server_name domain.com;
  return 301 $scheme://www.domain.com$request_uri;}
# remove 
'www'server{
  listen 80;
  listen 443 ssl;
  server_name www.domain.com;
  return 301 $scheme://domain.com$request_uri;
}

(4)兜底,把其它流量重定向到正确的域名 or 返回错误

server{
  listen 80 default_server;
  listen 443 ssl default_server;server_name_;
  return 301 $scheme://www.domain.com;# orreturn 444
}

Nginx的其他用法

nginx 禁止 / 允许IP 访问

使用到 ngx_http_access_module 模块

deny,相反的为 allow

location / {
            root   html; # 网站根目录
            index  index.html index.htm; # 默认首页文件
            deny 172.168.22.11;   # 禁止访问的ip地址,可以为all
    	      allow 172.168.33.44; # 允许访问的ip地址,可以为all
        }

原理:通过 $remote_addr 来判断。

在需要很多规则的情况下,最好使用 ngx_http_geo_module 模块。

结果:返回 403。

错误处理

error_page

(1)常见 HTTP (响应码)错误

· 403 Forbidden

· 404 Not Found

· 500 Internal Server Error 通常是 upstream server 返回的错误

· 502 Bad Gateway 通常是 nginx 无法到达 upstream server

· 503 Service Unavailable 通常是 nginx 因暂时超载或临时维护,无法处理HTTP请求

· 504 gateway timeout 通常是 upstream server 返回超时

(2)用法

error_page 可以位于 server block / location block

原理:通过内部重定向。(跟上面介绍的 index 指令 一样)

① 针对普通情况

基本:

# 指向错误页面
error_page 404/404.html;
error_page 500 502 503 504 /50x.html;
# 重定向到外部 
urlerror_page 500 http://www.google.com; 
# 重定向到 named 
location blocklocation/ {
  error_page 404= @fallback;
}
location @fallback{
  proxy_pass http://different_backend;
}

注1:因为 error_page 是通过内部重定向,所以你可以显示地写一个与之对应的 location (如 location /404.html)来干更多事。

注2:因为 error_page 是通过内部重定向,所以 access 日志会有两条记录。

高级:

# 更改HTTP状态码(不推荐,这样 nginx 日志记录也是)error_page500=200/index.html

② 针对反向代理(使用 proxy_intercept_errors,error_page 才会生效)

location @rails {
  proxy_pass http://rails_app;
  proxy_intercept_errors on; # focus here
  error_page 404/404.html;
}

Nginx防盗链

server {
  listen       80;        
  server_name  *.sherlocked93.club;
  
  # 图片防盗链
  location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
    valid_referers none blocked server_names ~\.google\. ~\.baidu\. *.qq.com;  # 只允许本机 IP 外链引用,感谢 @木法传 的提醒,将百度和谷歌也加入白名单
    if ($invalid_referer){
      return 403;
    }
  }
}

适配 PC 或移动设备

根据用户设备不同返回不同样式的站点,以前经常使用的是纯前端的自适应布局,但无论是复杂性和易用性上面还是不如分开编写的好,比如我们常见的淘宝、京东……这些大型网站就都没有采用自适应,而是用分开制作的方式,根据用户请求的 user-agent 来判断是返回 PC 还是 H5 站点。

首先在 /usr/share/nginx/html 文件夹下 mkdir 分别新建两个文件夹 PCmobilevim 编辑两个 index.html 随便写点内容。

cd /usr/share/nginx/html
mkdir pc mobile
cd pc
vim index.html   # 随便写点比如 hello pc!
cd ../mobile
vim index.html   # 随便写点比如 hello mobile!

然后和设置二级域名虚拟主机时候一样,去 /etc/nginx/conf.d 文件夹下新建一个配置文件 fe.sherlocked93.club.conf

# /etc/nginx/conf.d/fe.sherlocked93.club.conf

server {
  listen 80;
	server_name fe.sherlocked93.club;

	location / {
		root  /usr/share/nginx/html/pc;
    if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
      root /usr/share/nginx/html/mobile;
    }
		index index.html;
	}
}

配置基本没什么不一样的,主要多了一个 if 语句,然后使用 $http_user_agent 全局变量来判断用户请求的 user-agent,指向不同的 root 路径,返回对应站点

Nginx配置高可用

当主 Nginx 服务器宕机之后,切换到备份 Nginx 服务器

先安装keepalived,然后编辑 /etc/keepalived/keepalived.conf 配置文件,并在配置文件中增加 vrrp_script 定义一个外围检测机制,并在 vrrp_instance 中通过定义 track_script 来追踪脚本执行过程,实现节点转移:

global_defs{
   notification_email {
        acassen@firewall.loc
   }
   notification_email_from Alexandre@firewall.loc
   smtp_server 127.0.0.1
   smtp_connect_timeout 30 // 上面都是邮件配置,没卵用
   router_id LVS_DEVEL     // 当前服务器名字,用hostname命令来查看
}
vrrp_script chk_maintainace { // 检测机制的脚本名称为chk_maintainace
    script "[[ -e/etc/keepalived/down ]] && exit 1 || exit 0" // 可以是脚本路径或脚本命令
    // script "/etc/keepalived/nginx_check.sh"    // 比如这样的脚本路径
    interval 2  // 每隔2秒检测一次
    weight -20  // 当脚本执行成立,那么把当前服务器优先级改为-20
}
vrrp_instanceVI_1 {   // 每一个vrrp_instance就是定义一个虚拟路由器
    state MASTER      // 主机为MASTER,备用机为BACKUP
    interface eth0    // 网卡名字,可以从ifconfig中查找
    virtual_router_id 51 // 虚拟路由的id号,一般小于255,主备机id需要一样
    priority 100      // 优先级,master的优先级比backup的大
    advert_int 1      // 默认心跳间隔
    authentication {  // 认证机制
        auth_type PASS
        auth_pass 1111   // 密码
    }
    virtual_ipaddress {  // 虚拟地址vip
       172.16.2.8
    }
}

其中检测脚本 nginx_check.sh,这里提供一个:

#!/bin/bash
A=`ps -C nginx --no-header | wc -l`
if [ $A -eq 0 ];then
    /usr/sbin/nginx # 尝试重新启动nginx
    sleep 2         # 睡眠2秒
    if [ `ps -C nginx --no-header | wc -l` -eq 0 ];then
        killall keepalived # 启动失败,将keepalived服务杀死。将vip漂移到其它备份节点
    fi
fi

复制一份到备份服务器,备份 Nginx 的配置要将 state 后改为 BACKUPpriority 改为比主机小。

设置完毕后各自 service keepalived start 启动,经过访问成功之后,可以把 Master 机的 keepalived 停掉,此时 Master 机就不再是主机了 service keepalived stop,看访问虚拟 IP 时是否能够自动切换到备机 ip addr

再次启动 Master 的 keepalived,此时 vip 又变到了主机上。

一个HTTP到Nginx处理的过程

img

对比F5

F5的负载均衡功能

其实看到Nginx的原理和功能,是不是觉得已经不需要F5了?当然也不是,F5毕竟是负载均衡的老前辈,一直以来都以功能强大,性能稳定著称,很多功能其实是软负载无法做到的。

F5 BIG-IP用作HTTP负载均衡器的主要功能:

(1)F5 BIG-IP提供12种灵活的算法将所有流量均衡的分配到各个服务器,而面对用户,只是一台虚拟服务器。

(2)F5 BIG-IP可以确认应用程序能否对请求返回对应的数据。假如F5 BIG-IP后面的某一台服务器发生服务停止、死机等故障,F5会检查出来并将该服务器标识为宕机,从而不将用户的访问请求传送到该台发生故障的服务器上。这样,只要其它的服务器正常,用户的访问就不会受到影响。宕机一旦修复,F5 BIG-IP就会自动查证应用保证对客户的请求作出正确响应并恢复向该服务器传送。

(3)F5 BIG-IP具有动态Session的会话保持功能,笔者也是在网站中使用的F5将用户IP与Session通过F5进行的绑定,使其Session保持一致。

(4)F5 BIG-IP的iRules功能可以做HTTP内容过滤,根据不同的域名、URL,将访问请求传送到不同的服务器。

对比

(1)F5,硬件

优点:能够直接通过智能交换机实现,处理能力更强,而且与系统无关,负载性能强,更适用于一大堆设备、大访问量、简单应用。

缺点:成本高,除设备价格高昂,而且配置冗余,很难想象后面服务器做一个集群,但最关键的负载均衡设备却是单点配置,无法有效掌握服务器及应用状态。

硬件负载均衡,一般都不管实际系统与应用的状态,而只是从网络层来判断,所以有时候系统处理能力已经不行了,但网络可能还来得及反应(这种情况非常典型,比如应用服务器后面内存已经占用很多,但还没有彻底不行,如果网络传输量不大就未必在网络层能反映出来)

(2)Nginx,软负载

优点:基于系统与应用的负载均衡,能够更好地根据系统与应用的状况来分配负载。这对于复杂应用是很重要的,性价比高,实际上如果几台服务器,用F5之类的硬件产品显得有些浪费,而用软件就要合算得多,因为服务器同时还可以跑应用、做集群等。


文章作者: 小小千千
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小小千千 !
评论
  目录