反向代理-Nginx

概述

Nginx是异步框架的网页服务器,也可以用作反向代理、负载平衡器和HTTP缓存。

与Apache相比

Nginx 的编写有一个明确目标就是超越 Apache Web 服务器的性能。Nginx 提供开箱即用的静态文件,使用的内存比 Apache 少得多,每秒可以处理大约四倍于 Apache 的请求。低并发下性能与 Apache 相当,有时候还低于,但是在高并发下 Nginx 能保持低资源低消耗高性能。还有高度模块化的设计,模块编写简单。配置文件简洁。

命令行

# 启动example: 
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

# 测试配置文件
nginx -t

# 平滑重启
nginx -s reload


# 如何shutdown
# 查询 master process主进程号
ps -ef | grep nginx

# 从容停止
kill -QUIT 3266

Nginx支持的几种信号:

  • TERM,INT 快速关闭
  • QUIT 从容关闭
  • HUP 平滑重启,重新加载配置文件
  • USR1 重新打开日志文件,在切割日志时用途较大
  • USR2 平滑升级可执行程序
  • WINCH 从容关闭工作进程

nginx.conf配置

example

@ref:

cat nginx.conf :

user       www www;  ## Default: nobody
worker_processes 5; ## Default: 1
error_log logs/error.log;
pid logs/nginx.pid;
worker_rlimit_nofile 8192;

events {
use epoll;
multi_accept on;
worker_connections 10240;
}

http {
include /etc/nginx/mime.types; # 设定mime类型
default_type application/octet-stream;
access_log /var/log/nginx/access.log; # 设定日志格式
include upstream-servers.conf; # 建议把upstream设置放在单独的文件

# 虚拟服务器, 可以有多个server
server{
listen 80;
server_name s1.xxx.com;
index index.shtml index.html index.htm;
root /opt/xxx;

# upstream定义,上游服务器设置:
upstream resin-labs {
server 192.168.1.100 weight=3;
server 192.168.1.101;
# 设置超时时间 proxy_connect_timeout 5s; proxy_read_timeout 10s;
}
upstream resin-admin {
server 192.168.1.109;
}

# rewrite规则:
rewrite ^/help$ /help/ redirect;

# location规则,建议顺序:精确匹配=, 前缀匹配^~, 正则匹配~, 普通匹配
location ~ ^/api/labs {
access_log /opt/logs/nginx/labs_stat.log labs_stat;
# 反向代理到‘resin-labs’的 upstream
proxy_pass http://resin-labs;
}
location /{
# 反向代理到‘resin-admin’的 upstream
proxy_pass http://resin-admin;
}
}
}

http

http下的Keepalive设置, 是Nginx与客户端(一般为浏览器、APP等)保持的长连接进行限制管理:

keepalive_timeout  120s 120s; // 
keepalive_requests 100; //
  • keepalive_timeout: 第一个参数:客户端连接在服务器端空闲状态下保持的超时值(默认75s);值为0会禁用keep-alive,也就是说默认不启用长连接;第二个参数:响应的header域中设置“Keep-Alive: timeout=time”;告知浏览器对长连接的维持时间;官方文档:Module ngx_http_core_module
  • keepalive_requests:默认100,某个长连接连续处理请求次数限制,超过次数则该长连接被关闭;如果需要释放某个连接占用的内存,必须关闭该链接,内存不大的情况下,不建议开大该配置;在QPS较高的场景,则有必要加大这个参数;官方文档:Module ngx_http_core_module

http/server

一个server{} 对应一个port

server 下的超时:

send_timeout 30s;

用于设置 Nginx 在响应请求时的超时时间。如果在设置的时间内 Nginx 还没有将响应完全发送出去,则会返回 “408 Request Time-out” 错误。
上面的例子中,如果 Nginx 在响应请求时超过了 30 秒还没有将响应完全发送出去,则会返回 “408 Request Time-out” 错误。

server/location

参考 (http://nginx.org/en/docs/http/ngx_http_core_module.html#location)
优先级:

  1. 精确匹配: location = /xxx URL完全匹配”/xxx”
  2. 前缀匹配: location ^~ /xxx URL”/xxx”开头的前缀, 比如”a.com/xxx/1”
  3. 正则匹配: location ~ ^*.php$
  4. 正则(不区分大小写): location ~* ^*.php$
  5. 普通匹配: location / 这样写一般用作其他条件都不符合, 最后的default行为

for Example:

# 第一个必选规则
#直接匹配网站根, 如果首页访问量很大, 应该首先匹配
location = / {
root /var/www/;
index index.htm index.html;
}

# 第二个必选规则是处理静态文件请求
# 前缀匹配"^~"优先级仅次于精确匹配"=", 可以用来
location ^~ /static/ {
root /webroot/static/;
}
# 如果使用memcached作为缓存, 也可以使用前缀匹配
location ^~ /api/services/topic/load {
memcached_pass memcached-cluster;
}
# 前缀匹配^~也可以是转发到应用服务, 但不推荐, 应该让静态文件访问处于更高的优先级

# 正则匹配也可以用来处理静态文件
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}

# 正则匹配用来转发到后端应用服务
location ~ ^/api/v2 {
proxy_pass http://tomcat:8080
}

