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

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
EMR Serverless StarRocks,5000CU*H 48000GB*H
简介:

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

http://douer.blog.51cto.com/6107588/1922682


七、Nginx之URL重写

1.URL重写模块(Rewrite)

摘要

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

指令

break

语法:break  
默认值:none  
使用字段:server, location, if  
完成当前设置的规则,停止执行其他的重写指令。  
示例:

1
2
3
4
if  ($slow) {
   limit_rate  10k;
   break ;
}

if

语法:if (condition) { … }  
默认值:none  
使用字段:server, location  
注意:在使用if指令之前请查看if is evil page并且尽量考虑用try_files代替。  
判断一个条件,如果条件成立,则后面的大括号内的语句将执行,相关配置从上级继承。  
可以在判断语句中指定下列值:

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

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

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

  • ~为区分大小写的匹配。

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

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

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
if  ($http_user_agent ~ MSIE) {
   rewrite  ^(.*)$  /msie/$1   break ;
}
                                                                                                                                                         
if  ($http_cookie ~*  "id=([^;] +)(?:;|$)"  ) {
   set  $id  $1;
}
                                                                                                                                                         
if  ($request_method = POST ) {
   return  405;
}
                                                                                                                                                         
if  (!-f $request_filename) {
   break ;
   proxy_pass  http: //127.0.0.1;
}
                                                                                                                                                         
if  ($slow) {
   limit_rate  10k;
}
                                                                                                                                                         
if  ($invalid_referer) {
   return    403;
}
                                                                                                                                                         
if  ($args ~ post=140){
   rewrite ^ http: //example.com/ permanent;
}

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

return

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

rewrite

语法:rewrite regex replacement flag  
默认值:none  
使用字段:server, location, if  
按照相关的正则表达式与字符串修改URI,指令按照在配置文件中出现的顺序执行。  
可以在重写指令后面添加标记。  
如果替换的字符串以http://开头,请求将被重定向,并且不再执行多余的rewrite指令。  
尾部的标记(flag)可以是以下的值:

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

  • break - 完成重写指令。

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

  • permanent - 返回301永久重定向。

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

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

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

1
2
3
4
5
location /download/ {
   rewrite  ^(/download/.*)/media/(.*)\..*$  $1/mp3/$2.mp3   break ;
   rewrite  ^(/download/.*)/audio/(.*)\..*$  $1/mp3/$2.ra    break ;
   return    403;
}

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

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

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

1
/photos/123456

为:

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

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

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

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

1
2
3
4
server {
    server_name www.example.com;
    rewrite ^ http: //example.com$request_uri? permanent;
}

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

1
2
3
if  ($args ^~ post=100){
   rewrite ^ http: //example.com/new-address.html? permanent;
}

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

rewrite_log

语法:rewrite_log on | off  
默认值:rewrite_log off  
使用字段:server, location, if  
变量:无  
启用时将在error log中记录notice 标记的重写日志。

set

语法:set variable value  
默认值:none  
使用字段:server, location, if  
指令设置一个变量并为其赋值,其值可以是文本,变量和它们的组合。  
你可以使用set定义一个新的变量,但是不能使用set设置$http_xxx头部变量的值。

uninitialized_variable_warn

语法:uninitialized_variable_warn on|off  
默认值:uninitialized_variable_warn on  
使用字段:http, server, location, if  
开启或关闭在未初始化变量中记录警告日志。  
事实上,rewrite指令在配置文件加载时已经编译到内部代码中,在解释器产生请求时使用。  
这个解释器是一个简单的堆栈虚拟机,如下列指令:

