Linux 运维手册之 NGINX HTTP网页服务

in Linux with 0 comment

HTTPHyperText Transfer Protocol,超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTPWWWWorld Wide Web,全球广域网)万维网的数据通信基础。

一、HTTP 协议简介

发展历程

设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由URIUniform Resource Identifiers,统一资源标识符)来标识。

HTTP的发展是由 Tim Berners-Lee(蒂姆·伯纳斯-李)1989年在CERNEuropean Organization for Nuclear Research,欧洲核子研究组织)所发起。HTTP的标准制定由W3CWorld Wide Web Consortium,万维网协会)和IETFInternet Engineering Task Force,互联网工程任务组)进行协调,最终发布了一系列的RFC,其中最著名的是1999 年 6 月公布的 RFC 2616,定义了HTTP协议中现今广泛使用的一个版本——HTTP 1.1

201412月,互联网工程任务组的Hypertext Transfer Protocol Bis(httpbis)工作小组将HTTP/2标准提议递交至IESG进行讨论,于2015217日被批准。HTTP/2标准于20155月以RFC 7540正式发表,取代HTTP 1.1成为HTTP的实现标准。

协议概述

HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP)。通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)。我们称这个客户端为用户代理程序(user agent)。应答的服务器上存储着一些资源,比如HTML文件和图像。我们称这个应答服务器为源服务器(origin server)。在用户代理和源服务器中间可能存在多个“中间层”,比如代理服务器、网关或者隧道(tunnel)。

尽管TCP/IP协议是互联网上最流行的应用,但是在HTTP协议中,并没有规定必须使用它或它支持的层。事实上,HTTP可以在任何互联网协议上,或其他网络上实现。但是实际上HTTP其下层协议必须提供可靠的传输。因此,任何能够提供这种保证的协议都可以被其使用。也就是在TCP/IP协议族使用TCP作为其传输层。

通常,由客户端发起一个请求,创建一个到服务器指定端口的TCP连接。服务端则在那个端口监听客户端的请求。一旦收到请求,服务器会向客户端返回一个状态,比如"HTTP/1.1 200 OK",以及返回的内容,如请求的文件、错误消息、或者其它信息。

请求方法

HTTP/1.1 协议中共定义了八种方法(也叫“动作”)来以不同方式操作指定的资源:

GET
向指定的资源发出“显示”请求。使用GET方法应该只用在读取数据,而不应当被用于产生“副作用”的操作中,例如在Web Application中。其中一个原因是GET可能会被网络蜘蛛等随意访问。参见安全方法

HEAD
与GET方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据)。

POST
向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。

PUT
向指定资源位置上传其最新内容。

DELETE
请求服务器删除Request-URI所标识的资源。

TRACE
回显服务器收到的请求,主要用于测试或诊断。

OPTIONS
这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用'*'来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作。

CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。通常用于SSL加密服务器的链接(经由非加密的HTTP代理服务器)。

方法名称是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405 (Method Not Allowed),当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码501 (Not Implemented)

HTTP服务器至少应该实现GETHEAD方法,其他方法都是可选的。当然,所有的方法支持的实现都应当匹配下述的方法各自的语义定义。此外,除了上述方法,特定的HTTP服务器还能够扩展自定义的方法。例如:PATCH(由 RFC 5789 指定的方法)用于将局部修改应用到资源。

版本演进

超文本传输协议已经演化出了很多版本,它们中的大部分都是向下兼容的。在 RFC 2145 中描述了HTTP版本号的用法。客户端在请求的开始告诉服务器它采用的协议版本号,而后者则在响应中采用相同或者更早的协议版本。

HTTP/0.9

已过时。只接受GET一种请求方法,没有在通讯中指定版本号,且不支持请求头。由于该版本不支持POST方法,因此客户端无法向服务器传递太多信息。

HTTP/1.0

这是第一个在通讯中指定版本号的HTTP协议版本,至今仍被广泛采用,特别是在代理服务器中。

HTTP/1.1

