百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Nginx 那些事

toyiye 2024-06-21 12:39 9 浏览 0 评论

Nginx 是什么

Nginx(即 [engine x]),它是一个基于异步框架的网页服务器,同时,它也可以用作反向代理服务器、负载均衡服务器、邮件代理服务器和通用 TCP/UDP 代理服务器,最初由俄罗斯程序员 Igor Sysoev,它是一个基于异步框架的网页服务器,同时,它也可以用作反向代理服务器、负载均衡服务器、邮件代理服务器和通用 TCP/UDP 代理服务器,最初由俄罗斯程序员 [Igor Sysoev")编写实现。它在 Yandex[1]Mail.Ru[2]等网站均有应用。

根据权威机构 Netcraft[3] 2022年8月26日发布的最新调查数据[4]显示,Nginx 服务和代理已经超越 Apache,在主流网站中市场份额中占有率最高。可参考下图:

nginx_market

为什么使用 Nginx

Nginx 最核心的是高性能,它可以让 Web 服务器在高并发压力下正常提高服务。基于事件驱动型设计、全异步的网络 I/O 处理机制、极少的进程间切换以及许多优化设计,使得 Nginx 天生善于处理高并发压力下的网络请求,同时Nginx降低了资源消耗,可以把服务器硬件资源发挥到极致。Nginx 的主要特性可概括如下:

nginx_function

如何使用

Nginx 安装

首先是 Nginx 的安装,可以从 `Nginx`官网[5]下载安装,具体安装步骤这里就不展开讲了(如果需要自己开发或者自定义 Nginx 相关模块,可以选择从源码构建,需要安装GCCPCREzlibOpenSSL等相关库,这里先作为了解,不展开)

Nginx 配置文件

首先打开 nginx.conf,通过命令行 vi /usr/local/etc/nginx/nginx.conf 查看配置项:

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    server {
        listen       8080;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            root   html;
            index  index.html index.htm;
        }
        #error_page  404              /404.html;
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.phpnbsp;{
        #    proxy_pass   http://127.0.0.1;
        #}
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.phpnbsp;{
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;
    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;
    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;
    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    include servers/*;
}

常见命令

我们可以通过命令行 nginx -h,查看 Nginx 常见命令,如下

nginx_help

对于 Nginx 来讲,日常一般应用使用最高频的配置文件就是 nginx.conf 了,这里我们以更改该配置文件为例,了解下会涉及到哪些命令行操作。

我们先将 nginx.conf 中监听的服务端口号改为 8082,目的是将 Nginx 的服务将由默认的 http://localhost:80/ 转移到 http://localhost:8082/,配置更改如下

server {
    listen 8082;
}

由于 Nginx 对配置文件有严格的缩紧语法要求,所以当我们更改了配置文件后,可以通过命令行:

nginx -t

对配置文件格式进行正确性检测,可以看到如下信息,表示配置文件语法正确无误:

nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

接着,我们需要重新加载 Nginx 配置,才能使刚才的更改生效,如下

nginx -s reload

生效后,我们访问 http://localhost:8082/ 页面,可以看到 Nginx 默认页面已出现,配置已经生效

nginx-port

如果我们要强制停止运行该服务,可使用

nginx -s stop

-s 参数其实是告诉 Nginx 程序向正在运行的 Nginx 服务发送信号量,Nginx 程序通过 nginx.pid 文件中得到 master 进程的进程 ID,再向运行中的 master 进程发送 TERM 信号来快速地关闭该服务。

我们也可以通过 kill 命令直接向 nginx master 进程发送 TERM 或者 INT 信号,如下

# 先查看当前运行进程
ps -ef | grep nginx
501 59054     1   0 10:21上午 ??         0:00.01 nginx: master process nginx -q 
501 60079 59054   0 10:54上午 ??         0:00.01 nginx: worker process 

# 直接 kill
kill -s SIGINT 59054 
or 
kill -s SIGTERM 59054

如果希望 Nginx 服务可以正常地处理完当前所有请求再停止服务,可以使用

nginx -s quit

其他命令可以使用 nginx -h 命令查询使用。

常见配置有哪些

静态资源文件

Nginx 作为网页服务器,可以指定静态资源文件所在位置,具体配置如下:

location / {
    #指定静态资源文件到桌面的 index.html 文件
    root   /Users/apple/Desktop/;
    index  index.html index.htm;
}

nginx -s reload 加载配置,查看页面,可以看到页面已经从默认页转到了我们指定的页面

gzip 压缩

在日常开发过程中,我们经常会涉及到性能优化,特别是针对服务端返回的内容,而在 Nginx 中开启 gzip 就是一个有效的优化手段。

nginx gzip 配置可以参考 ngx_http_gzip_module[6],示例配置如下:

#是否开启gzip模块,on表示开启,off表示关闭
gzip  on;
##设置允许压缩的页面最小字节(从header头的Content-Length中获取) ,当返回内容大于此值时才会使用gzip进行压缩,以K为单位,当值为0时,所有页面都进行压缩。建议大于1k
gzip_min_length 1000;
##设置用于处理请求压缩的缓冲区数量和大小。比如32 4K表示按照内存页(one memory page)大小以4K为单位(即一个系统中内存页为4K),申请32倍的内存空间,建议使用默认值
gzip_buffers  32 4k;
#用于识别http协议的版本,默认在http/1.0的协议下不开启gzip压缩
gzip_http_version  1.0;
#指定压缩的MIME类型,线上配置时尽可能配置多的压缩类型
gzip types  text/plain application/xml text/css text/xml application/javascript;
#可以让前端的缓存服务器缓存经过gzip压缩的页面; 表示在传送数据时,给客户端说明使用了gzip压缩
gzip_vary  on
#根据请求和响应启用或禁用代理请求的响应gzip压缩。请求被代理的事实是由Via请求头字段的存在决定的
gzip_proxied  expired no-cache no-store private auth;

开启压缩功能后,可以使用 ab(Apache bench) 命令进行压测,验证效果。

基于客户端 IP 地址的访问控制

Nginx 可以通过 ngx_http_access_module[7] 模块实现基于客户端 IP 地址的访问控制,配置如下:

location / {
    allow 10.37.129.2;
    allow 192.168.31.246;
    deny all;
}

通过以上配置,我们就可以实现访问 IP 白名单或者说黑名单,仅仅放行 10.37.129.2&1192.168.31.246 这两个 IP进行访问,其余 IP 一律返回 403 Forbidden,当然,也可以配置 IP 网段进行控制。

响应速度限制

结合 IP 地址的访问控制,更进一步,如果我们想要防止多个用户下载时占用过高的带宽,可以针对指定资源文件进行限速处理,比如我们针对 mp4 类型文件进行限制,当下载文件大小超过 500k 时,限制其下载速率为 50k,这里是不是可以联想到某知名网盘,可如下配置:

location /mp4/ {
    mp4;
    limit_rate_after 500k;
    limit_rate       50k;
}

限制来自同一个地址的同时连接或请求的数量

如果有恶意攻击者对 Web 应用发起流量攻击,短时间内使用脚本无限制地请求Web 应用地址,就会造成该应用带宽流量上升,无法响应其他正常用户的请求,这时候我们可以使用ngx_http_limit_conn_module[8]ngx_http_limit_req_module[9]针对同一个地址的同时连接和请求的数量进行限制,可参考如下配置

  • 同一个地址的同时连接个数限制为 5
http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    ...
    server {
        ...
        location /download/ {
            limit_conn addr 5;
            #限制与虚拟服务器的连接总数
            limit_conn perserver 100;
        }
    }
}
  • 同一个地址的同时请求的数量限制为 5,即平均每秒不超过 5 个请求,并且突发不超过 50 个请求,这里的限制机制采用了 leaky bucket(漏桶算法)[10]算法完成。
http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    ...
    server {
        ...
        location /search/ {
            limit_req zone=one burst=50;
        }
    }
}

基于 IP 的地理定位

最近一段时间,各个互联网平台都对用户 IP 地址进行了展示,那么如何实现基于 IP 的地理定位展示,Nginx 为我们提供了 ngx_http_geoip_module[11] 模块,通过解析 MaxMind GeoIP[12] 库,可以实现地理定位。也可以对指定区域或 IP 进行自定义处理,比如针对来自特定区域 IP 访问进行拦截。相关配置如下:

http {
    #根据客户端 IP 地址确定国家/地区的数据库
    geoip_country GeoIP.dat;
    #根据客户端 IP 地址确定国家、地区和城市的数据库
    geoip_city GeoLiteCity.dat;
    #定义可信地址
    geoip_proxy 192.168.100.0/24;
    #禁用递归搜索
    geoip_proxy_recursive on;
    ...
    server {
        ...
        #可自定义操作,如针对某个国家返回指定页面
        if ($geoip_country_code == 'AT'){
            return something;
        }
        #可自定义操作,如针对某个城市返回指定页面
        if ($geoip_city == 'Bonito'){
            return something; 
        }
    }
}

Nginx 默认情况下不构建此模块,应使用 --with-http_geoip_module 配置参数启用它

njs 脚本语言

通过基于 IP 的地理定位模块,我们知道 Nginx 可以处理一些简单逻辑模块,如果这里要处理的逻辑较多或者说比较复杂,那是不是可以使用现代化编程语言处理,并借用其相关类库,将一个个逻辑抽离到函数中呢?答案是可以的,Nginx 支持了 njs scripting language[13],可以通过 Javascript 语言来处理,比如我们想要将响应正文字符统一转换为小写,可以先写好 Javascript 文件,再引入使用,示例如下:

function to_lower_case(r, data, flags) {
    // 注意这里使用了JavaScript API toLowerCase() 函数,使用函数库,可以简化脚步语言的逻辑
    r.sendBuffer(data.toLowerCase(), flags);
}
export default {to_lower_case};
http {
  js_path "/etc/nginx/njs/";
  js_import main from http/response/to_lower_case.js;
  server {
        listen 80;
        location / {
            #调用引入的JavaScript函数 to_lower_case
            js_body_filter main.to_lower_case;
            proxy_pass http://localhost:8080;
        }
  }
  server {
        listen 8080;
        location / {
            return 200 'Hello World';
        }
  }
}

更多 njs 示例,可以参考njs-examples[14]

反向代理

我们日常使用最多的莫过于 Nginx 的反向代理了,通过反向代理[15],可以隐藏服务端真实调用地址,还可以作为应用层防火墙,为网站的攻击行为提供前置防护。反向代理这块主要配置分为:proxy_passproxy_cacheproxy_sslproxy_buffer

  • proxy_pass主要涉及代理转发相关配置
  • proxy_cache主要用于定义缓存的共享内存区域相关配置
  • proxy_ssl 主要用于 HTTPS 协议转发配置
  • proxy_buffer 主要用于缓冲区相关配置 常用反向代理配置如下:
location /name/ {
    #配置反向代理服务目标地址,由 nginx 进行转发操作
    proxy_pass http://127.0.0.1/remote/;
    #另外,在转发过程中,也可以自定义转发头部字段,如下:
    #默认情况下反向代理是不会转发请求中的Host头部的
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE_HOST $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-NginX-Proxy true;
}

更多配置请查看 http_proxy_module[16]

负载均衡

在微服务理念盛行的今天,负载均衡[17]的重要性更加凸显,负载均衡一般指在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载。可以使用 NginX 作为高效的 HTTP 负载均衡器,将客户端请求分布到多个应用服务器,并通过 NginX 提高 Web 应用程序的性能、可扩展性和可靠性。

如果存在多个后端服务 S1S2S3,我们可以通过设置负载均衡来调节用户访问,如下:

nginx-load-balance

Nginx 主要有三种负载均衡机制:

  • round-robin:即以轮询方式分发客户端的请求,可以参考如下配置:
upstream backend {
    server backend.s1.com   weight=5;
    server backend.s2.com;
    server backend.s3.com;
}
server {
    location / {
        proxy_pass http://backend;
    }
}

请求使用加权循环平衡方法在服务器之间分配。在上面面的示例中,每 7 个请求将按的分配机制是:5 个请求到达 backend.s1.com1 个请求到达 backend.s2.com1 个请求到达 backend.s3.com

  • least_conn[18]: 即最少连接负载均衡。将请求传递到具有最少活动连接数的服务器,同时考虑服务器的权重。如果有多个这样的服务器,则使用加权循环平衡方法依次连接。配置如下:
upstream backend {
    #使用最少连接策略
    least_conn
    server backend.s1.com   weight=5;
    server backend.s2.com;
    server backend.s3.com;
}
server {
    location / {
        proxy_pass http://backend;
    }
}
  • ip_hash[19]:基于客户端 IP 地址在服务器之间分配请求。客户端 IPv4 地址或整个 IPv6 地址的前三个八位字节用作散列密钥。该方法确保来自同一客户端的请求将始终传递到同一服务器,除非该服务器不可用。在后一种情况下,客户端请求将被传递到另一台服务器。这样做的好处是客户端绑定到特定的应用服务器,可以保持持久会话,同时解决动态网页 Session 共享的问题,也可以有效地管理缓存信息。相关配置如下:
upstream backend {
    #使用ip_hash策略
    ip_hash;
    server backend.s1.com   weight=5;
    server backend.s2.com;
    server backend.s3.com;
}
server {
    location / {
        proxy_pass http://backend;
    }
}

除此之外,我们还可以给设置服务器的 keepalive 会话个数和会话有效时间、max_fails设置持续时间内与服务器通信的不成功尝试次数、fail_timeout设置与服务器通信不成功的次数等。

更多配置请查看 ngx_http_upstream_module[20]

其他

Nginx 还可以处理很多需求,如:图像转换[21]正则匹配 URI[22]支持 A/B 测试[23]等。

为什么 Nginx 这么高效

Nginx 性能的高效源自其架构设计的优势,主要包含以下几个点:

nginx_arc

有兴趣可以参考关于 NginX 架构设计Nginx Core Architecture[24]

总结

本文我们主要介绍了 NginX 是什么以及其优势,接下来,主要了解了 NginX 常见命令和配置。另外,介绍了几个 NginX 有意思的模块使用,包括:基于客户端 IP 地址的访问控制、响应速度限制、限制来自同一个地址的同时连接或请求的数量、基于 IP 的地理定位、njs 脚本语言。接着具体介绍了 NginX 反向代理和负载均衡。最后简要总结了 NginX 高性能的几个设计优势。如果你想了解更多关于 NginX 的特性,可以进一步去 官网[25]了解。

参考资料

[1]

Yandex: http://www.yandex.ru/

[2]

Mail.Ru: https://mail.ru/

[3]

Netcraft: https://www.netcraft.com/

[4]

最新调查数据: https://news.netcraft.com/archives/2022/08/26/august-2022-web-server-survey.html

[5]

Nginx官网: https://nginx.org/en/download.html

[6]

ngx_http_gzip_module: https://nginx.org/en/docs/http/ngx_http_gzip_module.html

[7]

ngx_http_access_module: https://nginx.org/en/docs/http/ngx_http_access_module.html

[8]

ngx_http_limit_conn_module: https://nginx.org/en/docs/http/ngx_http_limit_conn_module.html

[9]

ngx_http_limit_req_module: https://nginx.org/en/docs/http/ngx_http_limit_req_module.html

[10]

leaky bucket(漏桶算法): https://en.wikipedia.org/wiki/Leaky_bucket

[11]

ngx_http_geoip_module: https://nginx.org/en/docs/http/ngx_http_geoip_module.html

[12]

MaxMind GeoIP: https://dev.maxmind.com/geoip/release-notes/2022#geoip-legacy-databases-have-been-retired?lang=en

[13]

njs scripting language: https://nginx.org/en/docs/njs/index.html

[14]

njs-examples: https://github.com/nginx/njs-examples

[15]

反向代理: https://zh.wikipedia.org/wiki/%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86

[16]

http_proxy_module: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size

[17]

负载均衡: https://zh.wikipedia.org/wiki/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1

[18]

least_conn: https://nginx.org/en/docs/http/ngx_http_upstream_module.html#least_conn

[19]

ip_hash: https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash

[20]

ngx_http_upstream_module: https://nginx.org/en/docs/http/ngx_http_upstream_module.html

[21]

图像转换: https://nginx.org/en/docs/http/ngx_http_image_filter_module.html

[22]

正则匹配 URI: https://nginx.org/en/docs/http/ngx_http_rewrite_module.html

[23]

支持 A/B 测试: https://nginx.org/en/docs/http/ngx_http_split_clients_module.html

[24]

Nginx Core Architecture: https://zh.booksc.org/book/61672853/b36b22

[25]

官网: https://nginx.org/en/

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码