彻底搞懂Nginx

前言

Nginx在工作中用的很多,平时开发也一直用Nginx来代理,但是一直对Nginx是一个模糊的概念。这次打算结合理论和工作中的Nginx配置彻底搞清楚Nginx。

Nginx能做什么

  1. 正向代理
  2. 反向代理
  3. 负载均衡
  4. HTTP服务器

正向代理

正向代理,也就是传说中的代理,他的工作原理就像一个跳板,简单的说,我是一个用户,我访问不了某网站,但是我能访问一个代理服务器,这个代理服务器呢,他能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容,代理服务器去取回来,然后返回给我。从网站的角度,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。

专业点说:正向代理是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并制定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特殊的设置才能使用正向代理

关键代码如下

1
2
3
4
5
6
7
8
9
resolver 114.114.114.114 8.8.8.8;
server {
resolver_timeout 5s;
listen 81;

location / {
proxy_pass http://$host$request_uri;
}
}

resolver是配置正向代理的DNS服务器,listen是正向代理的端口,配置好了就可以在代理插件上通过服务器ip+端口号进行代理了。

反向代理

继续举例。
用户访问http://www.test.com/readme,但www.test.com上并不存在readme页面,他是偷偷从另外一台服务器上取回来,然后作为自己的内容返回用户,但用户并不知情。这里提到的www.test.com这个域名对应的服务器就设置了反向代理功能。

结论就是:反向代理和正向代理正好相反,对于客户端而言他就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端,就像这些内容原本就是他自己的一样。

关键代码如下

1
2
3
4
5
6
7
8
server {
listen 80;
server_name localhost;

location / {
proxy_pass http://localhost:8080;
}
}

这样当我们访问localhost:80时,80端口会向8080端口转交请求,并将内容返回给我们客户端,就相当于访问localhost:8080了。

负载均衡

负载均衡也是Nginx常用的一个功能,负载均衡的意思就是分摊到多个操作单元上进行执行,例如Web服务器,FTP服务器、企业关键应用服务器和其它关键人物服务器等,从而共同完成工作任务。简单而言,就是当有2台或以上服务器时,根据规则随机的将请求分发到制定的服务器上处理,负载均衡配置一般都需要同时配置反向代理,通过反向代理跳转到负载均衡。

Nginx自带3种负载均衡策略,还有2种常用的第三方策略。

RR(默认)

每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器挂了,则自动剔除。

核心代码

1
2
3
4
5
6
7
8
9
10
11
12
upstream test {
server localhost:8080;
server localhost:8081;
}
server {
listen 80;
server_name localhost;

location / {
proxy_pass http://test;
}
}

upstream 部分即为负载均衡的核心代码。
这里配置2个端口,而8081端口是访问不到的,但是我们访问 http://localhost 的时候也不会有问题,会默认跳转到 http://localhost:8080 具体是因为Nginx会自动判断服务器的状态,如果服务器挂了,则不会跳转到这台服务器。

权重

制定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。

核心代码如下

1
2
3
4
upstream test {
server localhost:8080 weight=9;
server localhost:8081 weight=1;
}

那么10次一般只有1次会访问到8081,剩下9次会访问到8080。

ip_hash

上面的2种方式都有一个问题,那就是下一个请求来的时候请求可能分到另一个服务器,当我们的程序不是无状态的时候(采用了session保存数据),这时候就有一个很大的问题了,比如把登录信息保存到session种,那么跳转到另外一台服务器的时候就需要重新登录了,所以很多时候我们需要一个客户只访问一个服务器,那么就需要用iphash了,iphash的每个请求按访问ip的hash结果分配,这样每个方可固定访问一个后端服务器,可以解决session的问题。

核心代码如下

1
2
3
4
5
upstream {
ip_hash;
server localhost:8080;
server localhost:8081;
}

fair(第三方)

按后端服务器的响应时间来分配请求,响应时间短的优先分配。

1
2
3
4
5
upstream backend {
fair;
server localhost:8080;
server localhost:8081;
}

url_hash(第三方)

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method使使用的hash算法

核心代码如下

1
2
3
4
5
6
upstream backend {
hash $request_uri;
hash_method crc32;
server localhost:8080;
server localhost:8081;
}

HTTP服务器

Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器,同时现在也很流行动静分离,就可以通过Nginx来实现。

首先看看Nginx做静态资源服务器

1
2
3
4
5
6
7
8
9
server {
listen 80;
server_name localhost;

location / {
root e:\wwwroot;
index index.html;
}
}

这样如果访问到 http://localhost 就会默认访问到E盘wwwroot目录下面的index.html,如果一个网站只是静态页面的话,那么就可以通过这种方式来实现部署。

动静分离

动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。

核心代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
upstream test {
server localhost:8080;
server localhost:8081;
}

server {
listen 80;
server_name localhost;

location / {
root e:\wwwroot;
index index.html;
}

# 所有静态请求都由nginx处理
location ~ \.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
root e:\wwwroot;
}

# 所有动态请求都转发给tomcat处理
location ~ \.(jsp|do)$ {
proxy_pass http://test;
}
}

这样我们就可以把html、图片、css以及js放到wwwroot目录下,而tomcat只复杂处理jsp和请求,例如当我们后缀为gif的时候,Nginx默认会从wwwroot获取到当前请求的动态图文件返回,当然这里的静态文件跟Nginx是同意爱服务器,我们也可以在另外一台服务器,然后通过反向代理和负载均衡配置过去就好了。

实际业务中用到的conf文件分析

主要代码如下

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
server {
listen 80;

# host中绑定的www.sb.com实际是localhost
server_name www.sb.com;

# 静态资源从这里返回,缓存的过期时间是1天
location ~* ^.+\.(woff|woff2|ttf|json|log|jpg|jpeg|gif|png|ico|html|cfm|cfc|afp|asp|lasso|pl|py|txt|fla|swf|zip)$ {
root /Users/admin/Documents/sb;
expires 1d;
}

# jss、css和less这些静态资源依然走这个目录,过期时间2小时
location ~* ^.+\.(js|css|less)$ {
root /Users/admin/Documents/sb;
expires 2h;
}

# 监听80端口,当访问www.sb.com:80的时候
# 会将请求转发到 http://101.37.111.40
# 最后将结果返回给客户端
location ~ /{
proxy_pass http://101.37.111.40;
}
}

可以看到,项目中用到了反向代理和将Nginx作为静态资源服务器。
PS:如果将www.sb.com的host绑定到测试环境,经过验证,不会走进本地Nginx配置。关于这个可以这么理解,Nginx在本地起了一个服务器,如果请求的是本地,则会走进此服务器,如果请求的是其他域名,则不会走进本地Nginx服务器,即和本地Nginx没有关系。

参考

坚持原创技术分享,您的支持将鼓励我继续创作!