持久连接被默认采用,并能很好地配合代理服务器工作。还支持以管道方式在同时发送多个请求,以便降低线路负载,提高传输速度。

HTTP/1.1相较于HTTP/1.0协议的区别主要体现在:
缓存处理
带宽优化及网络连接的使用
错误通知的管理
消息在网络中的发送
互联网地址的维护
安全性及完整性

HTTP/2

HTTP/2 相比 HTTP/1.1 的修改并不会破坏现有程序的工作,但是新的程序可以借由新特性得到更好的速度。

HTTP/2 保留了 HTTP/1.1 的大部分语义,例如请求方法、状态码乃至URI和绝大多数HTTP头部字段一致。而 HTTP/2 采用了新的方法来编码、传输客户端——服务器间的数据。

当前版本,于2015年5月作为互联网标准正式发布。

HTTP 状态码

因篇幅有限,此处省略:点击查看详情


二、常用 HTTP 服务

常用网页服务

市场占有率

Developer June 2018 Percent July 2018 Percent Change
Apache 76,721,597 35.23% 76,312,577 34.60% -0.63
Microsoft 56,030,491 25.73% 57,395,894 26.02% 0.29
NGINX 50,860,718 23.35% 50,246,244 22.78% -0.57
Google 1,909,658 0.88% 1,948,858 0.88% 0.01

表格数据来源


三、NGINX 服务

NGINX是一个免费的,开源的,高性能的HTTP服务器和反向代理,以及IMAP / POP3代理服务器。 NGINX以其高性能,稳定性,丰富的功能集,简单的配置和低资源消耗而闻名。
----- 官方宣传语

NGINX

虽然 NGINX 市场占有率并不占有绝对优势,但是对比其他WEB服务器还是有很大优势。

  1. 作为网页服务器:相比 ApacheNGINX 使用更少的资源,支持更多的并发连接(能够支持高达 50000 个并发连接数的响应),静态页面处理性能比 Apache3倍以上,但对动态内容支持较弱,需要其他依赖进行实现,并且组件不如 Apache 丰富。

  2. 作为负载均衡服务器:相比 PerlbalNGINX 既可以在内部直接支持 RailsPHP 程序对外进行服务, 也可以支持作为HTTP代理服务器对外进行服务。采用C语言进行编写,不论是系统资源开销还是CPU使用效率都要好很多。

其他优势

  1. NGINX 配置相对简洁,启动过程迅速,服务宕机可能性低,并且支持服务平滑升级。

  2. Apache是同步多进程模型,一个连接对应一个进程;NGINX是异步的,多个连接(万级别)对应一个进程。

  3. NGINX的优势是处理静态请求,CPU内存使用率低,Apache适合处理动态请求,所以一般前端用NGINX作为反向代理抗住压力,Apache作为后端处理动态请求。

NGINX 部署

NGINX 官方预编译版本支持以下发行版

RHEL/CentOS

版本 支持的平台
6.x x86_64, i386
7.4+ x86_64, ppc64le

Debian

版本 代号 支持的平台
8.x jessie x86_64, i386
9.x stretch x86_64, i386

Ubuntu

版本 代号 支持的平台
14.04 trusty x86_64, i386, aarch64/arm64
16.04 xenial x86_64, i386, ppc64el, aarch64/arm64
17.10 artful x86_64, i386
18.04 bionic x86_64

SLES

版本 支持的平台
12 x86_64

导入官方源

1). 为 RHELCentOS 设置 yum 仓库,例如编辑:

$ sudo vi /etc/yum.repos.d/nginx.repo

插入以下内容:

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/OS/OSRELEASE/$basearch/
gpgcheck=0
enabled=1

小贴士:需要将 "< OS >" 替换为系统发行版,将 "< OSRELEASE >" 替换为系统版本。

例如:在 CentOS 7 上可以使用

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1

2). 为 DebianUbuntu 设置 apt 仓库,例如编辑:

$ sudo vi /etc/apt/sources.list.d/nginx.list

插入以下内容:

Debian 系统下

