前端运维-nginx必备

nginx简介

Nginx是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。在高连接并发的情况下,Nginx是Apache服务器不错的替代品。

  • nginx的优势

    • 高并发高性能
    • 可扩展性好,跨平台 - 模块拓展
    • 高可靠性 - 宕机概率很小
    • 热部署
    • 开源许可
    • 等等
  • nginx 的最重要的几个使用场景:

  1. 静态资源服务,通过本地文件系统提供服务;
  2. 反向代理服务,延伸出包括缓存、负载均衡等;
  3. api接口服务

nginxnode.js 的很多理念类似,HTTP服务器、事件驱动、异步非阻塞等。nginx 擅长于底层服务器端资源的处理(静态资源处理转发、反向代理,负载均衡等),总之目前形式,在服务器上应用非常广泛

nginx架构之工作模式

    1. nginx启动后,有一个master进程和多个相互独立的worker进程
    1. 每个worker进程都有可能处理request连接
    1. master进程可以监控worker进程的运行状态,当worker进程异常退出,会自动启动新的worker进程
微信图片_20221012101710.jpg
  • worker进程数,一般会设置成机器cpu核数。因为更多的worker数,只会导致进程相互竞争CPU,从而带来不必要的上下文切换
  • 使用多进程模式,不仅能提高并发率,而且进程之间相互独立,一个worker进程挂了不影响其它woker进程的工作
  • CPU亲和,把CPU内核和nginxworker进程绑定在一起,让每个worker进程固定在一个CPU上执行,从而减少CPU的切换并提高缓存命中率提高性能

nginx的安装

注意不同的linux的操作系统安装命令不同,以下全部在centos7.x环境运行

安装依赖
yum install -y gcc gcc-c++ autoconf pcre pcre-devel zlib zlib-devel openssl openssl-devel
添加安装源

创建nginx.repo文件

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

添加如下内容

[nginx] 
name=nginx repo 
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0 
enabled=1
安装nginx
yum install -y nginx

也有其他方式比如安装包直接安装,docker镜像安装...

  • nginx -v 查看版本号
  • nginx -V 查看安装nginx配置的参数。查看可执行文件,配置文件,日志文件,第三方模块文件路径
  • nginx -t 检查配置是否正确
  • rpm -ql nginx查看nginx安装文件的详细路径

启动/关闭命令

  • 启动systemctl start nginx.service
  • 重新加载配置 nginx -s reload或systemctl reload nginx.service
  • 停止systemctl stop nginx.service或nginx -s stop
  • 重启systemctl restart nginx.service或nginx -s reopen
  • 开启自启systemctl enabled nginx.service
  • 关闭开机自启systemctl disabled nginx.service

nginx模块介绍

nginx的所有功能都是以模块的形式累加形成,模块也非常多。这包括核心模块和功能模块,针对不同的应用场景,并非所有的功能模块都要被用到。模块可参考如下3个网站

官方文档
官方文档翻译版
Nginx中文参考手册,教程

