掘金 后端 ( ) • 2024-04-06 13:14

highlight: atelier-estuary-dark theme: channing-cyan

u=1949822343,443959598&fm=253&fmt=auto&app=120&f=JPEG.webp

nginx目录结构

rpm -ql nginx

位置

1 配置文件所在目录

/usr/local/etc/nginx

2 homebrew 安装软件目录

/usr/local/Cellar/

目录文件

/usr/local/var/www

3 启动ngin x

sudo brew services start nginx

4、查看nginx是否启动成功

ps -ef|grep nginx

显示如下表示成功

 501 15800 1 0 12:17上午 ?? 0:00.00 nginx: master process /usr/local/Cellar/nginx/1.8.0/bin/nginx -c /usr/local/etc/nginx/nginx.conf
 501 15801 15800 0 12:17上午 ?? 0:00.00 nginx: worker process
 501 15848 15716 0 12:21上午 ttys000 0:00.00 grep nginx

这时候如果成功访问localhost:8080,说明成功安装和启动好了。

3 停止nginx

1、修改 nginx.conf 后,重载配置文件

 sudo nginx -s reload
 ​

2、停止 nginx 服务器

 sudo nginx -s stop

4 Nginx配置文件主要分成四部分

  1. main:(全局设置)
  2. server(主机设置)
  3. upstream(上游服务器设置,主要为反向代理、负载均衡相关配置)
  4. location(URL匹配特定位置后的设置),每部分包含若干个指令。

1.全局块:开头到events,影响服务器运行的配置指令

 #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;

备注:

worker_processes 1; #配置处理并发处理量 
pid logs/nginx.pid; #进程号

2.events块:服务器与用户网络连接

 events {
     worker_connections  1024; #最大的连接数
 }