# 最后普通字符匹配, 用来向后端应用转发
# 毕竟目前的一些RESTFUL框架的流行, 带.php,.jsp后缀的情况很少了
location / {
proxy_pass http://tomcat:8080/

location/proxy_pass

注意区分 ngx_stream_proxy_module 模块的 proxy_pass指令: 指令只能在server段使用使用, 只需要提供域名或ip地址和端口。可以理解为端口转发,可以是tcp端口,也可以是udp端口

这里介绍 ngx_http_proxy_module 模块的 proxy_pass指令, 只能出现在 server/location下, 可以理解为端口转发,可以是tcp端口,也可以是udp端口.
proxy_pass 把请求向下一个服务转发, 不影响用户浏览器地址栏的URL // 比如遇到跨域问题,而且客户端无法支持 CORS 时, 最好的办法就是让服务器来做代理.

格式 proxy_pass URL, 其中URL可以是另一个服务的Http地址, 也可以是定义的upstream,
需要注意URL后面是否带/, 表示的含义不同:

# URL后面没有`/`
# proxy_pass相对路径, 将会代理到(http://127.0.0.1:8080/api/**)

location /api {
proxy_pass http://127.0.0.1:8080 # 结尾没有/, 表示相对路径
}
# URL后面有`/`
# 将会跳转到(http://127.0.0.1:8080/**), 没有"/api"

location /api {
proxy_pass http://127.0.0.1:8080/ # 结尾有/, 表示绝对路径
}

location/allow,deny

allow,deny 是 ngx_http_access_module 模块提供的,
一般用在 location下, 允许/拒绝某些客户端访问location, 示例:

allow 192.168.1.0/24
deny all;

子网掩码的表示, 使用CIDR ( 参考 [[../22.Network-Protocol/网络协议2-IP]] ) 表示法:

  • /24: 255.255.255.0
  • /16: 255.255.0.0
  • /8: 255.0.0.0

deny 和 return 403的区别:
webserver - Nginx: Difference between deny all; and return 403; - Stack Overflow

server/rewrite

rewrite用来更改location, 实现跳转到其他location.
rewrite只能放在server{},location{},if{}中, 语法为rewrite regex replacement [flag];, 例如:

  • rewrite ^/help(.*) /static/help$1 last;
  • rewrite (.*) http://a.changyan.com$1 last;

rewrite的flag标记

  • last : rewrite之后, 跳出当前location, 并重新走一遍当前server的流程, 浏览器地址栏看起来仍是rewrite之前的URL;
  • break : 请求在这个location终结, 不再重新走server;
  • redirect : 返回302临时重定向, 浏览器地址栏会显示跳转后的地址;
  • permanent : 返回301永久重定向, 浏览器地址栏会显示跳转后的地址;

如果rewrite在location之外, last和break不会有任何区别, 都会跳过后面的rewrite直接进入location:

server {
rewrite ^/AAA/.* /BBB/$1 last; // 如果命中^AAA规则, 直接进入location, 下面的所有rewrite被跳过;
rewrite ^/XXX/.* /ZZZ/$1 last;
location ~ /BBB {
}
}

server/upstream

示例:

proxy_pass http://webapp
...
upstream webapp {
// [均衡方式]
server 192.168.1.9:8080;
}

负载均衡方式

  • 轮询(默认):
  • 带weight的轮询: 访问后端比例和weight成正比, 用于解决后端服务器性能不均衡
  • ip_hash: 来访ip hash, 用于解决session问题
  • url_hash: 后端服务器为缓存时

参考 SystemDesign-负载均衡-Nginx

上游超时

upstream backend { 
# 设置超时时间
proxy_connect_timeout 5s;
proxy_read_timeout 10s;
proxy_send_timeout
}

在上面的示例中,我们将连接超时时间设置为 5 秒,读取响应超时时间设置为 10 秒。如果在这些时间内没有建立连接或者没有接收到响应,nginx 将返回相应的错误码(504)。

log(access,error)

log 由 ngx_http_log_module 模块支持.

示例:

# log_format 可以在任何位置定义?
log_format myLog '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" $host $request_time';

# 可以出现在 http,server,location,limit_except 作用域
access_log /opt/logs/nginx/access.log myLog; ## 使用上面定义的format

# 可以出现在 main, http, mail, stream, server, location 作用域
error_log /opt/logs/nginx/error.log notice;

➤ access_log

格式: access_log path [format]

  • path 指定日志的存放位置。
  • format 指定日志的格式。格式可以用log_format自定义, 也可以不写, 不写则使用默认使用预定义的”combined”。

access_log作用域:
access_log指令的作用域分别有http,server,location,limit_except。也就是说,在这几个作用域外使用该指令,Nginx会报错。

➤ error_log

格式: error_log path [level]

  • level: debug, info, notice, warn, error, crit, alert,emerg中的任意值

error_log作用域: main, http, mail, stream, server, location

@ref: Nginx日志配置详解 - SegmentFault 思否

include

include 其他配置文件: include cache.conf;

module

Nginx模块一般分为三大类: filter, upstream, handler @todo

需要注意的

  • if判断字符串(注意是= 而不是==):
    if ($arg_client_id = "cxsh9byIb") {
    return 200 ':)';
    }

Nginx返回502, 503, 504

502: Bad Gateway

作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。

什么是无效的响应?与上游服务器无法连接 or 与上游服务器的连接断开

  • 与上游服务器无法连接 => 上游服务器因连接太多无法处理(例如 req-pre-thread 的服务器,线程池耗尽)
  • 上游服务器断开了连接 => 上游服务程序执行太久,上游服务终止了此次请求的 Worker 进程,Nginx 发现自己与上游服务断开

503: Service Unavailable

由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间。如果没有给出这个 Retry-After 信息,那么客户端应当以处理500响应的方式处理它。

可能的原因:

  • 上游服务器当前因为过载无法处理请求,主动拒绝响应,需要上游服务具备返回“Retry-After”的机制,比较少见到

504: Gateway Timeoua

作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器或者辅助服务器(例如 DNS)收到响应。

可能的原因:

  • 与上游服务的 connect time、send timeout、read time ,在最大等待时间内没有收到返回

参考 http 502 和 504 的区别 - 后端 - 掘金 @ref

代码解读

施工中…