1
2
3
4
5
6
7
8
location /download/ {
   if  ($forbidden) {
     return    403;
   }
   if  ($slow) {
     limit_rate  10k;
   }
   rewrite  ^/(download/.*)/media/(.*)\..*$  /$1/mp3/$2.mp3   break ;

将被编译成以下顺序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
variable $forbidden
checking to zero
recovery 403
completion of entire code
variable $slow
checking to zero
checkings of regular excodession
copying  "/"
copying $1
copying  "/mp3/"
copying $2
copying  ".mp3"
completion of regular excodession
completion of entire sequence

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

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

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

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

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

之后的顺序类似如下:

1
2
3
4
5
6
7
checking regular excodession
copying $1
copying  "/mp3/"
copying $2
copying  ".mp3"
completion of regular excodession
completion of entire code

2.简单案例

注,由于配置文件内容较多,为了让大家看着方便,我们备份一下配置文件,打开一个新的配置文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@nginx ~] # cd /etc/nginx/
[root@nginx nginx] # mv nginx.conf nginx.conf.proxy
[root@nginx nginx] # cp nginx.conf.bak nginx.conf
[root@nginx nginx] # vim /etc/nginx/nginx.conf
server {
       listen       80;
       server_name  localhost;
       #charset koi8-r;
       #access_log  logs/host.access.log  main;
       location / {
           root   html;
           index  index.html index.htm;
           rewrite ^/bbs/(.*)$ http: //192.168.18.201/forum/$1;
       }
}

准备forum目录与测试文件

1
2
3
4
5
6
7
[root@web1 ~] # cd /var/www/html/
[root@web1 html] # ls
index.html
[root@web1 html] # mkdir forum
[root@web1 html] # cd forum/
[root@web1 forum] # vim index.html
<h1>forum page!</h1>

测试一下

t13

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

3.重新加载一下配置文件
1
2
3
4
[root@nginx 63] # service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新载入 nginx:                                           [确定]

4.测试一下

t14

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

5.配置永久重定向

1
2
3
4
5
6
7
8
9
10
11
12
[root@nginx nginx] # vim /etc/nginx/nginx.conf
server {
         listen       80;
         server_name  localhost;
         #charset koi8-r;
         #access_log  logs/host.access.log  main;
         location / {
             root   html;
             index  index.html index.htm;
             rewrite ^/bbs/(.*)$ /forum/$1;
         }
}

准备forum目录与测试文件

1
2
3
4
5
6
7
[root@nginx ~] # cd /usr/html/
[root@nginx html] # ls
50x.html  index.html
[root@nginx html] # mkdir forum
[root@nginx html] # cd forum/
[root@nginx forum] # vim index.html
<h1>192.168.18.208 forum page</h1>

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

1
2
3
4
[root@nginx ~] # service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新载入 nginx:                                           [确定]

7.测试一下

t16

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

八、Nginx之读写分离

1.实验拓扑

nginx3

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

2.WebDAV功能说明

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

3.修改配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@nginx nginx] # vim /etc/nginx/nginx.conf
server {
         listen       80;
         server_name  localhost;
         #charset koi8-r;
         #access_log  logs/host.access.log  main;
         location / {
                 proxy_pass http: //192.168.18.202;
                 if  ($request_method =  "PUT" ){
                         proxy_pass http: //192.168.18.201;
                 }
         }
}

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

1
2
3
4
[root@nginx ~] # service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新载入 nginx:                                           [确定]

5.配置httpd的WebDAV功能

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

t17

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

6.重新启动一下httpd

1
2
3
[root@web1 ~] # service httpd restart
停止 httpd:                                               [确定]
正在启动 httpd:                                           [确定]

7.测试一下

1
2
3
4
[root@nginx ~] # curl http://192.168.18.201
<h1>web1.test.com</h1>
[root@nginx ~] # curl http://192.168.18.202
<h1>web2.test.com</h1>

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

1
2
3
4
5
6
7
8
9
10
[root@nginx ~] # curl -T /etc/issue  http://192.168.18.202
<!DOCTYPE HTML PUBLIC  "-//IETF//DTD HTML 2.0//EN" >
<html><head>
<title>405 Method Not Allowed</title>
</head><body>
<h1>Method Not Allowed</h1>
The requested method PUT is not allowed  for  the URL /issue.
<hr>
<address>Apache/2.2.15 (CentOS) Server at 192.168.18.202 Port 80</address>
</body></html>

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

1
2
3
4
5
6
7
8
9
10
11
[root@nginx ~] # curl -T /etc/issue  http://192.168.18.201
<!DOCTYPE HTML PUBLIC  "-//IETF//DTD HTML 2.0//EN" >
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
You don't have permission to access /issue
on  this  server.
<hr>
<address>Apache/2.2.15 (CentOS) Server at 192.168.18.201 Port 80</address>
</body></html>

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

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

