最近由于事情较多,加上个人的懈怠,有一段时间没更新了。习惯的养成很难,但一旦养成,从中的受益也常会超乎意料,还是得坚持。接下来准备对一些开发维护过程中常用的工具软件与服务进行整理,如本系列的nginx,后续的redis,消息队列,jenkins等,欢迎关注。

nginx是一个轻量级的高性能的HTTP服务器,在Web应用部署中很常见。也正因为很常见,所以掌握其基本原理与用法显得很有必要,本系列文章对nginx的相关内容进行梳理,以供初学者参考、熟悉者回顾。

1. 简介

在nginx以前,比较流行的HTTP服务器应属Apache(LAMP中A就是指Apache)。但根据netcraft的调查显示,近两年nginx已经超越Apache,成为市场占有率第一的HTTP服务器。如下图
httpserver-trend

nginx能战胜Apache有几个主要原因,一是其足够轻量,不管是安装与维护,还是资源的占用都非常简单与轻量;二是其高性能,nginx基于事件驱动机制,具备非常好的性能,据称能支持高达50000个并发连接数;三是其具有很高的稳定性,相对其它HTTP服务器在访问负载很高时会导致内存耗尽进而可能失去响应,nginx采用分阶段资源分配技术,CPU与内存占有率都很低,在高并发场景下,稳定性更高。

在日常使用中,nginx主要在三个方面为我们提供服务:

  1. 作为静态服务器提供静态资源的访问,如html网站,文件等
  2. 为后端服务提供反向代理
  3. 为反向代理的后端服务集群提供负载均衡

2. 静态服务器

静态服务器一般就是提供Web前端的一些静态资源,如html页面,js、css文件的访问,用法配置示例如下

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

location /static/ {
index index.html index.htm;
alias /usr/local/nginx/html/garten-web/dist/;
}
}

其中

  • index指定网站的初始页,可以跟多个文件,空格隔开,nginx根据顺序检查文件是否存在,如上例如果用户直接输入/static则会访问/usr/local/nginx/html/garten-web/dist/index.html(如果不存在则再看index.htm是否存在)
  • alias是与root对应的用法,都用于访问本地文件系统的资源,在匹配到location配置的url路径后,在alias或root配置的目录寻找对应的资源,区别在于:alias就在配置的目录下寻找对应的资源,而root则会将location配置路径附加到root路径后,在拼接后的目录下寻找对应的资源。如上例中访问 /static/hello.html,使用alias则会访问到/usr/local/nginx/html/garten-web/dist/hello.html,使用root则会访问到/usr/local/nginx/html/garten-web/dist/static/hello.html

alias配置的目录后有没有“/”要与location后面的路径是否有“/”保持一致,否则找不到资源

3. 反向代理

了解反向代理之前先看看什么是正向代理。

举个不那么和谐的例子,当你需要访问某些国外网站的时候,直接输入域名是打不开的,这时可以找一台能访问这些网站的服务器来做代理(这台服务器能访问你访问不了的网站,你能访问这台服务器),你访问网站时,实际是通过代理来中转访问。这种情况,你是知道目标网站的地址的,但是服务器只知道请求来自于代理服务器,而不知道是你(真正的客户端)在访问,所以正向代理代理的是客户端,是对服务端隐藏了真实的客户端信息。

而对于反向代理,客户端是明确的,但具体在后端请求了哪个服务却不明确了,比如你请求的是 www.abc.com, 在反向代理端,它可能是 www.cba.com 的代理,也可能是 www.ccc.com 的代理, 不看配置你是不知道它到底代理的谁。因此,反向代理代理的是服务器端,隐藏了服务端的信息。

nginx中配置反向代理很简单,如下

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

location /api/ {
proxy_pass http://192.168.0.120:8080/;
}
}

使用nginx的反向代理,可以解决两个问题:

  1. 跨域问题:前后端分离情况下,前端网页访问后端接口存在跨域问题,对后端接口的访问统一通过前端网站域名访问,在nginx中通过对接口的路径进行匹配后反向代理到后端接口服务。如上例中访问接口login可通过 http://localhost/api/login 访问,nginx将会反向代理到 http://192.168.0.120:8080/login 后端接口地址
  2. 负载均衡:如果后端服务部署的是服务器集群,则对服务的访问需要做负载均衡,nginx通过反向代理结合upstream来实现负载均衡

反向代理的路径路由规则:如果proxy_pass配置的路径最后带“/”,则类似于alias,不会在proxy_pass的uri后面拼接location的路径,如果没带“/”,则会进行拼接,类似于root。
比如我们按上例配置访问 http://localhost/api/login 则代理到 http://192.168.0.120:8080/login

但如果是按以下配置(proxy_pass配置路径不带子路径,且后面没带“/”),

1
2
3
location /api/ {
proxy_pass http://192.168.0.120:8080;
}

则会被代理到 http://192.168.0.120:8080/api/login, 将location的路径拼接了。

如果proxy_pass配置的路径带子路径,如

1
2
3
location /api/ {
proxy_pass http://192.168.0.120:8080/api/;
}

则不管后面带不带“/”,都不会拼接location的路径,只是与/api/后面的部分进行拼接。

注意:如果是不带“/” proxy_pass http://192.168.0.120:8080/api/login 则会被代理到 proxy_pass http://192.168.0.120:8080/apilogin 了, 这时,可通过将location与proxy_pass配置路径保持一致即可——要么都带“/”,要么都不带。

4. 负载均衡

nginx通过反向代理proxy_pass结合upstream来对后端服务器集群实现负载均衡,在nginx配置的http节点下定义upstream,如

1
2
3
4
upstream backend {
server 192.168.0.120:8080;
server 192.168.0.121:8080;
}

然后在server节点下的location里配置反向代理,如

1
2
3
location /api/ {
proxy_pass http://backend/api/;
}

这样就会将接收到的请求顺序循环分配到后端的服务器上,如果某个服务器宕机,也能自动将其剔除,不再分配请求,直到其恢复。这是默认的负载均衡策略,即轮询策略。

nginx负载均衡的策略包括:

  1. 权重轮询,权重轮询在上述轮询策略的基础上加了服务器的请求分配权重,以根据服务器配置的不同,将更多的请求分配到配置更高的服务器上。如
    1
    2
    3
    4
    upstream backend {
    server 192.168.0.120:8080 weight=10;
    server 192.168.0.121:8080 weight=20;
    }

分配给121的请求将比分配给120的请求多一倍。

  1. ip_hash,通过对请求来源ip求hash值,将相同ip的请求分配到相同的服务器上,此种策略可以解决分布式session的问题。配置如

    1
    2
    3
    4
    5
    upstream backend {
    ip_hash;
    server 192.168.0.120:8080;
    server 192.168.0.121:8080;
    }
  2. url_hash,对访问url求hash值,将同一个url的请求分配到相同的服务器上,对有本地缓存的场景比较适用。配置如

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

hash_method指定hash算法

  1. fair,根据后端服务器的响应时间来合理分配请求,响应时间短的优先分配。配置如
    1
    2
    3
    4
    5
    upstream backend {
    server 192.168.0.120:8080;
    server 192.168.0.121:8080;
    fair;
    }

5. 总结

nginx以其轻量级、高性能、高稳定性的特性成为HTTP服务器的主流,是不论开发者还是运维人员都必须了解掌握的服务软件。本文从静态服务器,反向代理,负载均衡三个日常使用场景的角度对nginx进行了简单介绍。



欢迎关注我的微信公众号:jboost-ksxy
———————————————————————————————————————————————————————————————
微信公众号