deb http://nginx.org/packages/debian/ codename nginx
deb-src http://nginx.org/packages/debian/ codename nginx

Ubuntu 系统下

deb http://nginx.org/packages/ubuntu/ codename nginx
deb-src http://nginx.org/packages/ubuntu/ codename nginx

小贴士:需要将 "< codename >" 替换为系统代号。

例如:在 Ubuntu 18.04 上可以使用

deb [arch=amd64] http://nginx.org/packages/ubuntu/ bionic nginx
deb-src [arch=amd64] http://nginx.org/packages/ubuntu/ bionic nginx

注意:因 Ubuntu 18.04 彻底移除了 x86 架构的支持,因此需要加入[arch=amd64]只检索 amd64 ,否则会有报错信息。

从仓库安装

配置仓库后即可使用官方的软件包管理命令安装官方仓库中的NGINX相应版本。

RHELCentOS 从官方仓库安装 NGINX

yum makecache
yum install nginx

DebianUbuntu 从官方仓库安装 NGINX

apt-get update
apt-get install nginx

软件包来源校验

RPM软件包和 DEB 存储库都使用数字签名来验证下载软件包的来源与完整性(是否被篡改)。
若想开启此功能,检查校验签名,则需要下载官方签名密钥并将其导入系统密钥池。

RHELCentOS 导入官方密钥:

$ sudo rpm --import nginx_signing.key

DebianUbuntu 导入官方密钥:

$ sudo apt-key add nginx_signing.key

注意:在 RHEL/CentOS 中默认不检查密钥,需要修改 /etc/yum.repos.d/nginx.repo 中的 gpgcheck=1 参数。

DebianUbuntu 中不导入密钥会报以下错误:

W: GPG error: http://nginx.org/packages/ubuntu bionic InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY ABF5BD827BD9BF62
E: The repository 'http://nginx.org/packages/ubuntu bionic InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

也可以使用以下命令导入密钥:

apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ABF5BD827BD9BF62

注意:后面的密钥串ABF5BD827BD9BF62应替换为错误信息中的数值。

NGINX 模块

自动索引模块 ngx_http_autoindex_module

官方文档:点击跳转

配置模板:

location / {
    root html;
    autoindex on;
    autoindex_localtime on;
    autoindex_exact_size off;
}

语法:

autoindex on/off;
默认参数:off
语句位置:http, server, location

参数:

autoindex_exact_size off;    # 单位换算
# 可选参数:on | off ,默认 on 单位为 byte,off 换算为 kB,MB,GB

autoindex_localtime on;      # 时间格式
# 可选参数:on |off ,默认 off 显示的文件时间为GMT时间。on 显示的文件时间为文件的服务器时间。

charset utf-8,gbk;           # 字符集设置
# 可选参数:UTF-8 | GBK | GB2312 ,添加GBK后即可解决中文乱码

autoindex_format html;       # 网页格式
# 可选参数: html | xml | json | jsonp ,默认 html 。

状态监测模块 ngx_http_stub_status_module

官方文档:点击跳转

配置模板:

location = /basic_status {
    stub_status;
}

语法:

stub_status;
默认参数:  —
语句位置:server, location

访问限制模块 ngx_http_access_module

官方文档:点击跳转

配置模板:

location / {
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}

语法:

allow address | CIDR | unix: | all;
默认参数:  —
语句位置:http, server, location, limit_except

用户认证模块 ngx_http_auth_basic_module

官方文档:点击跳转

配置模板:

location / {
    auth_basic           "closed site";
    auth_basic_user_file conf/htpasswd;
}

语法:

auth_basic string | off;
默认:   off
auth_basic_user_file file;
语句位置:http, server, location, limit_except

注意:密码文件需严格按照以下格式进行生成。密码文件名可使用变量。

# comment
name1:password1
name2:password2:comment
name3:password3

生成密码可以使用阿帕奇工具包中的小工具

$ sudo yum install httpd-tools
$ sudo htpasswd -c /etc/nginx/auth_conf password

连接限制模块 ngx_http_limit_conn_module

官方文档:点击跳转

