nginx使用篇-核心功能
1.Nginx概述
1.1Nginx 简介
nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定,所以现在很多知名的公司都在使用nginx。
2004 年 10 月发布第一个版本。国内大型的站点,例如百度、京东、新浪、网易、腾讯、淘宝等,都使用了 Nginx。
1.2代理服务器
代理服务器根据其代理对象的不同,可以分为正向代理服务器与反向代理服务器。这里
的“正”与“反”均是站在客户端角度来说的。
1.2.1正向代理
正向代理是对客户端的代理。客户端 C 想要从服务端 S 获取资源,但由于某些原因不能直接访问服务端,而是通过另外一台主机 P 向服务端发送请求。当服务端处理完毕请求后,将响应发送给主机 P,主机 P 在接收到来自服务端的响应后,将响应又转给了客户端 C。此时的主机 P,就称为客户端 C 的正向代理服务器。
客户端在使用正向代理服务器时是知道其要访问的目标服务器的地址等信息的。正向代理服务器是服务器的用户(客户端)架设的主机,与服务端无关,正向代理服务器的出现,使服务端根本就不知道真正客户端的存在。
正向代理优点:
-
隐藏
向服务端隐藏真正的访问者。因为,对于服务端来说,真正的访问者,真正的客户端是正向代理服务器,服务端是不知道正向代理服务器的访问者的。所以起到了隐藏客户端的作用。例如,现在的很多电信诈骗电话,都是使用了代理服务器。我们看到的来电显示电话号码,其实并不是诈骗者真正使用的电话号码。诈骗者真正拨打的是正向代理服务器的电话,由代理服务器拨通了我们的电话。
-
FQ
由于某些原因,客户端 C 不能直接访问服务端 S,但客户端 C 可以直接访问代理服务器P,而代理服务器 P 可以直接访问服务器 S,所以,客户端通过代理服务器 P 实现对服务端 S的访问,这种技术称为“FQ”。
例如,我们想通过“Google 学术”下载一些学术论文,由于政策原因,我们不能直接
访问 Google。 此时,我们可能通过一些FQ软件,在软件中我们可以访问 Google。但,在使用软件之前,需要首先在软件中输入我们要连接的正向代理服务器的 IP 地址,连接上这个服务器
- 提速
若客户端直接访问服务端,其是通过一个低速网络链路,其访问效率较低。但客户端访问另一主机 P,及该主机 P 访问服务端,它们所使用的链路均为高速链路。此时,就可将这台主机 P 构建为一个正向代理服务器。通过该代理服务器访问服务端的效率,比直接访问的效率还要高。
- 缓存
若客户端从服务端以获取资源为主,则可在客户端与服务端之间添加具有缓存功能的正向代理服务器。当一个客户端从服务器获取某资源时,首先查看代理服务器中是否具有该资源。若具有该资源,则直接从代理服务器获取资源即可;若不具有该资源,则再由代理服务器向服务端发送资源请求,将资源获取到后,缓存到正向代理服务器中,并返回给客户端。以后再有客户端提交获取该资源的请求时,直接从代理服务器中获取即可。不仅加快了对客户端的响应速度,增强了用户体验,而且还减轻了服务端的压力,提高的整个系统的执行效率。
Maven 的 Nexus 私服就是一个典型的用于“缓存”功能的正向代理服务器。
- 授权
比较典型的授权应用是,在公司内部局域网中,不是所有人的电脑都是可以连接外网的。那么公司是怎样实现外网访问权限管理的呢?在公司局域网与外网之间架设一道防火墙,而在正向代理服务器中设置公司局域网内的连接外网权限,即向防火墙中添加新的规则,以实现能否通过防火墙。
1.2.2反向代理
反向代理 Reverse Proxy, 是对服务端的代理。单从功能示意图上看,好像反向代理与正向代理没有区别,都是架设在客户端与服务端间的主机。但,反向代理是服务端架设的主机,与客户端无关。客户端认为其访问的是服务器本身,但其真正访问是反向代理服务器。客户端在使用反向代理服务器时,根本就不知道自己真正要访问的目标服务器的地址及信息,所有的访问都是通过代理完成的。这点上是与正向代理服务器不同的。
-
保护隐藏
客户端只能访问到反向代理服务器,而真正的服务器客户端是不能直接访问的。这样就起到了保护和隐藏真正服务器的目的。
-
负载均衡
当客户端访问较集中时,会产生高并发问题。对于分布式服务器系统,反向代理可以根据请求功能的不同,将请求转发给相应的服务器;对于集群服务器系统,反向代理可以根据各服务器的负载量,将请求转发给负载较轻的服务器。而这些,都是起到了负载均衡的效果。
- 动静分离
动态资源是指,需要经过服务端代码运算后才可形成的资源。例如, JSP 页面就是动态资源,因为页面中的数据是由服务端从 DB 中查询出来的。静态资源是指不会发生改变的资源,例如,页面中的图片、音频、视频、 CSS、 JS 等资源文件,均为静态资源。反向代理服务器直接将动态资源请求与静态资源请求进行了分离,降低了应用服务器的压力。
- 数据缓存
反向代理也具有数据缓存的功能。例如,将客户端请求的静态资源缓存到代理服务器中。当再有相同资源请求时,直接从代理服务器中获取该资源即可。
1.3Nginx 的特点
-
并发
-
低消耗
-
热部署
-
高扩展
-
高可用
1.4nginx 的 web 请求处理机制
Nginx 结合多进程机制和异步机制对外提供服务, 异步机制使用的是异步非阻塞方式。Nginx 的 master 进程会生成多个 worker 进程, master 进程负责管理这些 worker 进程的生命周期、接受外部命令、解析 perl 脚本等。而 worker 进程则用于接收和处理客户端请求。
每个 worker 进程能够使用异步非阻塞方式处理多个客户端请求。当某个 worker 进程接收到客户端的请求以后,其会调用 IO 进行处理, 如果不能立即得到结果, worker 进程就去处理其他的请求。 当 IO 返回结果后, 就会通知 worker 进程,而 worker 进程得到通知后,就会挂起当前正在处理的事务,拿 IO 返回结果去响应客户端请求。worker 进程采用的是 epoll事件驱动模型与 IO 进行通信的。 epoll 模型底层采用的是“回调 callback”替代了轮询,使效率要高于 select 模型。
2.Nginx请求定位
2.1nginx.conf文件的结构
在安装目录/usr/local/nginx/conf/nginx.conf
nginx的配置由特定的标识符(指令符)分为多个不同的模块。
指令符分为简单指令和块指令。
- 简单指令格式:[name parameters;]
- 块指令格式:和简单指令格式有一样的结构,但其结束标识符不是分号,而是大括号{},块指令内部可以包含simple directives 和block directives, 可以称块指令为上下文(e.g. events, http, server, location)
conf文件中,所有不属于块指令的简单指令都属于main上下文的,http块指令属于main上下文,server块指令http上下文。
location,请求定位模块。用于设置“访问路径”所对应的“真实资源路径”。 location
后跟的就是访问路径,该路径的参照路径为下面 root 属性指定的路径。 location 模块中常见
的属性有两个: root 与 index
-
root:用于指定请求路径的参照路径,该路径是 Linux 系统中真实存在的。可以是不以
斜杠开头的相对路径,也可以是以斜杠开头的 Linux 系统绝对路径。该路径可以是任意
目录,不一定非要是 Nginx 安装目录中的目录 -
index:用于指定默认访问资源文件。若客户端浏览器发送来的请求路径只包含 location
后指定的虚拟访问路径,而未指定具体的资源名称,则系统会从 index 属性指定的文件
中逐个查找,直到找到一个为止。若找不到,则报 404。
2.2访问资源入门
注意在才开始的使用过程如果调试出现404可以在logs目录下查看error.log,它会打印你的请求Url和Root最后拼接的路径,有助于解决问题
2.2.1修改配置文件
2.2.2 创建资源目录
在真实目录中,必须要在 root 属性指定的目录下存在 location 指定的 URI 路径目录。(目录可以是相对目录路径也可以是绝对路径),所以上面的实例我们需要在/usr/local/nginx目录下创建iss目录,并创建访问目录/iss
[root@localhost iss]# pwd
/usr/local/nginx/iss/iss
[root@localhost iss]# ll
总用量 4
-rw-r--r--. 1 root root 19 7月 13 08:48 index.html
注意上面是两层iss,一个是root对应的iss目录,一个是location访问的iss
效果如下(如果是中文可能会乱码),解决方案详解:https://blog.csdn.net/niugang0920/article/details/95722434
3.Nginx静态代理
Nginx 静态代理是指,将所有的静态资源,例如, css、 js、 html、 jpg 等资源存放到 Nginx服务器,而不存放在应用服务器 Tomcat 中。当客户端发出的请求是对这些静态资源的请求时, Nginx 直接将这些静态资源响应给客户端,而无需提交给应用服务器处理。这样就降低了应用服务器的压力。
同时, Nginx 对于静态资源的处理较 Tomcat,性能更好,效率更高,所以,在实际生产环境下,会使用 Nginx 作为静态代理服务器,专门处理静态资源的响应。Nginx 对于静态资源请求的拦截方式,可以通过静态资源名称的扩展名拦截,也可以通过静态资源所在的目录名称拦截。
3.1 修改配置
#访问静态资源
location ~ .*\.(css|js|jpg|png)$ {
root images;
}
location 后的~表示正则表达式开始, $表示正则表达式结束; .*中的.号表示正则表达式中的任意字符,而则为正则表达式中的 0 个或多个; .则为转义字符,表示要匹配字符串内容中的.号;(css|js|html|jpg|png)表示指定扩展名中的任意一个。所以,该 location 指定的 URI 为所有以.css、 .js、 .html、 .jpg、 .png 结尾的请求。
~与.间有无空格均可。
3.2 上传静态文件
在nginx安装目录下,创建images文件夹,路径为:
[root@localhost images]# pwd
/usr/local/nginx/images
并上传一张图片
[root@localhost images]# ll
总用量 116
-rw-r--r--. 1 root root 116024 6月 3 09:55 alipay.jpg
重启nginx:
nginx -s reload
浏览器访问:
3.2 注意
如果将配置改为
在之前的基础上添加的html,那么之前配置的iss/index.html,就会报404
因为该请求所请求的资源为 html 后辍文件,根据静态代理的配置,对于 html 静态资源的查找,会到/images的目录中查找 iss/index.html资源,当然是不存在的。所以会报出 404 异常。
现在我们在images下新建iss文件夹,新建index.html
[root@localhost iss]# pwd
/usr/local/nginx/images/iss
[root@localhost iss]# echo "nginx静态代理配置">index.html
[root@localhost iss]# ll
总用量 4
-rw-r--r--. 1 root root 24 7月 15 14:04 index.html
重启nginx,再次访问:
3.2目录名拦截
3.2.1修改配置文件
#基于目录拦截的
location ~.*(css|js|images).+ {
root static;
}
由于这里的 css、 js、 images 表示的是目录,所以(css|js|images)后不能添加$,但需要添加.+,表示其后一定有字符。因为目录的后台还会有静态资源名称。
其中.号表示正则表达式中的任意字符,而+表示前面的字符出现至少一次。
3.2.2创建对应的目录
为了演示方便在nginx的安装目录下新建static文件下,里面创建三个目录,分别是css,js,images文件夹,用于存放静态文件。
[root@localhost static]# pwd
/usr/local/nginx/static
[root@localhost static]# ll
总用量 0
drwxr-xr-x. 2 root root 6 7月 15 20:19 css
drwxr-xr-x. 3 root root 35 7月 15 14:02 images
drwxr-xr-x. 2 root root 6 7月 15 20:19 js
3.3.3重启nginx查看效果
4.负载均衡
4.1负载均衡简介
负载均衡, Load Balancing,就是将对请求的处理分摊到多个操作单元上进行。这个均衡是指在大批量访问前提下的一种基本均衡,并非是绝对的平均。
对于 Web 工程中的负载均衡,就是将相同的 Web 应用部署到多个不同的 Web 服务器上,形成多个 Web 应用服务器。当请求到来时,由负载均衡服务器负责将请求按照事先设定好的比例向 Web 应用服务器进行分发,从而增加系统的整体吞吐量。
-
硬件负载均衡
硬件负载均衡器的性能稳定,且有生产厂商作为专业的服务团队。但其成本很高,一台硬件负载均衡器的价格一般都在十几万到几十万,甚至上百万。知名的负载均衡器有 F5、Array、深信服、梭子鱼等。
-
软件负载均衡
软件负载均衡成本几乎为零,基本都是开源软件。例如, LVS、 HAProxy、 Nginx 等。
4.2 演示总体介绍
集群一共三台用Vmware构建的虚拟机,一台用于部署nginx,另外两台部署springboot演示程序。
4.2.1安装jdk
另外两台部署springboot应用程序的服务器需要安装jdk.
注意:在安装之前需要查看系统是否已经安装了open jdk.
- 查看是否安装的jdk
rpm -qa|grep jdk
- 卸载已经安装的jdk
yum -y remove 上面输出的结果
核心配置如下:
- 编辑/ect/profile
vim /etc/profile
- 添加如下内容
export JAVA_HOME=/usr/local/jdk1.8.0_211
export PATH=$PATH:$JAVA_HOME/bin
- 让配置生效
source /etc/proifile
- 查看jdk版本
[root@localhost ~]# java -version
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
4.2.2Springboot程序准备
用idea快速构建springboot应用。pom.xml需要引入lomback.
- 工程结构
- pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--配置访问静态资源-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
- controller
package com.example.demo.web;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* @author Created by niugang on 2019/7/10/16:23
*/
@RestController
@RequestMapping("boot")
@Slf4j
public class ServerController {
@GetMapping("")
public ResponseEntity<Map> save(HttpServletRequest request) {
//当前服务器主机名
String localName = getIpAddr(request);
//服务器主机ip
int localAddr = request.getRemotePort();
Map<String, Object> map = new HashMap<>();
map.put("ip", localName);
map.put("port", localAddr);
map.put("timestamp", System.currentTimeMillis());
log.info("Server info:{}", map.toString());
return ResponseEntity.ok(map);
}
private static String getIpAddr(HttpServletRequest request) {
final String unknown = "unknown";
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}
}
4.2.3配置
在192.168.32.129和192.168.32.130上安装springboot应用。通过java -jar启动。(这是前台启动)
在192.168.32.12配置nginx
- upstream 模块
upstream www.boot.com {
server 192.168.32.129:8088 weight=1;
server 192.168.32.130:8088 weight=1;
}
upstream,上传流,指定请求 www.xxx.com 提交到 Nginx 后 Nginx 的转发配置,是 Nginx配置中的关键,其不仅可以设置各个服务器的负载比例,而且还可以监控服务器的健康状态。若某些服务器发生故障,其会自动屏蔽掉这些故障服务器,将负载均衡到其它服务器。
注意, upstream 后的指定请求名可以是任意字符串,不一定非要是域名形式。
- location 模块
location ~.*(/boot|/) {
proxy_pass http://www.boot.com;
}
配置表示,若当前请求路径的资源名称为/boot或为/(Nginx 服务器的根路径),则会由 proxy_pass 指定的“通行代理”再次提交一个请求。而该请求的处理模块即为前面指定的 upstream 模块。其本质就是做了一个请求转发。
但是,需要注意,不要在正则表达式后面添加结束符$,这样会使该 location 模块只匹配/boot与/请求,其它请求无法匹配,页面中的图片无法显示。因为图片提交的是…./images/alipay.jpg 请求,即非/boot,又非/请求。
4.2.4访问
http://192.168.32.128/images/alipay.jpg
5.动静分离
5.1介绍
动静分离,就是将 JSP、Servlet 等动态资源交由 Tomcat 或其它 Web 服务器处理,将 css、js、 image 等静态资源交由 Nginx 或其它 Http 服务器处理,充分发挥各自的优势,减轻其它服务器的压力,搭建更为高效的系统架构。
5.2
微信公众号