3.http块:包括http块,server块。代理缓存日志等都在这一块配置

 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 ~ .php$ {
         #    proxy_pass   http://127.0.0.1;
         #}
         # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
         #
         #location ~ .php$ {
         #    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对于前端性能以及接口性能优化

nginx确实非常强大大多数情况下很多人只使用了他的基础功能

1. 缓存优化
 location / {
 ​
     root  /var/www/html/fibs/v1;  #主系统
 ​
     error_page 404 /;
        if ($request_filename ~* ^.*?.(json|html|css)$){
               add_header Cache-Control no-cache;
         }
 ​
     if ($request_filename ~* ^.*?.(js|txt|doc|pdf|rar|gz|zip|docx|exe|xlsx|ppt|pptx|jpg|png)$){
       add_header Cache-Control public;
     }
 ​
 }

缓存控制-没有请求就是最好的请求

协商缓存

Last-Modified

我们的单页入口文件是index.html,这个文件呢决定了我们要加载的js以及css,故我们给html文件设置协商缓存Cache-Control no-cache,当我们首次加载时http的状态码为200,服务器会返回一个Last-Modified表示这个文件的最后修改时间,

再次刷新时浏览器会把这个修改时间通过If-Modified-Since发送给服务器,如果没有变动(Etag也会校验),那么服务器会返回304状态码,说我的文件没有变,你直接用缓存吧。

Etag

HTTP协议解释Etag是被请求变量的实体标记,你可以理解为一个id,当文件变化了,这个id也会变化,这个和Last-Modified差不多,服务器会返回一个Etag,浏览器下次请求时会带上If-None-Match,进行对比返回,有些服务器的Etag计算不同,故在做分布式的时候可能会出问题,文件没改动不走缓存,当然你可以关闭这个只使用Last-Modified。

强缓存

我们的单页应用打包时webpack等工具是会根据文件的变化生成对应的js的,也就也是文件不变的话js的hash值不变,故我们在加载js等文件时可以使用强缓存,让浏览器在缓存时间类不进行请求,直接从缓存里面取值,

比如上面我们通过设置expires(Cache-Control也行,这个优先级更高)为30天,那么浏览器下此访问我们相同的缓存过的js和css时(缓存时间内),就直接从缓存里面拿(200 from cache),而不会请求我们的服务器。

注意:此方法是基于上述打包生成hash而言的,假如你生成的是1.js,2.js之类的,那么你修改了1.js里面的类容,打包出来的还是1.js,那么浏览器还是会从缓存里面拿,不会进行请求的。也就是说使用此方式需要确保你修改了文件打包后修改的hash值需要变动。

强制刷新

强缓存用得好的话是飞一般的感觉,但是如果在错误情况下使用就老是走浏览器缓存,如何清理这个呢,我们常用的方式是Ctrl+F5或者在浏览器控制台上把Disable cache给勾上,实际上这个是在请求文件时会自动加上一个header头Cache-Control: no-cache,也就是说我不要缓存,那么浏览器会老老实实的向服务器发出请求。

长连接-减少握手次数

TCP握手以及TLS握手还是比较费时的,比如以前的http1.1之前的连接就是每一条都要进过TCP三次握手,超级费时,还好1.1默认使用了长连接,可以减少握手开销,但是假如你做大文件上传时会发现超过一定时间会断掉,这是由于Nginx默认的长连接时间为75s,超过了就会断开,

当你的网页确实要加载很多很多东西时可以适当把这个时间延长一点,以减少握手次数(keepalive_requests可以限制keep alive最大请求数),至于大文件上传吗你可以选择分片上传,这里就不做介绍了。

server:

 keepalive_timeout 75;  
 keepalive_requests 100; 

gzip压缩优化

 http{
 ​
 # 开启gzip
 ​
 gzip on;
 ​
 # 启用gzip压缩的最小文件;小于设置值的文件将不会被压缩
 ​
 gzip_min_length 1k;
 ​
 # gzip 压缩级别 1-10
 ​
 gzip_comp_level 2;
 ​
 # 进行压缩的文件类型。
 ​
 gzip_types text/plain application/javascript application/x-javascript application/json application/html text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
 ​
 # 是否在http header中添加Vary: Accept-Encoding,建议开启
 ​
 gzip_vary on;
 ​
 }
 ​

其次前端要我们可以配置vue.config.js:

 const CompressionWebpackPlugin = require('compression-webpack-plugin')  
 buildcfg = {  
   productionGzipExtensions: ['js', 'css']  
 }  
 configureWebpack: (config) => {  
   config.plugins.push(  
     new CompressionWebpackPlugin({  
       test: new RegExp('\.(' + buildcfg.productionGzipExtensions.join('|') + ')$'),  
       threshold: 8192,  
       minRatio: 0.8  
     })  
   )  
 }

HTTP/2-更安全的 HTTP、更快的 HTTPS

现在很多网站都启用了HTTP/2,HTTP/2最大的一个优点是完全保持了与HTTP/1的兼容,HTTP/2 协议本身并不要求一定开启SSL,但浏览器要求一定要启用SSL才能使用HTTP/2,头部压缩、虚拟的“流”传输、多路复用等技术可以充分利用带宽,降低延迟,从而大幅度提高上网体验。Nginx开启相当简单

 server {  
   listen       443 ssl http2;  
   ssl_certificate         /etc/nginx/conf.d/ssl/xxx.com.pem;  
   ssl_certificate_key     /etc/nginx/conf.d/ssl/xxx.com.key;  
   ssl_ciphers   ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:!MD5:!SHA1; # 弃用不安全的加密套件 
   ssl_prefer_server_ciphers   on; # 缓解 BEAST 攻击  
 } 

HSTS-减少302重定向

现在大多数网站都是https的了,但是有个问题就是用户在输入网址时一般来说不会主动输入https,走的还是80端口,我们一般会在80端口进行rewrite重写:

 server{  
   listen    80;  
   server_name   test.com;  
   rewrite ^(.*)https://host$1 permanent; // 
 } 

但这种重定向增加了网络成本,多出了一次请求,我想下次访问时直接访问https怎么处理?我们可以使用HSTS,80端口的不变,在443端口的server新增:

 add_header Strict-Transport-Security "max-age=15768000; includeSubDomains;"; 

这相当于告诉浏览器:我这个网站必须严格使用HTTPS协议,在在max-age时间内都不允许用HTTP,下次访问你就直接用HTTPS吧,那么浏览器只会在第一次访问时走80端口重定向,之后访问就直接是HTTPS的了(includeSubDomains指定的话那么说明此规则也适用于该网站的所有子域名)。

Session Ticket-https会话复用

我们知道https通信时,SSL握手会消耗大量时间,使用非对称加密保护会话密钥的生成。而真正传输的是通过对称加密进行通信传输。那么我们每次刷新都进行SSL握手太费时间了,既然双方都拿到会话密钥了,那么用这个密钥进行通信不就可以了,这就是会话复用。

服务器把密钥加密后生成session ticket发送给客户端,请求关闭后,如果客户端发起后续连接(超时时间内),下次客户端再和服务器建立SSL连接的时候,将此session ticket发送给服务器,服务器解开session ticket后拿出会话密钥进行加密通信。

 ssl_protocols               TLSv1.2 TLSv1.3; # 开启TLS1.2 以上的协议  
 ssl_session_timeout         5m; # 过期时间,分钟  
 ssl_session_tickets         on; # 开启浏览器的Session Ticket缓存  

nginx代理解决跨域问题

通过 Nginx 反向代理可以有效地解决跨域问题。下面是一种简单的配置方式:

假设有两个域名为 example.com 和 api.example.com,我们希望在 example.com 上通过 AJAX 请求获取 api.example.com 上的数据,但由于跨域限制,请求被浏览器拦截了。我们可以通过 Nginx 配置反向代理来解决这个问题。

首先,确保 Nginx 已经安装并运行。

编辑 Nginx 的配置文件,通常位于 /etc/nginx/nginx.conf/etc/nginx/sites-available/default。

在配置文件中添加以下内容:

 server {
     listen 80;
     server_name example.com;
 location /api {
     # 定义代理目标
     proxy_pass http://api.example.com;
     # 允许跨域请求
     add_header Access-Control-Allow-Origin *;
     # 允许带身份验证信息的跨域请求
     add_header Access-Control-Allow-Credentials true;
     # 允许的请求方法
     add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
     # 允许的请求头
     add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
     # 预检请求的有效期
     add_header Access-Control-Max-Age 3600;
     # 处理 OPTIONS 请求
     if ($request_method = 'OPTIONS') {
         add_header Content-Type 'text/plain; charset=utf-8';
         add_header Content-Length 0;
         return 204;
     }
     }
 }

重启 Nginx 以使配置生效

Nginx常用实现负载均衡的方式

轮询(Round Robin):

这是默认的负载均衡算法,Nginx按照请求的顺序依次将请求分配给后端的服务器。每个服务器按照其权重来处理请求,然后按顺序循环分配。这种算法简单且平均地将负载分配给后端服务器,适用于后端服务器配置相同、处理能力相当的场景。

 http {
     upstream backend {
         server 192.168.1.101:8080;
         server 192.168.1.102:8080;
         server 192.168.1.103:8080;
     }
 server {
     listen 80;
     
     location / {
         proxy_pass http://backend;
     }
 }
 }

IP哈希(IP Hash):

Nginx根据客户端的IP地址进行哈希运算,并根据计算结果将请求分配给固定的后端服务器。这种算法保证了相同的客户端IP每次请求都会被分配到相同的服务器,适用于需要保持会话状态的应用。

  http {
                 upstream backend {
                     ip_hash;
                     server 192.168.1.101:8080;
                     server 192.168.1.102:8080;
                     server 192.168.1.103:8080;
                 }
  
                 server {
                     listen 80;
                     
                     location / {
                         proxy_pass http://backend;
                     }
                 }
               }

加权轮询(Weighted Round Robin):

Nginx根据每个后端服务器的配置权重将请求分配给服务器。权重越高的服务器,处理的请求就越多。这种方式适用于后端服务器之间配置不同、处理能力不同的情况下。
 http {
     upstream backend {
         server 192.168.1.101:8080 weight=3;
         server 192.168.1.102:8080 weight=2;
         server 192.168.1.103:8080 weight=1;
     }
 server {
     listen 80;
     
     location / {
         proxy_pass http://backend;
     }
 }
 }

最少连接(Least Connections):

Nginx会统计每个后端服务器当前的活动连接数,并将请求分配给活动连接数最少的服务器,以实现负载均衡。这种算法适用于后端服务器配置和处理能力不同、连接持续时间不均衡的场景。

 http {
     upstream backend {
         least_conn;
         server 192.168.1.101:8080;
         server 192.168.1.102:8080;
         server 192.168.1.103:8080;
     }
  
     server {
         listen 80;
         
         location / {
             proxy_pass http://backend;
         }
     }
 }