配置模板:

http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    ...

    server {

        ...

        location /download/ {
            limit_conn addr 1;
        }

配置模板2:

http {
    limit_conn_zone $binary_remote_addr zone=perip:10m;
    limit_conn_zone $server_name zone=perserver:10m;
    ...
    server {
        ...
        limit_conn perip 10;
        limit_conn perserver 100;
    }

语法:

limit_conn zone number;
默认: —
语句位置:http, server, location

日志:

limit_conn_log_level info | notice | warn | error;
默认:error;
语句位置:http, server, location

状态:

limit_conn_status code;
默认:503;
语句位置:http, server, location

请求限制模块 ngx_http_limit_req_module

官方文档:点击跳转

配置模板:

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    ...

    server {

        ...

        location /search/ {
            limit_req zone=one burst=5;
        }

语法:

limit_req zone=name [burst=number] [nodelay];
默认: —
语句位置:http, server, location

示例用法:

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

server {
    location /search/ {
        limit_req zone=one burst=5;
    }

说明:允许每秒平均不超过1个请求,并发不超过5个请求。

如果不希望在请求受限的情况下拒绝过多的请求,则应使用以下参数来推迟多余的请求:

limit_req zone=one burst=5 nodelay;

日志:

limit_req_log_level info | notice | warn | error;
默认: error;
语句位置:http, server, location

状态:

limit_req_status code;
默认: 503;
语句位置:http, server, location

日志记录模块 ngx_http_log_module

官方文档:点击跳转

NGINX 提供完备的日志记录功能,此模块可以深度定义日志格式,便于筛选可用信息。

配置模板:

log_format compression '$remote_addr - $remote_user [$time_local] '
                       '"$request" $status $bytes_sent '
                       '"$http_referer" "$http_user_agent" "$gzip_ratio"';

access_log /spool/logs/nginx-access.log compression buffer=32k;

语法:

access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
默认:
access_log logs/access.log combined;
语句位置:http, server, location, if in location, limit_except

日志变量详解:

$remote_addr, $http_x_forwarded_for # 记录客户端IP地址
$remote_user                        # 记录客户端用户名称
$request                            # 记录请求的URL和HTTP协议
$status                             # 记录请求状态
$body_bytes_sent                    # 发送给客户端的字节数,不包括响应头的大小
$bytes_sent                         # 发送给客户端的总字节数
$msec                               # 日志写入时间。 单位为秒, 精度是毫秒。
$http_referer                       # 记录从哪个页面链接访问过来的
$http_user_agent                    # 记录客户端浏览器相关信息
$request_length                     # 请求的长度(包括请求行, 请求头和请求正文)。
$request_time                       # 请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始, 直到把最后一个字符发送给客户端后进行日志写入为止。
$time_iso8601                       # ISO8601标准格式下的本地时间。
$time_local                         # 通用日志格式下的本地时间。

日志缓存功能:

open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
默认:off;
语句位置:http, server, location

日志缓存参数标注:
max: 设置缓存中的最大文件描述符数量,如果缓存被占满,采用LRU算法将描述符关闭。
inactive: 设置存活时间,默认是10s
min_uses: 设置在inactive时间段内, 日志文件最少使用多少次后,该日志文件描述符记入缓存中,默认是1次
valid: 设置检查频率, 默认60s
off: 禁用缓存


NGINX 配置

此部分配置实质上是核心模块中内容(ngx_http_core_module),但是使用频率最高,因此单独拿出来进行分析。

监听端口(listen

示例配置:

server {
    listen       80;
    server_name  www.wavengine.com;
    root         /var/www/html/wavengine/blog;
    index        index.php index.html
    ...
}

注意:浏览器在访问页面时会默认访问 80 端口,因此网站的监听端口请勿修改(若做了端口转发或者负载均衡可使用其他端口),以防访客无法正常使用。

根目录(root

示例配置:

server {
    listen       80;
    server_name  www.wavengine.com;
    root         /var/www/html/wavengine/blog;
    index        index.php index.html
    ...
}

root 指定了此主机的根目录,所有资源会在此目录下寻找,因此请设置正确的根目录,部分产品解压后存在多个目录,请分辨实际的网站目录并指定。

补充:指定根目录后可以使用文件的相对地址来指定资源。

与之相关的还有一个 alias 作用与 root 相似,会将root目录重定向为alias 地址。

举个例子:

server {
        listen 80;
        index index.html;
        location /request_path/code/ {
                alias /local_path/code/;
        }
}

实际请求:/local_path/code/index.html

server {
        listen 80;
        index index.html;
        location /request_path/code/ {
                root /local_path/code/;
        }
}

实际请求:/local_path/code/request_path/code/index.html

索引页面(index

示例配置:

server {
    listen       80;
    server_name  www.wavengine.com;
    root         /var/www/html/wavengine/blog;
    index        index.php index.html
    ...
}

说明:指定索引页面后,NGINX 会按指定的顺序在根目录下搜索,显示为当前主机的主页。

虚拟主机 (VH

虚拟主机是指在一个 NGINX 配置文件中指定多个网站

$ cat /etc/nginx/conf.d/all.conf

配置文件模板

server {
    listen       80;
    server_name  blog.wavengine.com;
    root         /var/www/html/wavengine/blog;
    ...
}

server {
    ...
    listen       80;
    server_name  ftp.wavengine.com;
    root         /var/www/html/wavengine/ftp;
}

也可以将多个主机拆分为多个文件(文件名可以自定义,但必须以 .conf 结尾)

$ ll
-rw-r--r-- 1 root root 1.1K Apr 17 09:46 default.conf
-rw-r--r-- 1 root root  353 Aug 14 00:07 ftp.conf
-rw-r--r-- 1 root root 2.6K Aug 14 23:01 blog.conf
total 12K

小贴士:推荐在主配置文件上 /etc/nginx/nginx.conf 配置 http 段配置,在 /etc/nginx/conf.d/ 中配置 server 段配置。
不同的域名可以监听在同一个端口,请求会根据请求的域名进行自动分配,但是若同一域名绑定相同的地址会触发优先级问题(应尽量避免)。

资源定位(location)

location 用于在一个主机中匹配用户访问的资源,并进行处理和回应。

匹配符 匹配规则 优先级
= 表示精确匹配 1
^~ 表示以某字符串开头 2
~ 表示区分大小写的正则匹配 3
~* 表示不区分大小写的正则匹配 4
!~ 表示区分大小写不匹配的正则 5
!~* 表示不区分大小写不匹配的正则 6
/ 通用匹配,任何请求都会匹配到 7

注意:~~* 正则匹配规则在匹配后会寻找更精准的location再次进行匹配。

文件检查(try_files)

检查指定顺序的文件是否存在,并使用第一个找到的文件进行请求处理;处理在当前上下文中执行。根据rootalias指令从文件参数构造文件的路径。可以通过在名称的末尾指定斜杠来检查目录的存在,例如:$ URI /。如果未找到任何文件,则会进行内部重定向到最后一个参数中指定的uri

语句位置:server, location

示例配置:

server {
        listen      80;
        server_name test.wavengine.com;
        root        /test/code;
        index       index.html;
        location / {
                try_files $uri @java_page;
        }
        location @java_page {
                proxy_pass http://127.0.0.1:8080;
        }
}

说明:此配置文件使用后,若用户访问示例地址后会在 /test/code 下寻找 index.html 若不存在文件会将请求导向本地端口8080进行解析(Tomcat)。

NGINX 负载均衡

LBLoad Balance,负载均衡)是将一个任务分摊到多个操作单元上进行执行,从而分摊压力,增加吞吐量、加强数据处理能力、提高网络的灵活性和可用性。

NGINX 的负载均衡实质上是“反向代理”。

反向代理与负载均衡之间的关系:如果后端是一台服务器就叫反向代理,如果有多台就是负载均衡。反向代理才能实现负载均衡,负载均衡是做反向代理的目的之一。

“正向代理”和“反向代理”的区别:
简单地理解,正向代理隐藏用户身份,反向代理隐藏服务器身份。

正向代理与反向代理

正向代理

举个例子:

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

正向代理的用途:
(1)访问原来无法访问的资源。
(2)作为缓存,加速访问资源。
(3)对客户端访问授权,上网进行认证。
(4)代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息。

反向代理

举个例子:

  我是一个用户,我访问某个网站,但是实质上给我提供数据的是另一个服务器,但是它隐藏在代理服务器后,我只能知道我连接的是谁,但是不知道具体谁给我提供的服务。隐藏了真实服务器的信息,提高了安全指数。

反向代理的用途:
(1)保证内网的安全,可以使用反向代理提供WAF功能,阻止web攻击。
(2)负载均衡,分摊压力,提高数据处理能力。

NGINX 反向代理配置

语法:

proxy_pass URL;
默认参数:—
语句位置:location, if in location, limit_except

跳转重定向

语法:

proxy_redirect default;
可选参数:proxy_redirect off;proxy_redirect redirect replacement;
默认参数:proxy_redirect default;
语句位置:http, server, location

头部设定

在默认使用反向代理时会遇到一个问题,抓包时可在头部信息中看到真实服务器地址及端口,这是不合理的,因此需要使用重新定义头部信息功能。

语法:

proxy_set_header field value;
默认参数:proxy_set_header Host $proxy_host;
            proxy_set_header Connection close;
语句位置:http, server, location

例子:

# 用户请求的时候HOST的值是www.wavengine.com, 那么代理服务会像后端传递请求的还是www.wavengine.com
proxy_set_header Host $http_host;
# 将$remote_addr的值放进变量X-Real-IP中,$remote_addr的值为客户端的ip
proxy_set_header X-Real-IP $remote_addr;
# 客户端通过代理服务访问后端服务, 后端服务记录真实客户端地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

其他参数:

# 代理服务连接后端服务器的连接超时时间,建议使用默认值
语法:proxy_connect_timeout time;
默认参数:proxy_connect_timeout 60s;
语句位置:http, server, location

# 代理服务等待后端服务器的响应时间
语法:proxy_read_timeout time;
默认参数:proxy_read_timeout 60s;
语句位置:http, server, location

# 后端服务器在规定时间之内必须传完所有的数据至代理
语法:proxy_send_timeout time;
默认参数:proxy_send_timeout 60s;
语句位置:http, server, location

代理缓冲区

代理缓冲功能开启的情况下,NGINX会把后端返回的内容先放到缓冲区当中,然后再返回给客户端,边收边传, 不是全部接收完再传给客户端。

语法:proxy_buffering on | off;
默认参数:proxy_buffering on;
语句位置:http, server, location

语法:proxy_buffer_size size;
默认参数:proxy_buffer_size 4k|8k;
语句位置:http, server, location

语法:proxy_buffers number size;
默认参数:proxy_buffers 8 4k|8k;
语句位置:http, server, location

配置优化

在同一个配置文件中全部定义这些参数会导致配置文件冗余复杂,可读性差。因此将这部分配置写入一个配置文件,然后统一调用。

比如:

[root@domain ~]# vim /etc/nginx/proxy_params

写入以下内容

proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;

proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;
proxy_max_temp_file_size 256k;

在其他配置文件中可以直接使用:

location / {
    proxy_pass http://127.0.0.1:8080;
    include proxy_params;
}

NGINX 负载均衡

负载均衡的作用是分摊压力,因此需要一台服务器暴露在外面用于分配工作,其他的服务器用于实际承担工作内容,因此需要定义一个“负载均衡池”,就是一个定义工作服务器的清单。这个清单在 NGINX 中称为 upstream

配置模板:

upstream backend {
    server backend1.example.com       weight=5;
    server backend2.example.com:8080;
    server unix:/tmp/backend3;

    server backup1.example.com:8080   backup;
    server backup2.example.com:8080   backup;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

配置说明:定义了一个负载均衡池,其中有五台机器。weight 定义了权重,数值越大,分配使用的概率越大。backup 则是定义为备用机器,在其他机器可用的时候不会使用,只有当全部非备用机器宕机后才会实际使用。

upstream 中支持健康检查功能,可检测服务器的可用性,并对此进行实时调整。

配置模板:

resolver 10.0.0.1;

upstream dynamic {
    zone upstream_dynamic 64k;

    server backend1.example.com      weight=5;
    server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
    server 192.0.2.1                 max_fails=3;
    server backend3.example.com      resolve;
    server backend4.example.com      service=http resolve;

    server backup1.example.com:8080  backup;
    server backup2.example.com:8080  backup;
}

server {
    location / {
        proxy_pass http://dynamic;
        health_check;
    }
}
参数 说明
down 不参与负载均衡
backup 预留的备份服务器
max_fails 允许请求失败的次数
fail_timeout 达到允许请求失败的次数后, 会在此时间内不参与负载均衡
max_conns 限制最大的接收连接数

负载均衡调度算法

方式 说明
轮询 按时间顺序逐一分配到不同的后端服务器(默认)
weight 加权轮询,值越大,分配到的访问几率越高
ip_hash 每个请求按访问IP的校验结果分配,来自同一IP的固定访问一个后端服务器(不推荐)
url_hash 按照访问URL的校验结果来分配请求,每个URL定向到同一个后端服务器(不推荐)
least_conn 最少连接数,哪个机器连接数少就分发新连接

NGINX 缓存

通常情况下缓存是用来减少后端压力,将压力尽可能的往前推,减少后端压力,提高网站并发延时。

通常在完善架构下会使用 MemcachedRedis 来优化缓存,提高缓存的 IO ,加快取用速率。

语法:

proxy_cache zone | off;
默认参数:proxy_cache off;
语句位置:http, server, location

缓存路径:

proxy_cache_path path [levels=levels]
[use_temp_path=on|off] keys_zone=name:size [inactive=time]
[max_size=size] [manager_files=number] [manager_sleep=time][manager_threshold=time]
[loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off]
[purger_files=number] [purger_sleep=time] [purger_threshold=time];
默认参数:—
语句位置:http

缓存有效期:

proxy_cache_valid [code ...] time;
默认参数:—
语句位置:http, server, location

示例:
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;

缓存支持断点续传:

location /tmp-test/ {
                proxy_cache tmp-test;
                proxy_cache_valid  200 206 304 301 302 10d;
                proxy_cache_key $uri;
                proxy_set_header Range $http_range;
                proxy_pass http://127.0.0.1:8081/media_store.php/tmp-test/;
}

NGINX 实例

1.1 NGINX 用反向代理实现动静分离实例

将用户的访问的请求分离,动态请求和静态请求剥离开,保证服务的可用性,即使某一种不可用也不影响另一种。

系统 部署服务 地址 节点
CentOS NGINX 192.168.69.112 N.1
CentOS NGINX 192.168.69.113 N.2
CentOS Tomcat 192.168.69.114 N.3

在节点 2 (192.168.69.113)操作:

新建配置文件:

[root@domain ~]# vim /etc/nginx/conf.d/access.conf 

写入以下内容:

server{
        listen 80;
        root /code;
        index index.html;

        location ~ .*\.(png|jpg|gif)$ {
                gzip on;
                root /soft/code/images;
        }
}

准备一个静态资源(png)

[root@domain ~]# wget -O /code/images/nginx.png http://nginx.org/nginx.png

在节点 3 (192.168.69.114)操作:

部署动态环境:

[root@domain ~]# wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-9/v9.0.7/bin/apache-tomcat-9.0.7.tar.gz
[root@domain ~]# mkdir /opt/tomcat
[root@domain ~]# tar xf apache-tomcat-9.0.7.tar.gz -C /opt/tomcat/

编辑动态页面:

[root@domain ~]# vi /opt/tomcat/apache-tomcat-9.0.7/webapps/ROOT/java_test.jsp

写入以下内容:(注意不要使用vim

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<HTML>
    <HEAD>
        <TITLE>JSP Test Page</TITLE>
    </HEAD>
    <BODY>
      <%
        Random rand = new Random();
        out.println("<h1>Random number:</h1>");
        out.println(rand.nextInt(99)+100);
      %>
    </BODY>
</HTML>

在节点 1 (192.168.69.112)操作:

编辑配置文件:

[root@domain ~]# vim /etc/nginx/conf.d/proxy.conf 

写入以下内容:

upstream static {
        server 192.168.69.113:80;
}

upstream java {
        server 192.168.69.114:8080;
}

server {
        listen 80;
        server_name 192.168.69.112;

        location / {
                root /code;
                index index.html;
        }

        location ~ .*\.(png|jpg|gif)$ {
                proxy_pass http://static;
                include proxy_params;
        }

        location  ~ .*\.jsp$ {
                proxy_pass  http://java;
                include proxy_params;
        }

}

编辑网页文件:

[root@domain ~]# vim /code/index.html

写入以下内容:

<html lang="en">
<head>
        <meta charset="UTF-8" />
        <title>测试ajax和跨域访问</title>
        <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<script type="text/javascript">
$(document).ready(function(){
        $.ajax({
        type: "GET",
        url: "http://192.168.69.112/java_test.jsp",
        success: function(data) {
                $("#get_data").html(data)
        },
        error: function() {
                alert("fail!!,请刷新再试!");
        }
        });
});
</script>
        <body>
                <h1>测试动静分离</h1>
                <img src="http://192.168.69.112/nginx.png">
                <div id="get_data"></div>
        </body>
</html>

部署完成,现在访问

http://192.168.69.112/java_test.jsp
http://192.168.69.112/nginx.png
http://192.168.69.112/index.html

查看效果

1.2 NGINX 通过识别 USER-AGENT 实现不同浏览器(设备)访问不同页面

示例配置:

http {
...
    upstream firefox {
        server 172.31.57.133:80;
    }
    upstream chrome {
        server 172.31.57.133:8080;
    }
    upstream iphone {
        server 172.31.57.134:8080;
    }
    upstream android {
        server 172.31.57.134:8081;
    }
    upstream default {
        server 172.31.57.134:80;
    }
...
}

server {
    listen       80;
    server_name  www.wavengine.com;

    location / {
        if ($http_user_agent ~* "Safari"){
        proxy_pass http://dynamic_pools;
        }     

        if ($http_user_agent ~* "Firefox"){
        proxy_pass http://static_pools;
        }

        if ($http_user_agent ~* "Chrome"){
        proxy_pass http://chrome;
        } 

        if ($http_user_agent ~* "iphone"){
        proxy_pass http://iphone;
        }

        if ($http_user_agent ~* "android"){
        proxy_pass http://and;
        }

        proxy_pass http://dynamic_pools;
        include proxy.conf;
        }
    }
}

1.3 NGINX 实现访问不同路径使用不同服务器

方式一:使用负载池

upstream static_pools {
    server 10.0.0.9:80  weight=1;
}
upstream upload_pools {
    server 10.0.0.10:80  weight=1;
}
upstream default_pools {
    server 10.0.0.9:8080  weight=1;
}

server {
    listen       80;
    server_name  www.domain.com;

#url: http://www.domain.com/
    location / { 
        proxy_pass http://default_pools;
        include proxy.conf;
    }

#url: http://www.domain.com/static/
    location /static/ {
        proxy_pass http://static_pools;
        include proxy.conf;
    }

#url: http://www.domain.com/upload/
    location /upload/ {
        proxy_pass http://upload_pools;
        include proxy.conf;
    }
}

方式二:使用判断语句实现

if ($request_uri   ~*   "^/static/(.*)$")
{
        proxy_pass http://static_pools/$1;
}
if ($request_uri   ~*   "^/upload/(.*)$")
{
        proxy_pass http://upload_pools/$1;
}
location / { 
    proxy_pass http://default_pools;
    include proxy.conf;
}


参考链接

回复