nginx处理请求的流程

  • 客户端请求
  • 读取http请求的请求行,请求头,请求体
  • 根据域名确认使用哪个server配置
  • server_rewriteserver内部的重写)
  • 匹配location
  • rewritelocation内部的重写)
  • 访问控制(每个ip每秒的并发数)
  • 生成内容(return , 硬盘, 反向代理)
  • 响应过滤(gzip sub_filter
  • 打印日志(错误和访问日志)
  • 返回给客户端

nginx配置解读

内置变量
  • $http_host 请求的主机名称
  • $requet_uri 请求的url地址
  • $request_method 请求的http方法
  • $request http的请求行
  • $remote_addr 客户端地址
  • $remote_user 客户端名称
  • $http_referer
  • $http_user_agent
  • $http_x_forwarded_for 转发客户端请求头的ip地址
  • $proxy_add_x_forwarded_for 通过(proxy_set_header X_Forwarded_For: $proxy_add_x_forwarded_for配置透传客户端合代理ip
  • $arg_[参数名称] http请求参数名称
  • $http_[HEADER] http的请求头 如:$http_referer $http_user_agent
  • $send_http_[HEADER] http的响应头 如:$send_http_cookie
核心配置示例

整体上的配置块如下所示

main {
  ...
  http {
    upstream { ... }
    server {
      if() {}
      location { ... }
    }
  }
}

更详细的核心配置如下

cat /etc/nginx查看nginx配置如下


user  root; # 用于配置worker进程的用户和用户组(如果指定的用户不存在,则报错)
worker_processes  auto; # 配置 worker进程的个数,建议和CPU核数一样
error_log  /var/log/nginx/error.log notice;  # 配置错误日志存放路径 [日志级别]
pid        /var/run/nginx.pid; # 配置master进程的进程号和进程号ID的文件路径,位于全局块
events {
    worker_connections  1024; # 每个worker进程允许最大的连接数
}
http {
    charset utf-8;
    include       /etc/nginx/mime.types; # 设定mime类型,类型由mime.types文件定义
    default_type  application/octet-stream; # 默认的mime类型,如果mime.types文件找不到使用默认的文件类型
    # 日志格式(自定义输出内容) 和 日志的级别
    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  /var/log/nginx/access.log  main; # 访问日志路径
    
    # 下方3个建议同时开启,静态资源服务器应用起到优化的作用
    sendfile        on; # 提高处理静态资源的性能,系统读取的文件数据直接发送给网络不再经过ng。如果配置反向代理不起作用
    #tcp_nopush     on; # 减少网络报文段的数量,可以在达到一定的数据后一起发送。仅在使用sendfile的时候使用
    tcp_nodelay     on; # 在keep-alive开启的情况生效,来提高网络包传输的'实时性'和tcp_nopush的作用相反
    
    keepalive_timeout  65; # 配置 长连接超时时间
    #keepalive_requests 120; # 配置 一个长连接 可以处理的请求的个数,超过这个个数就会断开该连接
    
    #gzip  on; # 是否开启gzip压缩
    #gizp_comp_level 6; # 压缩级别
    #gzip_min_length 1k; # 内容超过1k才参与gzip
    #gzip_http_version 1.1; # 启用gzip压缩的最小http版本
    #gzip_static on; # 如果是提前`gzip`过的需要启用此配置
    #gzip_types text/css appliction/javascript text/html; # 压缩的文件类型
    
    # 其它配置文件
    include /etc/nginx/conf.d/*.conf; 
    
    server {
        listen       80; # 服务监听端口
        server_name  test.222.com test1.222.com; # 服务使用的域名可以是ip/域名/localhost,可配置多个

        #access_log  /var/log/nginx/host.access.log  main;  # 单独 为该服务定义一个日志路径,而不是使用全局的

        #ssl_certificate /root/nginx/ssl/test.222.com.pem;   # 证书文件地址 https需要
        #ssl_certificate_key /root/nginx/ssl/test.222.com.key;  # 私钥文件地址 https需要

        # 定义访问改服务URI的匹配规则
        location / {
            root   /usr/share/nginx/html; # 根目录
            index  index.html index.htm; # 默认访问文件
        }

        #error_page  404              /404.html; # 404页面

        error_page   500 502 503 504  /50x.html; # 状态码500 502 503 504重定向到/50x.html
        # 精确匹配
        location = /50x.html {
            root   /usr/share/nginx/html; # 根目录
        }
    }
}

上述配置日志格式log_format是含有访问ip,访问用户,时间,请求行,请求响应状态码,访问referer,访问客户端ua,转发的ip

执行/var/log/nginx/access.log可以实时在控制台查看日志,如下

access_log.png

上述是一个最简单的静态资源服务的nginx配置。当你访问test.222.com或者test1.222.com(前提是这两个域名已经备案并添加了解析)时,nginx就会访问匹配到上述配置的server,在server内部会根据访问路径命中location。上述只配置了/前缀命中所有路径,然后根据路径会访问/usr/share/nginx/html目录下的文件

server配置块

server 是配置服务的,可以理解成针对域名形式的路由匹配。

根据配置的server_name匹配优先级顺序如下所示

  • 精准匹配
  • *在前
  • *在后
  • 正则匹配
  • default_server

即优先级如下:

test.222.com > *.222.com > test.222.*>~(\w+)\.test\.222\.com$ > default.conf文件的配置

location匹配规则
  • location仅匹配请求路径,忽略请求参数
  • 前缀字符串
    • 常规(前缀)
    • = 精准
    • ^~ 忽略正则的前缀匹配
  • 正则匹配
    • ~ 大小写敏感的正则匹配
    • ~*大小写不敏感的正则匹配

匹配的优先级顺序如图

ng_location_img.png
  • =优先级最高;一旦成功不在查找其它项
  • ^~一旦匹配成功;不在查找其它项
  • 正则表达式的优先级次之,如果多个location的正则匹配,则使用正则表达式最长的那个
  • 常规字符串匹配类型按前缀匹配
location ~ /Test/$ {
  return 200 "匹配到的第一个正则";
}

location ~* /Test/(\w+)$ {
  return 200 "匹配到的最长的正则";
}

location ^~ /Test/ {
  return 200 "忽略后续的正则";
}

location /Test/a {
  return 200 "最长的前缀匹配";
}

location /Test {
  return 200 "前缀匹配";
}

location = /Test {
  return 200 "精确匹配"
}

访问下边4个地址分别得到的请求结果

/Test -> 精确匹配
/Test/ -> 忽略后续的正则
/Test/a -> 匹配到的最长的正则
/test/a -> 匹配到的最长的正则

rewrite使用

可以实现url的重写和重定向

rewrite 正则 replacement  [flag]

作用域server/http

  • 请求的地址如果匹配到了正则,会被后边的replacement替换,然后通过[flag]标识符决定后一步的处理行为

示例

 rewrite ^(.*)$  https://$host$1 permanent;  # 可以让http重定向到https

使用场景

  • URL页面跳转 http -> https,/a-> /b
  • 兼容旧版本
  • SEO优化(伪静态)/:id.html => /:id
  • 维护提示

[flag]标识符列举

  • last 返回200 地址栏不发生变化
  • break 返回200 地址栏不发生变化
  • redirect 临时重定向; 返回302,地址栏发生变化
  • permanent 永久重定向; 返回301,地址栏发生变化

lastbreak的区别

  • rewrite规则在location{}外,breaklast作用一样,遇到breaklast后,其后续的rewrite/return语句不再执行。但后续有location{}的话,还会近一步执行location{}里面的语句,当然前提是请求必须要匹配该location
  • rewrite规则在location{}里,遇到break后,本location{}与其他location{}的所有rewrite/return规则都不再执行。
  • rewrite规则在location{}里,遇到last后,本location{}里后续rewrite/return规则不执行,但重写后的url再次从头开始执行所有规则,哪个匹配执行哪个。

前端应用场景

监控nginx状态
stub_status on/off;

作用域范围server/location

配置示例:

location /status {
         stub_status on;
}

访问该路径会看到nginx当前的处理状态

微信截图_20221013173046.png
  • Active connections 当前所有处于打开状态的连接数
  • accepts 总处理的连接数
  • handled 总成功创建握手数
  • requests 总处理的请求数
  • Reading 正在读取客户端的连接数
  • Writing 正在响应数据到客户端的数量
  • Waiting 正在等待下一次请求的驻留连接数
请求限制

需要先安装yum install -y httpd-tools

模拟请求ab -n 40 -c 20 http://127.0.0.1

  • -n 总共请求的次数
  • -c 并发的请求数,每秒请求的数量

请求连接的限制

limit_conn_zone $binary_remote_addr zone=conn_zone:10m; 

作用域范围http;定义共享区域大小

limit_conn conn_zone 1; # 指定限制域,请求连接每秒限制1个
limit_conn_status 500; # 限制拦截的状态返回500
limit_conn_log_level warn; # 失败的日志级别
limit_rate 50; # 每秒服务器只能给客户端50字节的数据

作用域范围http/server/location

请求数限制

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

作用域范围http;定义共享域大小,每秒一个ip只能请求1次

limit_req zone=req_zone burst=3;
  • burst可以暂存的最大请求数;比如某一个客户端同时发送5个请求,那么这一秒处理1个,暂存3个,失败一个。暂存3个会在将来有序被处理
访问控制
  • 基于IP的访问控制 -http_access_module
  • 基于用户登录信息的访问控制 -http_auth_basic_module
location = /admin.html {
  deny ip;
  allow all;
}

作用域范围http/server/location

设置缓存

注意缓存仅仅设置静态资源,不要设置动态资源

expires 1h;  # 设置缓存时间
add_header Cache-Control no-cache / no-store / public / private; # 设置缓存策略 no-store不缓存,no-cache协商缓存 , public可以被任何对象缓存,private只能针对个人用户不能被代理服务器缓存
支持跨域

当服务端不支持跨域并且服务端也是经过nginx代理,可以在nginx配置cros跨域的支持,如下

add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers token,xxx;
add_header Access-Control-Allow-Credentials 'true';
add_header Access-Control-Max-Age 6h;
if ($request_method = 'OPTIONS') {
       return 204;
}

可以配置http/server/location块内

防盗链

如果你的静态资源不希望被别的的站点访问,可以设置防盗链,仅仅只支持自己的站点访问,可以配置如下

location ~* \.(gif|jpg|png)$ {
    valid_referers none blocked 域名/ip; # 没有refer 具体域名/ip可以访问
    if ($invalid_referer) { # 上述配置后会得到一个内置变量$invalid_referer,该变量false直接返回403
      return 403; # 无效的referer返回403状态
    }
}

curl -e "ip" url模拟加referer访问具体url

正向代理
正向代理.jpg

对于访问目标来说,代理的是客户端。对于公司局域网内往往会有一个代理来访问外网以进行局域网内网络访问控制,还有vpnCharles等都是正向代理的应用。nginx配置正向代理如下:

resolver 114.114.114.114; # DNS解析
location {
  proxy_pass http://$http_host$http_rui # 
}
反向代理
反向代理.jpg

反向代理,其实对客户端无感知的;因为客户端不需要任何配置就可以访问,只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端。暴露的是代理服务器地址,隐藏了真实服务器IP地址。

  • 保护了真实的web服务器,web服务器对外不可见
  • 节约了有限的IP地址资源
    • 在所有的服务器之间使用私有地址(局域网内的地址)访问,不分配真正的外网的ip
  • 减少web服务器压力,提高响应速度
    • 可以适当在代理服务缓存结果
  • 跨域
  • 请求的统一控制(权限、过滤规则)
  • 等等
location / {
    proxy_pass http://127.0.0.1:3000; # 真实的服务
    index  index.html index.htm;
    proxy_pass http://xxxxx.com;
    proxy_set_header Host $http_host; # 向后传递host请求头
    proxy_set_header X-Real_IP $remote_addr; # 向后传递前一个客户端请求的ip地址
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 层层传递客户端和代理服务器ip
    proxy_connect_timeout 90;  # 连接超时时间
    proxy_send_timeout 90; # 连接成功后等候服务器响应时间
    proxy_read_timeout 90; # 服务器数据回传时间就是在规定时间之内服务器必须传完所有的数据
    proxy_buffer_size 4k;
    proxy_buffers 4 32k;
    proxy_busy_buffers_size 64k;
    proxy_temp_file_write_size 64k;
    ...
}

注意事项

  • proxy_pass后的url最后加上/就是绝对路径,localtion中匹配的路径部分不走代理,也就是会被替换掉。
location /api/ {
    proxy_pass http:/test.222.com/;
}

访问 http://xxxx/api/user -> http:/test.222.com/user

  • proxy_pass后的url最后如果没有/就是相对路径,location中匹配的路径会走代理也就是会保留location匹配的路径
location /api {
    proxy_pass http:/test.222.com;
}

访问 http://xxxx/api/user -> http:/test.222.com/api/user

负载均衡
  • 服务器的处理能力,存储空间不足,而扩容永远也满足不了实际的问题
  • 集群可以解决高并发,流量过高导致服务器压力大的问题
upstream upName {
  server xxx1.com;
  server xxx2.com;
  server xxx3.com;
}

location / {
  proxy_pass http://upName;
}

分配策略

  • 轮巡
  • 权重轮巡
upstream upName {
  server xxx1.com weight=1;
  server xxx2.com weight=2;
  server xxx3.com weight=3;
}
  • ip_hash相同的ip始终命中固定服务器
upstream upName {
  ip_hash;
  server xxx1.com;
  server xxx2.com;
  server xxx3.com;
}
  • least_conn 哪个服务的连接数最小命中哪一个
  • url_hash 固定的url不变命中的服务器也会固定。需要安装第三方模块才可以使用
upstream upName {
  url_hash;
  ...
}
  • fair 按后端的响应时间划分,越快的服务被分配。需要安装第三方模块才可以使用

根据服务器的运行状态

upstream upName1 {
  server xxx.com down/backup/max_conns/max_fair=3 max_fair_timeout=10s/
}
  • down 服务器挂了,不参与分配
  • backup 备份服务,其它服务挂了才会使用该服务
  • max_fair=3 max_fair_timeout=10s 服务响应失败3次休眠10s,过了这个时间段恢复正常
  • max_conns 服务链接最大数

结语

以上介绍了nginx的知识点以及在前端的应用场景。运用到实际项目的生产环境还需针对实际问题做不同的nginx配置。ps:虽然在稍微大一点的公司nginx操作不属于前端职责,但我们也需要储存nginx知识,以备不时之需~

你可能感兴趣的:(前端运维-nginx必备)