下面我们再来测试一下,

1
2
3
4
5
6
7
8
9
10
[root@nginx ~] # curl -T /etc/issue  http://192.168.18.201
<!DOCTYPE HTML PUBLIC  "-//IETF//DTD HTML 2.0//EN" >
<html><head>
<title>201 Created</title>
</head><body>
<h1>Created</h1>
Resource /issue has been created.
<hr />
<address>Apache/2.2.15 (CentOS) Server at 192.168.18.201 Port 80</address>
</body></html>

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

1
2
3
4
5
6
[root@web1 ~] # cd /var/www/html/
[root@web1 html] # ll
总用量 12
drwxr-xr-x 2 root   root   4096 9月   4 13:16 forum
-rw-r--r-- 1 root   root     23 9月   3 23:37 index.html
-rw-r--r-- 1 apache apache   47 9月   4 14:06 issue

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


本文出自 “Share your knowledge …” 博客,请务必保留此出处http://freeloda.blog.51cto.com/2033581/1288553






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





相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
11天前
|
负载均衡 算法 搜索推荐
Nginx 常用的负载均衡算法
【10月更文挑战第17天】在实际应用中,我们需要根据具体的情况来选择合适的负载均衡算法。同时,还可以结合其他的优化措施,如服务器健康检查、动态调整权重等,来进一步提高负载均衡的效果和系统的稳定性。
105 59
|
7天前
|
负载均衡 算法 应用服务中间件
Nginx 常用的负载均衡算法
【10月更文挑战第22天】不同的负载均衡算法各有特点和适用场景。在实际应用中,需要根据具体的业务需求、服务器性能和网络环境等因素来选择合适的算法。
19 3
|
11天前
|
负载均衡 监控 应用服务中间件
除了 Nginx,还有以下一些常见的负载均衡工具
【10月更文挑战第17天】这些负载均衡工具各有特点和优势,在不同的应用场景中发挥着重要作用。选择合适的负载均衡工具需要综合考虑性能、功能、稳定性、成本等因素。
|
20天前
|
负载均衡 应用服务中间件 nginx
Nginx的6大负载均衡策略及权重轮询手写配置
【10月更文挑战第9天】 Nginx是一款高性能的HTTP服务器和反向代理服务器,它在处理大量并发请求时表现出色。Nginx的负载均衡功能可以将请求分发到多个服务器,提高网站的吞吐量和可靠性。以下是Nginx支持的6大负载均衡策略:
102 7
|
18天前
|
负载均衡 算法 Java
腾讯面试:说说6大Nginx负载均衡?手写一下权重轮询策略?
尼恩,一位资深架构师,分享了关于负载均衡及其策略的深入解析,特别是基于权重的负载均衡策略。文章不仅介绍了Nginx的五大负载均衡策略,如轮询、加权轮询、IP哈希、最少连接数等,还提供了手写加权轮询算法的Java实现示例。通过这些内容,尼恩帮助读者系统化理解负载均衡技术,提升面试竞争力,实现技术上的“肌肉展示”。此外,他还提供了丰富的技术资料和面试指导,助力求职者在大厂面试中脱颖而出。
腾讯面试:说说6大Nginx负载均衡?手写一下权重轮询策略?
|
29天前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
65 1
|
29天前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
40 2
数据的存储--Redis缓存存储(二)
|
25天前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
57 6
|
30天前
|
缓存 NoSQL 关系型数据库
redis和缓存及相关问题和解决办法 什么是缓存预热、缓存穿透、缓存雪崩、缓存击穿
本文深入探讨了Redis缓存的相关知识,包括缓存的概念、使用场景、可能出现的问题(缓存预热、缓存穿透、缓存雪崩、缓存击穿)及其解决方案。
139 0
redis和缓存及相关问题和解决办法 什么是缓存预热、缓存穿透、缓存雪崩、缓存击穿
|
2天前
|
缓存 NoSQL Redis
Redis 缓存使用的实践
《Redis缓存最佳实践指南》涵盖缓存更新策略、缓存击穿防护、大key处理和性能优化。包括Cache Aside Pattern、Write Through、分布式锁、大key拆分和批量操作等技术,帮助你在项目中高效使用Redis缓存。
46 22