nginx

nginx

一 系统I/O模型:

1.1.1 同步/异步

关注的是事件处理的消息通信机制,即在等待一件事情的处理结果时,被调用者是否提供完成通知。

同步:synchronous,调用者等待被调用者返回消息后才能继续执行,如果被调用者不提供消息返回则为同步,同步需要调用者主动询问事情是否处理完成。

异步:asynchronous,被调用者通过转态、通知或回调机制主动通知调用者,即异步会主动返回被调用者的状态给调用者。

同步:进程发出请求调用后,内核不提供通知机制,即文件IO处理完成后不通知进程,需要进程自己去问内核是否处理完成
异步:进程发出请求调用后,内核会在调用处理完成后返回调用结果给进程,nginx时异步的。

在这里插入图片描述

1.1.2: 阻塞/非阻塞

关注调用者在等待结果返回之前所处的状态

阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情
非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成,最终的调用者结果返回之前,调用者不会被挂起,可以去做别的事情。

在这里插入图片描述

1.1.3:系统IO模型组合:

在这里插入图片描述

二 nginx基础

2.1 nginx功能介绍

静态的web资源服务器html,图片,js,css,txt等静态资源

结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求

http/https协议的反向代理

imap4/pop3协议的反向代理
tcp/udp协议的请求转发(反向代理)

2.1.1:基础特性
特x性:
模块化设计,较好的扩展性
高可靠性
支持热部署:不停机更新配置文件,升级版本,更换日志文件
低内存消耗:10000个keep-alive链接模式下的非活动连接,仅需2.5M内存
event-driven,aio,mmap,sendfile


基本功能:
静态资源的web服务器
http协议反向代理服务器
pop3/imap4 协议反向代理服务器
FastCGI(lnmp),uWSGI(python)等协议
模块化(非DSO),如zip,SSL模块
2.1.2:和web服务相关的功能
虚拟主机(server)
支持 keep-alive 和管道连接(利用一个连接做多次请求)
访问日志(支持基于日志缓冲提高其性能)
url rewrite
路径别名
基于IP及用户的访问控制
支持速率限制及并发数限制
重新配置和在线升级而无须中断客户的工作进程(reload工作原理 生成两个相同的进程,把新的请求转发到这两个进程上去,原先那两个处理完后在销毁)

在这里插入图片描述

2.2:nginx组织结构

web请求处理机制:
1、多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程相应客户端,直到用户关闭连接,这样的优势是处理速度快,各子进程之间相互独立,但是如果访问过大会导致服务器资源耗尽而无法提供请求。
2、多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程来个客户方进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可以相互访问同样的内存地址空间,所以他们相互影响,另外一旦主进程挂掉则所有子线程都不能工作了,II S服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定
2.2.1: 组织模型

nginx是多进程组织模型,而且是一个由Master主进程和Worker工作进程组成。
在这里插入图片描述

主进程(master process)的功能

读取Nginx 配置文件并验证其有效性和正确性
建立、绑定和关闭socket连接
按照配置生产、配置和结束工作进程
接受外界指令,比如重启、升级及退出服务器等指令
不中断服务,实现平滑升级,升级失败进行回滚处理,重启服务并应用新的配置
开启日志文件,获取文件描述符
编译和处理perl脚本

工作进程(worker process)的功能

接受处理客户的请求
将请求依次送入各个功能模块进行处理
IO调用,获取响应数据
与后端服务器通信,接收后端服务器的处理结果
缓存数据,访问缓存索引,查询和调用缓存数据
发送请求结果,响应客户的请求
接收主程序指令,比如重启、升级和退出等

清空20G日志文件 echo > a.log 不能rm -rf

在这里插入图片描述

2.2.2: 进程间通信

在这里插入图片描述

2.2.3 编译安装nginx
编译的三个过程:
configure 按照参数生成makefile文件
make 按照makefile文件生成模块
make install 把模块拷贝到指定的路径
官方源码包下载地址
https://nginx.org/en/download.html

安装依赖的文件
yum -y install pcre pcre-devel zlib zlib-devel gcc gcc-c++ glibc glibc-devel systemd-devel zip zlib-devel openssl openssl-devel wget
pcre pcre-devel:使nginx支持正则表达式
zlib zlib-devel:使nginx支持gzip压缩
openssl openssl-devel:使nginx支持https


[root@k8s-vip nginx-1.20.2]#./configure --prefix=/apps/nginx \ 
--user=nginx \ 
--group=nginx \ 
--with-http_ssl_module \ 
--with-http_v2_module \ 
--with-http_realip_module \ 
--with-http_stub_status_module \ 
--with-http_gzip_static_module \ 
--with-pcre --with-file-aio \ 
--with-stream \ 
--with-stream_ssl_module \ 
--with-stream_realip_module \ 
--add-module=/usr/local/src/nginx-module-vts/(Prometheus抓取数据的模块) \ 
[root@k8s-vip nginx-1.20.2]# make
[root@k8s-vip nginx-1.20.2]# make install
[root@k8s-vip nginx-1.20.2]# useradd nginx


编写service文件
vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/apps/nginx/logs/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /apps/nginx/logs/nginx.pid
ExecStartPre=/apps/nginx/sbin/nginx -t
ExecStart=/apps/nginx/sbin/nginx
ExecReload=/apps/nginx/sbin/nginx -s reload
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target

在这里插入图片描述

2.2.4 yum 安装nginx
yum install epel-release
yum install nginx -y
2.2.5 默认的配置文件

在这里插入图片描述

三 nginx核心配置

3.1:全局配置

nginx 配置网站 https://nginx.org/en/docs/ngx_core_module.html#daemon

user nginx nginx; 启动Nginx工作进程的用户和组
worker_processes [number | auto]; #启动Nginx工作进程的数量
worker_cpu_affinity auto; #将Nginx工作进程绑定到指定的CPU核心,默任Nginx是不进行进程绑定的,绑定并不是意味着当前nginx进程独占以一核心CPU,但是可以保证此进程不会运行在其他核心上,这就极大减少了ngnx的工作进程在不同的cpu核心上的来回跳转,减少了CPU对进程的资源分配与回收以及内存管理等,因此可以有效的提升nginx服务器的性能。

[root@k8s-vip ~]# while true; do curl 172.16.10.105/234.jpg sleep 0.2s;done;
[root@k8s-vip conf]# watch -n1 'ps -axo pid,cmd,psr | grep nginx' #查看进程变化
  2275 nginx: master process /apps   0
 79168 nginx: worker process         0
 79169 nginx: worker process         1
 82972 grep nginx                    0

#错误日志记录配置,语法:error_log file [debug | info | notice | warn | error | crit | alert | emerg]
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
error_log  /apps/nginx/logs/error.log error;

#pid文件保存路径
pid /apps/nginx/logs/nginx.pid;


worker_priority 0; #工作进程nice值, -20-19  越低优先级越高
worker_rlimit_nofile 65536; #这个数字包括Nginx的所有连接(例如与代理服务器的连接,与后端服务器的连接等),而不仅仅是与客户端的连接,另一个考虑因素是实际的并发连接数不能超过系统级别的最大文件数的限制


daemon off; #前台运行Nginx服务用于测试、docker等环境
master_process off|on; #是否开启Nginx的master-worker工作模式,仅用于开发调试场景

events {   #事件模型配置参数
    worker_connections  1024; #设置单个工作进程的最大并发链接数
    use epoll; # 使用epoll事件驱动,Nginx支持众多的事件驱动,比如select、poll、epoll,智能设置在events模块中
    accept_mutex on;#优化同一时刻只有一个请求而避免多个睡眠进程被唤醒的设置,on为防止被同时唤醒,默认为off,全部唤醒的过程也成为"惊群",因此nginx刚安装完以后要进行适当的优化。
    multi_accept on;#Nginx服务器的每个工作进程可以同时接受多个新的网络连接,但是需要在配置文件中配置,此指令默认为关闭,即默认为一个工作进程只能一次接受一个新的网络连接,打开后几个同时接受多个。
}

3.2:http详细配置

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; #实现文件零拷贝 (原理:nginx调内核,内核调cpu,cpu吧数据调内存,不在往进程拷贝(也不会再进程中构建响应报文,节省两次内存到进程的时间),内存吧数据拷到socket区域,构建响应报文。)
    #tcp_nopush     on; #在开启了sendfile的情况下,合并请求后同意发送给客户端
	#tcp_nodelay on | off; #在开启keepalived模式下的连接是否启动TCP_NODELAY选项,当为off时,延迟0.2s发送,默认为On时,不延迟发送,立即发送用户响应报文。
    #keepalive_timeout  0;
    keepalive_timeout  65 65;#设置会话保持时间

    #gzip  on;# 开启文件压缩
     server {
        listen       80;#设置监听地址和端口
        server_name  localhost;#设置server name,可以以空格隔开写多个并支持正则表达式。如*.magedu.com

        #charset koi8-r;#设置编码格式,默认是俄语模式,可以改为utf-8

        #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;
        }
        #location ~ \.php$ { #以http的方式转发php请求到指定web服务器
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ { #以fastcgi的方式转发php请求到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 {#拒绝web形式访问指定文件,如很多网站都是通过.htaccess文件来改变自己的重定向等功能。
        #    deny  all;
        #}
        location ~ /passwd.html {
            deny all;
        }
    }       
 

3.3 正则表达式

/:正则表达式的开始和结束符号。

^:表示匹配文本的开头。例如,/^abc/ 表示匹配以 "abc" 开头的文本。

$:表示匹配文本的结尾。例如,/abc$/ 表示匹配以 "abc" 结尾的文本。

.:匹配任意单个字符,不包括换行符。例如,/a.c/ 表示匹配以 "a" 开头,"c" 结尾,中间有任意一个字符的文本。

|:表示或,可以用于匹配多个表达式中的任意一个。例如,/abc|def/ 表示匹配 "abc" 或 "def"。

[]:表示字符集,用于匹配一组字符中的任意一个。例如,/[abc]/ 表示匹配字母 "a"、"b" 或 "c" 中的任意一个。

():表示分组,可以将一部分正则表达式放在括号中,并对它们进行分组匹配。例如,/(ab)+/ 表示匹配一或多个 "ab"。

?:表示可选,用于匹配前面的字符或表达式出现零次或一次。例如,/a?b/ 表示匹配零个或一个 "a",后面紧跟一个 "b"。

*:表示零个或多个,用于匹配前面的字符或表达式出现零次或多次。例如,/ab*c/ 表示匹配一个 "a",后面跟着零个或多个 "b",最后紧跟一个 "c"。

+:表示一或多个,用于匹配前面的字符或表达式出现一次或多次。例如,/ab+c/ 表示匹配一个 "a",后面跟着一个或多个 "b",最后紧跟一个 "c"。

{}:表示重复次数,用于指定前面的字符或表达式重复出现的次数范围。例如,/ab{2,4}c/ 表示匹配一个 "a",后面跟着两到四个 "b",最后紧跟一个 "c"。

\:表示转义字符,用于将特殊字符转义为普通字符。例如,/a\./ 表示匹配一个 "a",后面跟着一个 "."。

以上是一些常见的正则表达式符号和元字符的说明,还有一些比较重要的符号和元字符:

[] 中的 ^:表示不在字符集中,用于匹配不属于指定字符集中的任意字符。例如,/[^abc]/ 表示匹配除了 "a"、"b"、"c" 之外的任意字符。

[] 中的 -:表示字符范围,用于匹配指定范围内的任意字符。例如,/[a-z]/ 表示匹配任意小写字母。

() 中的 |:表示分组中的或,可以用于匹配分组中的任意一个表达式。例如,/(ab|cd)/ 表示匹配 "ab" 或 "cd"。


3.4 核心配置实例:

基于不同的IP、不同的端口以及不用的域名实现不同的虚拟主机,依赖于核心模块ngx_http_core_module实现。

3.4.1:构建一个PC web站点
[root@k8s-vip conf.d]# mkdir /apps/nginx/conf/conf.d
[root@k8s-vip conf.d]# cat /apps/nginx/conf/conf.d/pc.conf
server {
   listen 80;
   server_name pc.gf.com;
   location / {
       root /data/nginx/html/pc;
    }
}
[root@k8s-vip conf.d] mkdir /date/nginx/html/pc -p
[root@k8s-vip conf.d] echo "pc server" >/date/nginx/html/pc/index.html
[root@k8s-vip conf.d] vim /apps/nginx/conf/nginx.conf
        include /apps/nginx/conf/conf.d/*.conf;
[root@k8s-vip conf.d] /apps/nginx/sbin/nginx -s reload
访问测试
3.4.2:构建一个Mobile web站点
server {
   listen 80;
   server_name mobile.gf.com;
   location / {
       root /data/nginx/html/mobile;
    }
}
mkdir /data/nginx/html/mobile
echo 'mobile server' > /data/nginx/html/mobile/index.html
/apps/nginx/sbin/nginx -s reload
访问测试
3.4.3: root与alias

root: 指定web的家目录,在定义location的时候,文件的绝对路径等于root+location,如

server {
   listen 80;
   server_name pc.gf.com;
   location / {
       root /data/nginx/html/pc;
    }
    location /about {
       root /data/nginx/html/pc; #必须要在html目录中创建一个about目录才可以访问,否则报错.
       index index.html;
       }
}
mkdir /data/nginx/html/pc/about
echo about > /data/nginx/html/pc/abount/index.html
重启nginx并访问测试

alias:定义路径别名,会把访问的路径重新定义到其指定的路径:如

server {
   listen 80;
   server_name pc.gf.com;
   location / {
       root /data/nginx/html/pc;
    }
    location /about {# 使用alias的时候uri后面如果加了斜杠则下面的路径配置必须加斜杠,否则403
       alias /data/nginx/html/pc; #当访问about的时候,会显示alias定义的/data/nginx/html/pc里面的内容。
       index index.html;
       }
}
重启nginx并访问测试
3.4.4: location的详细使用:

在没有使用正则表达式的时候,nginx会先在server中的多个location选取匹配度最高的一个uri,uri是用户请求的字符串,即域名后面的web文件路径,然后使用该location模块的正则url和字符串,如果匹配成功就结束搜索,并使用location处理此请求。

语法规则: location [=|~|~*|^~] /uri/ {...}
= #用于标准的uri前,需要请求字符串与uri精确匹配,如果匹配成功就停止向下匹配并立即处理请求。
~ #用于标准的uri前,表示包含正则表达式并且区分大小写,并且匹配
!~ #用于标准的uri前,表示包含正则表达式并且区分大小写,并且不匹配

~* #用于标准的uri前,表示包含正则表达式并且不区分大小写,并且匹配
!~* #用于标准的uri前,表示包含正则表达式并且不区分大小写,并且不匹配

^~ #用于标准的uri前,表示包含正则表达式并且匹配以什么开头
$  #用于标准的uri前,表示包含正则表达式并且匹配以什么结尾
\  #用于标准的uri前,表示包含正则表达式并且转义字符。可以转. * ?等
*  #用于标准的uri前,表示包含正则表达式并且代表任意长度的任意字符

在这里插入图片描述

在这里插入图片描述

3.4.4.1:匹配案例-精确匹配

在server部分使用location配置一个web界面,要求:当访问nginx服务器/login的时候要显示指定html文件的内容

server {
   listen 80;
   server_name pc.gf.com;
   location / {
       root /data/nginx/html/pc;
    }
    location /about {
       root /data/nginx/html/pc;
       index index.html;
       }
    location = /1.jpg {
       root /var/nginx/image;
       index index.html;
       }
}
上传图片到/var/nginx/image,重启nginx并访问测试
访问测试   pc.gf.com/1.jpg
3.4.4.2 匹配案例-区分大小写

如果uri中包含大写字母,则一下location匹配Ax.jpg条件不成功,因为~为区分大小写,那么当用户的请求被执行匹配时发现location中定义的是大写的A,则匹配失败,即要么继续往下匹配其他的location(如果有),要么报错给客户端

location ~ /A.?\.jpg { #匹配除换行符\n之外的其他任何单字符0次或多次
       root /var/nginx/image;
       index index.html;
       }
3.4.4.3 匹配案例-不区分大小写
location ~* /A.?\.jpg {
       root /var/nginx/image;
       index index.html;
       }
3.4.4.4 匹配案例-URI开始:
server {
   listen 80;
   server_name pc.gf.com;
   location / {
       root /data/nginx/html/pc;
    }
    location ^~ /images { #匹配以images开头
       root /data/nginx/html/pc;
       index index.html;
       }
    location  /images1 {
       root /data/nginx/html/pc;
       index index.html;
       }
}

3.4.4.5:匹配案例-文件名后缀
server {
   listen 80;
   server_name pc.gf.com;
   location / {
       root /data/nginx/html/pc;
    }
    location ~* \.(gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js)$ {
       root /data/nginx/images;
       index index.html;
       }
} 


    location ~ /images/.*\.((gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js))$ {
       root /data;
       index index.html;
       valid_referers none blocked server_names
          ~\.baidu\.  ~\.google\.;
       if ($invalid_referer) {
            return 403;
          }
       }
重启nginx并访问测试
3.4.4.6:匹配案例-优先级:
server {
   listen 80;
   server_name pc.gf.com;
   location / {
       root /data/nginx/html/pc;
    }
    location ~* /1.jpg {
       root /data/nginx;
       index index.html;
       }
    location = /1.jpg { #通常用于精确匹配指定文件,如favicon.ico、index.jsp等
       root /data/nginx/images;
       index index.html;
       }
}
匹配优先级: = ^~ ~/~* /
location优先级:(location =) > (location 完整路径) > (location ^~路径) > (location ~ ~* 正则顺序) > (location 部分起始路劲) > (/)
3.3.4.7:生产使用案例
直接匹配网站根会加速Nginx访问处理:
location = /index.html {
  ...;
}
location = / {
  ...;
}
静态资源配置
location ^~ /static {
  ...;
}
location ~* \.(gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js)$ {
  ...;
}
多应用配置
location ~* /app1 {
  ...;
}
location ~* /app2 {
  ...;
}

3.5: nginx三层访问控制:

访问控制基于模块ngx_http_access_module实现,可以通过匹配客户端源ip地址进行限制

    location ~* /1.jpg {
       root /data/nginx;
       index index.html;
       allow 172.16.10.105;
       deny all; #先永许小部分,在拒绝大部分
       }

3.6:Nginx账户认证功能:

[root@k8s-vip ~]# yum install -y httpd-tools -y
[root@k8s-vip ~]# htpasswd -cbm /apps/nginx/conf/.htpasswd gf 123456 #第一次要创建文件
[root@k8s-vip ~]# htpasswd -bm /apps/nginx/conf/.htpasswd zyr 123456
    location /login {
        root /data/nginx/html/pc;
        index index.html;
        auth_basic "login passwd";
        auth_basic_user_file /apps/nginx/conf/.htpasswd;
        }

3.7:自定义错误页面

server {
   listen 80;
   server_name pc.gf.com;
   location / {
       root /data/nginx/html/pc;
    }
    location ~* /1.jpg {
       root /data/nginx;
       index index.html;
       #allow 172.16.10.105;
       deny all;
       }
    error_page   500 502 503 504 404  /error.html;
    location = /error.html {
        root   /data/nginx;
     }
}

3.8:自定义访问日志

server {
   listen 80;
   server_name pc.gf.com;
   access_log /var/nginx/logs/pc.gf.com-access.log main;
   error_log /var/nginx/logs/pc.gf.com-error.log info;
   location / {
       root /data/nginx/html/pc;
    }
    location ~* /1.jpg {
       root /data/nginx;
       index index.html;
       #allow 172.16.10.105;
       deny all;
       }
    error_page   500 502 503 504 404  /error.html;
    location = /error.html {
        root   /data/nginx;
     }
}

3.9: 检测文件是否存在

try_files会按顺序检测文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹,如果所有文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内部500错误)

访问:http://127.0.0.1/
$uri:/index.html
$request_uri:/  

location /images {
       root /data/nginx/html;
       try_files $uri /images/index.html;
       #try_files $uri $uri/index.html $uri.html =404;
       #try_files $uri =404;
   }
重启nginx测试,当访问到http://pc.gf.com/images/1 等不存在的uri会显示/images/index.html,如果是自定义状态码则会显示在返回数据的状态码中。

3.10:长连接配置:

keepalive_requests number: 在一次长连接上所永许请求的资源的最大数量,默认为100次

keepalive_timeout number:设定保持连接超时时长,0表示禁止长连接,默认为75s,通常配置在http字段作为站点全局配置

Syntax:	keepalive_requests number;
Default:	
keepalive_requests 1000;
Context:	http, server, location

    keepalive_timeout  65 65(让浏览器显示时长);
开启长连接后,返回客户端的会话保持时间为65s,单词长连接累次请求达到指定次数请求或65秒就会被断开,后面的65为发送给客户端应答报文头部中显示的超时时间设置为65s,如不设置客户端将不显示超时时间。
    keepalive_requests 3; 
	keep-Alive: timeout=60#浏览器收到的服务器返回的报文
如果设置为0表示关闭会话保持功能,将如下显示:
    Connection: close # 浏览器收到的服务器返回的报文。




[root@k8s-vip html]# telnet pc.gf.com 80
Trying 172.16.10.105...
Connected to pc.gf.com.
Escape character is '^]'.
GET / HTTP/1.1  
HOST: pc.gf.com

HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Sat, 06 Jan 2024 05:28:04 GMT
Content-Type: text/html
Content-Length: 19
Last-Modified: Fri, 05 Jan 2024 08:50:39 GMT
Connection: keep-alive
Keep-Alive: timeout=65
ETag: "6597c2df-13"
Accept-Ranges: bytes

<h1>pc server</h1>

GET / HTTP/1.1
HOST: pc.gf.com

HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Sat, 06 Jan 2024 05:28:18 GMT
Content-Type: text/html
Content-Length: 19
Last-Modified: Fri, 05 Jan 2024 08:50:39 GMT
Connection: close
ETag: "6597c2df-13"
Accept-Ranges: bytes

<h1>pc server</h1>
Connection closed by foreign host.

三次以后会自动断开连接  keepalive_requests 3; 这个参数的作用

3.11:作为下载服务器配置:

[root@k8s-vip conf.d]# mkdir /data/nginx/download
#download不需要index.html文件
location /download {
       root /data/nginx;
       autoindex on; #自动索引功能
       autoindex_exact_size on; #计算文件确切大小(单位bytes),off只显示大概大小(单位kb,mb,gb)
       autoindex_localtime on; #显示本机时间而非GMT(格林威治)时间
   }
重启nginx并访问测试下载页面

在这里插入图片描述

limit_rate rate; #限制响应给客户端的传输速率,单位bytes/second,默认值0表示无限制
location /download {
       root /data/nginx;
       autoindex on; #自动索引功能
       autoindex_exact_size on; #计算文件确切大小(单位bytes),off只显示大概大小(单位kb,mb,gb)
       limit_rate 100k;
       autoindex_localtime on; #显示本机时间而非GMT(格林威治)时间
   }
#限速和不限速的对比

在这里插入图片描述

在这里插入图片描述

3.12: 作为上传服务器

client_max_body_size 1m; #设置永许客户端上传单个文件的最大值,默认值为1m
client_body_buffer_size size; #用于接受每个客户端请求报文的baody部分的缓冲区大小;默认为16k;超过此大小时,其将被暂存到磁盘上的由下面client_body_temp_path 指令所定义的位置
client_body_temp_path path [level1 [level2 [level3 ]]];
#设定存储客户端请求报文的body部分的临时存储路径及子目录结构和数量,目录名为16进制的数字,使用bash之后的值从后往前截取1位、2位、2位作为文件名

配置实例
client_max_body_size 10m;
client_body_buffer_size 16k;
client_body_temp_path /opt/nginx/temp 1 2 2; #reload nginx会自动创建

3.13:其他配置

keepalive_disable none | browser ...;
# 对哪种浏览器禁用长连接
limit_except method ... { ... },仅用于location
限制客户端使用除了指定的请求方法之外的方法
     method: GET, HEAD, POST, PUT, DELETE, MKCOL, COPY, OPTIONS, PROPFIND, PROPPATCH, LOCK, UNLOCK, PATCH
       limit_except GET { #只能使用GET方法
          allow 172.16.0.0/16;
          deny all;
         }

aio on | off #是否启用asynchronous file I/O(AIO)功能,需要编译开启
linux 2.6以上内核提供以下几个系统调用来支持aio:
1. SYS_io_setup: 建立aio的context
2. SYS_io_submit: 提交I/O操作请求
3. SYS_io_getevents: 获取已完成的I/O事件
4. SYS_io_cancel: 取消I/0操作请求
5. SYS_io_desroy: 销毁aio的centext
directio size | off; #directio是直接磁盘IO,默认为关闭,directio的设计初衷,它具备sendfile的基本原理,只是不使用内核cache,而是直接使用DMA,当某个文件大于等于给定大小时会生效,小于此值会使用sendfile,例如directio 4m,直接I最大的优点就是减少操作系统缓冲区和用户地址空间的拷贝次数,降低了CPU的开销和内存带宽,主要使用在磁盘上有较大文件的场合,比如视频、音频等。

1. DMA请求:
   CPU对DMA控制器初始化,并向I/O接口提出DMA请求。
2. DMA响应:
   DMA控制器通知I/O接口开始DMA传输
3. DMA传输:
   DMA控制器获得总线控制权后,CPU不再进行数据拷贝,由DMA控制器输出读写命令,直接控制内存与I/O接口进行数据传输.
4. DMA结束:
   完成数据传输后,DMA控制器即释放总线控制权,并向I/O接口发出结束信号并通知cpu,cpu继续处理请求。
总结:
	DMA传输不需要cpu直接参与数据传输过程,也没有将cpu阻塞在数据拷贝的过程中,而是通过硬件内存与I/O设备建立一条直接传送数据的通路,在数据传输过程中cpu基础处理其他请求,使cpu的工作效率大为提高

在这里插入图片描述

directio_alignment 512; 指令来设置块大小 #设置directio的对齐方式,在大多数情况下,一个512字节的对齐就足够了,但是,在linux下使用XFS时,需要将其增加到4k
# direction可以和sendfile结合使用不冲突,在linux上同时启用AIO和sendfile时,AIO用于大于或等于directio指令中指定的大小的文件,而sendfile用于较小的文件或禁用direction的文件,direction需要nginx开启aio,如: 
   location /video {
     root /data;
     index index.html;
     sendfile on;
     aio on;
     directio  8m; #小于8m用sendfile传输
     directio_alignment 512;
   }


cat /proc/1430/status  查看某个进程中的线程
https://nginx.org/en/docs/ngx_core_module.html#thread_pool #开启多线程,定义多线程读取和发送文件不会阻塞
https://nginx.org/en/docs/http/ngx_http_core_module.html#aio #aio
Syntax:	aio on | off | threads[=pool];
Default:	
aio off;
Context:	http, server, location
This directive appeared in version 0.8.11.



#重新编译nginx,开启线程池功能,和aio
./configure --prefix=/apps/nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-file-aio --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/usr/local/src/nginx-module-vts --with-threads

#nginx.conf配置线程池:
events {
    worker_connections  1024;
    use epoll;
    accept_mutex on;
    multi_accept on;
}
thread_pool pool1 threads=16;
thread_pool pool2 threads=32;

#server调用线程池:
   location /video {
     root /data;
     index index.html;
     sendfile on;
     aio  threads=pool1;

     directio  8m;
     directio_alignment 4096;
   }
   
#重启nginx并验证
[root@k8s-vip conf.d]# cat /proc/5470/status 
Name:   nginx
Umask:  0000
State:  S (sleeping)
Tgid:   5470
Ngid:   0
Pid:    5470
PPid:   5443
TracerPid:      0
Uid:    99      99      99      99
Gid:    99      99      99      99
FDSize: 64
Groups: 99 
VmPeak:   440684 kB
VmSize:   440684 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:      2552 kB
VmRSS:      2552 kB
RssAnon:            1892 kB
RssFile:             656 kB
RssShmem:              4 kB
VmData:   395152 kB
VmStk:       132 kB
VmExe:      1068 kB
VmLib:      6952 kB
VmPTE:       288 kB
VmSwap:        0 kB
Threads:        49
SigQ:   0/7827
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000040001000
SigCgt: 0000000198016a07
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000001fffffffff
CapAmb: 0000000000000000
NoNewPrivs:     0
Seccomp:        0
open_file_cache off;#是否缓存打开过的文件信息
open_file_cache max=N [inactive=time];
     nginx可以缓存一下三种信息:
     (1) 文件元数据:文件的描述符、文件大小和最近一次的修改时间
     (2) 打开的目录结构
     (3) 没有找到的或者没有权限访问的文件的相关信息
     max=N: 可缓存的缓存项上限数量;达到上限后会使用LRU(Least recently used,最近最少使用)算法实现管理
     incative=time: 缓存项的非活动时长,在此处指定的时长内未被命中的次数少于open_file_cache_min_uses指令所指定的次数的缓存项极为非活动项,将被删除
open_file_cache_errors on | off;
	是否缓存查找时发生错误的文件一类的信息
	默认值为off
open_file_cache_min_uses number;
	open_file_cache指定的inactive参数指定的时长内,至少被命中此处指定的次数方可被归内为活动项
open_file_cache_valid time;
	缓存项有效性的检查验证频率,默认值为60s
open_file_cache          max=1000 inactive=60s;#最大缓存1000个文件,非活动数据超时时长60s
open_file_cache_valid    60s;#每间隔60s检查一下缓存数据有效性
open_file_cache_min_uses 5;#60秒内至少被命中访问5次才被标记为活动数据
open_file_cache_errors   on;	#缓存错误信息
Syntax:	server_tokens on | off ; #隐藏nginx版本

Context:	http, server, location

四 nginx高级配置

4.1:nginx状态页

基于nginx模块ngx_http_stub_status_module实现,在编译安装nginx的时候需要添加编译参数–with-http_stub_status_module,否则配置完成之后检测会提示语法错误

配置实例:
location = /nginx_status {
    allow 172.16.0.0/16;
    allow 127.0.0.1;
    deny all;
    stub_status;
}
状态页用于输出nginx的基本状态信息:
Active connections: 2 
server accepts handled requests
 20 20 38 
上面三个数字分别对应accepts,handled,requests三个值
Reading: 0 Writing: 1 Waiting: 1 

Active connections: 当前处于活动状态的客户端连接数,包括连接等待空闲连接数。
accepts:统计总值,Nginx自启动后已经接受的客户端请求的总数。
handled:统计总值,Nginx自启动后已经处理完成的客端请求的总数,通常等于accepts,除非有worker_connections限制等被拒绝的连接。
requests:统计总值,Nginx自启动后客户端发来的总的请求数。
Reading:当前状态,正在读取客户端请求报文首部的连接的连接数。
writing:当前状态,正在向客户端发送响应报文过程中的连接数。
Waiting;当前状态,正在等待客户端发出请求的空闲连接数,开启 keep-alive的情况下,这个值等于 active - (readingtwriting),

4.2: nginx第三方模块

第三方模块是对nginx功能的扩展,第三方模块需要在编译安装Nginx的时候使用参数--add-module=PATH指定路径添加,有的模块是由公司的开发人员针对业务需求定制开发的,有的模块是开源爱好者开发好之后上传到github进行开源的模块,nginx支持第三方模块需要从源码重新编译支持,比如开源的echo模块;https://github.com/openresty/echo-nginx-module

git clone https://github.com/openresty/echo-nginx-module
./configure --prefix=/apps/nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-file-aio --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/usr/local/src/nginx-module-vts --with-threads --add-module=/usr/local/src/echo-nginx-module

   location / {
       default_type  text/plain;
       echo $scheme;
       root /data/nginx/html/pc;
   }

4.3: nginx变量的使用:

nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用,变量可以分为内置变量和自定义变量,内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值

4.3.1:内置变量
$remote_addr;
#存放了客户端的地址,注意是客户端的公网IP,也就是一家人访问一个网站,则会显示为路由器的公网ip
$args;
#变量中存放了URL中的指令,例如http://pc.gf.com/index.html?name=gf&age=gf
name=gf&age=gf
$document_root
#保存了针对当前资源的请求的系统根目录,如/data/nginx/html/pc
$document_uri
#保存了当前请求中不包含指令的URI,注意是不包含请求的指令,比如http://pc.gf.com/index.html?age=12&name=gf
/index.html
$host;
#存放了请求的host名称
$http_user_agent;
$客户端浏览器的详细信息
$http_cookie;
#客户端的cookie信息
set $limit_rate 100k;
echo $limit_rate;
#如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有,则为0
$remote_port;
#客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口
echo $remote_user; #已经经过Auth Basic Module验证的用户名
auth_basic "login passwd";
auth_basic_user_file /apps/nginx/conf/.htpasswd;
$request_body_file;
#做反向代理时发给后端服务器的本地资源的名称
$request_method;
#请求资源的方式,GET/PUT/DELETE等
$request_filename;
#当前请求的资源文件的路径名称,由root或alias指令与URI请求生成的文件绝对路径,如/data/nginx/html/pc/index.html
$scheme;
#请求的协议,如ftp,https,http等
$server_protocol;
#保存了客户端请求资源使用的协议的版本,如HTTP/1.0等
$server_addr;
#保存了服务的IP地址
$server_name;
#保存了服务器的主机名
$server_port;
#请求的服务器的端口号
4.3.2 自定义变量:

假如需要自定义变量名称和值,使用指令set $variable value;

Syntax:	set $variable value;
Default:	—
Context:	server, location, if


set $name gf;
echo $name;
set $my_port $server_port;

4.4:自定义访问日志

访问日志是记录客户端即用户的具体请求内容信息,全局配置模块中的error_log是记录nginx服务器运行时的日志的level,因此有着本质的区别,而且nginx的错误日志一般只有一个,但是访问日志可以在不同server中定义多个,定义一个日志需要使用access_log指定日志的保存路径,使用log_format指定日志的格式,格式中定义要保存的具体日志内容

4.4.1 自定义默认格式日志:

如果是要保留日志的原格式,只是添加相应的日志内容

 
    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;
4.4.2 自定义json格式日志

nginx的默认访问日志记录内容相对比较单一,默认的格式也不方便后期做日志统计分析,生产环境中通常将nginx日志转换为json日志,然后配合使用elk做日志收集-统计-分析

    log_format access_json
      '{"@timestamp":"$time_iso8601",'
        '"host":"$server_addr",'          #访问主机ip
        '"clientip":"$remote_addr",'      #公网ip
        '"size":"$body_bytes_sent",'
        '"responsetime":"$request_time",'
        '"upstreamhost":"$upstream_addr",'
        '"http_host":"$host",'
        '"uri":"$uri",'
        '"domain":"$host",'
        '"xff":"$http_x_forwarded_for",' #真正访问的ip
        '"referer":"$http_referer",'
        '"tcp_xff":"$proxy_protocol_addr",'
        '"http_user_agent":"$http_user_agent",'
        '"status":"$status"}';

4.4.3 Json格式的日志访问统计:
import json
status_200 = []
status_404 = []
with open('pc.gf.com-access.log') as f:
    for lines in f.readlines():

        line = json.loads(lines)

        if line.get("status") == "200":
            status_200.append(line.get("status"))
        elif line.get("status") == "404":
            status_404.append(line.get("status"))
        else:
            print("状态码 ERROR")
print(status_404,status_200)

4.5 nginx的压缩功能

Nginx支持对指定类型的文件进行压缩然后在传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,这样有助于降低出口带宽的利用率,降低企业的IT支出,不过会占用相应的CPU资源

Nginx对文件的压缩功能是依赖于模块ngx_http_gzip_module,官方文档:https://nginx.org/en/docs/http/ngx_http_gzip_module.html 配置指令如下:

#启用或禁用gzip压缩,默认关闭
gzip on | off;

#压缩比由低到高从1到9,默认为1
gzip_comp_level level;

#禁用IE6 gzip功能
gzip_disable "MSIE [1-6]\."

#gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;

#启用压缩功能时,协议的最小版本,默认HTTP/1.1
gzip_http_version 1.0 | 1.1;

#指定Nginx服务需要向服务器申请的缓存空间的个数*大小,默认32 4k|16 8k;
gzip_buffers number size;

#指明仅对那些类型的资源执行压缩操作;默认为gzip_types text/html,不用显示指定,否则出错
gzip_types mime-type ;

#如果启用压缩,是否在响应报文首部插入"Vary: Accept-Encoding"
gzip_vary on |off;


    gzip  on;
    gzip_comp_level 5;
    gzip_min_length 1k;
    gzip_types text/plain application/javascript application/x-javascript text/cssappliction/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
    gzip_vary on;


[root@k8s-vip conf]# curl --head --compressed pc.gf.com/1.log 
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 09 Jan 2024 03:59:53 GMT
Content-Type: text/plain
Last-Modified: Tue, 09 Jan 2024 03:57:23 GMT
Connection: keep-alive
Keep-Alive: timeout=65
Vary: Accept-Encoding
ETag: W/"659cc423-1fc1"
Content-Encoding: gzip

4.6 https功能

web网站的登录首页都是使用https加密传输的,加密数据以保障数据的安全,https能够加密信息,以免敏感信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用https协议,HTTPS其实是有两部分组成:HTTP+SSL/TLS,也就是在HTTP上又加上了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据。

在这里插入图片描述

https 实现过程如下:
1. 客户端发起HTTPS请求:
客户端访问某个web端的https地址,一般都是443端口

2.服务端的配置:
采用https协议的服务器必须要有一套证书,可以通过一些组织申请,也可以自己制作,目前国内很多网站都是自己做的,当你访问一个网站的时候提示证书不可信任就表示证书是自己做的,证书就是一个公钥和私钥,就像一吧锁和钥匙,正常情况下只有你的钥匙可以打开你的锁,你可以把这个送给别人让他锁住一个箱子,里面放满了钱,别人不知道里面放了什么而且也打不开,只有你的钥匙才可以打开

3.传送证书
服务端给客户端传递证书,其实包含了很多信息,例如证书得到颁发机构,过期时间等。

4.客户端解析证书:
这部分工作是由客户端完成的,首先会验证公钥的有效性,比如颁发机构、过期时间等等。如果发现异常则会弹出一个警告框提示证书可能存在的问题,如果这个证书没有问题就生成一个随机值,然后用证书对随机值进行加密,就像前2步骤所说把随机值锁起来,不让别人看到。

5.传送4步骤的加密数据:
就是将用证书加密后的随机值传递给服务器,目的就是为了让服务器得到这个随机值,以后客户端和服务器的通信就可以通过这个随机值进行加密解密了。

6.服务端解密信息。
服务端用私钥解密5步骤加密后的随机值之后,得到了客户端传过来的随机值(私钥),然后把内容通过改制进行对称加密,对称加密就是将信息和私钥通过算法混合在一起,这样除非你知道私钥,不然是无法获取内部的内容,而正好客户端和服务端都知道这个私钥,所以只要机密算法够复杂就可以保证数据的安全性。

7. 传输加密后的信息
服务端将用私钥加密后的数据传递给客户端,在客户端可以被还原出原数据的内容

8. 客户端解密信息
客户端用之前生成的私钥获取解密服务端传递过来的数据,由于数据一直是加密的,因此即使第三方获取到数据也无法知道其详细内容。
4.6.1: ssl配置参数

Nginx的HTTPS功能基于模块ngx_http_ssl_module实现,因此如果是编译安装的nginx要使用参数ngx_http_ssl_module开启ssl功能,但是作为nginx的核心功能,yum安装的nginx默认就是开启的,编译安装的nginx需要指定编译参数–with-http_ssl_module开启,官方文档:https://nginx.org/en/docs/http/ngx_http_ssl_module.html,配置参数如下

ssl on | off;
#为指定的虚拟主机配置是否启用ssl功能,此功能在1.15.0废弃,使用listen [ssl]替代

ssl_certificate /path/to/file;
#当前虚拟主机使用的公钥文件,一般是crt文件

ssl_certificate_key /path/to/file;
#当前虚拟主机使用的私钥文件,一般是key文件

ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3];
# 支持ssl协议版本,早期为ssl,现在是TSL,默认为后三个

ssl_session_cache off | none | [builtin[:size]] [shared:name:size];
#配置ssl缓存
     off: 关闭缓存
     none: 通知客户端支持ssl session cache,但实际不支持
     builtin[:size]: 使用OpenSSL内建缓存,为每worker进程私有
     [shared:name:size]: 在各worker之间使用一个共享的缓存,需要定义一个缓存名称和缓存空间大小,一兆可以存储4000各会话信息,多个虚拟主机可以使用相同的缓存名称
     
ssl_session_timeout time; #客户端连接可以服务ssl session cache中缓存的有效时长,默认5m
4.6.2 自签发证书

[root@k8s-vip certs]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt #自签名CA证书
Generating a 4096 bit RSA private key
.....................................................................++
...............................................................................................................................................................................................................................................++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:ShanXi
Locality Name (eg, city) [Default City]:BaoJi     
Organization Name (eg, company) [Default Company Ltd]:gf.ltd
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:gf.com#通用名称
Email Address []:
[root@k8s-vip certs]# 
[root@k8s-vip certs]# ll
总用量 8
-rw-r--r-- 1 root root 1984 1月   9 12:49 ca.crt
-rw-r--r-- 1 root root 3272 1月   9 12:49 ca.key

#自治key和csr文件
[root@k8s-vip certs]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout pc.gf.com.key -out pc.gf.com.csr  
#签发证书
openssl x509 -req -days 3650 -in pc.gf.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out pc.gf.com.crt
#
openssl x509 -in pc.gf.com.crt -noout -text
4.6.3 nginx配置
   server_name pc.gf.com;
   listen 443 ssl;
   ssl_certificate /apps/nginx/certs/pc.gf.com.crt;
   ssl_certificate_key /apps/nginx/certs/pc.gf.com.key;
   ssl_session_timeout 10m;
   ssl_session_cache shared:sslcache:20m;
4.6.4:实现多域名证书

nginx支持基于单个IP实现多域名的功能,并且还支持单IP多域名的基础之上实现https,其实是基于nginx的SNI(Server Name Indication)功能实现,SNI是为了解决一个nginx服务器内使用一个IP绑定多个域名和证书的可能,其具体功能在连接到服务器建立SSL链接之前先发送要访问站点的域名,这样服务器在根据这个域名返回给客户端一个合适的证书

openssl req -newkey rsa:4096 -nodes -sha256 -keyout mobile.gf.com.key -out mobile.gf.com.csr

openssl x509 -req -days 3650 -in mobile.gf.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out mobile.gf.com.crt

   listen 443 ssl;
   server_name mobile.gf.com;
   ssl_certificate /apps/nginx/certs/mobile.gf.com.crt;
   ssl_certificate_key /apps/nginx/certs/mobile.gf.com.key;
   ssl_session_timeout 10m;
   ssl_session_cache shared:sslcache:20m;

4.7 关于favicon

   #location ~ ^/favicon\.ico$
   location = /favicon.ico {
       root /data/nginx/images;
       expires 90d;
    }

4.8安全选项

4.8.1 更改nginx源码信息并重新编译Nginx
cd /usr/local/src/nginx-1.20.2/src/http/ngx_http_header_filter_module.c

static u_char ngx_http_server_string[] = "Server: nginx" CRLF;
#定义响应报文中server字段信息
4.8.2 :升级OpenSSL版本:

心脏出血,也简称为心血漏洞,是一个出现在加密程序库OpenSSL的安全漏洞,该程序库广泛用于实现互联网的传输层安全(TLS)协议。它于2012年被引入了软件中,2014年4月首次向公众披露。只要使用的是存在缺陷的OpenSSL实例,无论是服务器还是客户端,都可能因此而受到攻击,此问题的原因在实现TLS的心跳扩展时没有对输入进行适当验证,因此漏洞的名称来源于“心跳”,该程序错误属于缓冲区过读,既可以读取的数据比应该永许读取的还多

准备OpenSSL源码包
wget https://www.openssl.org/source/old/1.1.1/openssl-1.1.1d.tar.gz --no-check-certificate

编译安装Nginx并指定新版本的OpenSSL路径
 ./configure --prefix=/apps/nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-file-aio --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/usr/local/src/nginx-module-vts --with-threads --add-module=/usr/local/src/echo-nginx-module --add-module=/usr/local/src/openssl-1.1.1d
 make && make install
 验证比启动
 [root@k8s-vip ~]# /apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful

  /apps/nginx/sbin/nginx 

五 nginx Rewrite相关功能:

nginx服务器利用ngx_http_rewrite_module 模块解析和处理rewrite请求,此功能依靠PCRE(Perl Compatible Regular Expressions),因此编译之前要安装PCRE库,rewrite时nginx服务器的重要功能之一,用于实现url重写,URL的重写时非常有用的功能,比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问,另外还可以在一定程度上提高网站的安全性。
http://www.pcre.org #pcre官方网站

5.1: ngx_http_rewrite_module 模块指令

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

5.1.1:if指令

用于条件匹配判断,并根据条件判断结果选择不同的nginx配置,可以配置在server或location块中进行配置,nginx的if语法仅能使用if做单词判断,不支持使用if else或if elif这样的多重判断,用法如下

if (条件匹配) {
    action
}

使用正则表达式对变量进行匹配,匹配成功时if指令认为条件为true,否则为false,变量与表达式之间使用以下符号链接

=: #比较变量和字符串是否相等,相等时if指定认为true,反之为false
!=: #比较变量和字符串是否不相等,不相等时if指定认为true,反之为false
~: #表示在匹配过程中区分大小写字符,(可以通过正则比表达式匹配),满足匹配条件为真,不满足为假
!~: #为区分大小写字符且匹配结果不匹配,不满足为真,满足为假
~*: #表示在匹配过程中不区分大小写字符,(可以通过正则表达式匹配),满足匹配条件为真,不满足为假
!~*: #为不区分大小字符且匹配结果不匹配,满足为假,不满足为真。

-f 和 ! -f:判断请求的文件是否存在和是否不存在
-d 和 ! -d:判断请求的目录是否存在和是否不存在
-x 和 ! -x:判断文件是否可执行和不可执行
-e 和 ! -e:判断请求的文件或目录是否存在和是否不存在(包括文件、目录、软链接)
   if ($request_method = GET){
        echo $request_method;
   }
   if (!-f $request_filename) {
        echo "file not exist";
    }

注:如果 变量的值为空字符串或是以 0 开头的任意字符串,则 i f 指令认为该条件为 f a l s e ,其他条件为 t r u e ,而且 n g i n x 1.0.1 版本之前的 变量的值为空字符串或是以0开头的任意字符串,则if指令认为该条件为false,其他条件为true,而且nginx 1.0.1版本之前的 变量的值为空字符串或是以0开头的任意字符串,则if指令认为该条件为false,其他条件为true,而且nginx1.0.1版本之前的变量的值为0还会使false

5.1.2: set指令:

指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key,另外set定义格式为set $key v a l u e ,及无论是 k e y 还是 v a l u e 都要加 value,及无论是key还是value都要加 value,及无论是key还是value都要加符号

   location / {
       default_type  text/plain;
		set $my_port $server_port;
       root /data/nginx/html/pc;
   }
  
5.1.3: break指令:

用于中断当前相同作用域(Location)中的其他nginx配置,与该指令处于同一作用域的nginx配置中,位于它前面的配置生效,位于后面的指令配置就不生效了,nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,该指令可以在server块和locaiton块以及if块中使用,使用语法如下:

   location / {
       default_type  text/plain;
       root /data/nginx/html/pc;
       set $name gf;
       echo $name;
       break;
       set $age 18;
       echo $age;
   }
5.1.4: return指令:

从nginx版本0.8.4开始支持,return用于完成对请求的处理,并直接向客户端返回响应状态码,如果其可以指定重定向URL(对于特殊重定向状态码,301或302等)或者是指定提示文本内容(对于特殊状态码403或500等),处于此指令后的所有配置都不被执行,return可以在server、if和location块进行配置,用法如下:

return code;#返回给客户端指定的HTTP状态码
return code (text);#返回给客户端的状态码及响应体内容,可以调用变量
return code URL; #返回给客户端的URL地址

   location / {
       default_type  text/plain;
       root /data/nginx/html/pc;
       return 500 1.11.1;
   }
   
   
   location / {
       default_type  text/plain;
       root /data/nginx/html/pc;
       return 404;
   }


   location / {
       default_type  text/plain;
       root /data/nginx/html/pc;
       return 302 http://www.baidu.com;
   }

5.1.5: rewrite_log 指令

设置是否开启记录ngx_http_rewrite_module模块日志记录到error_log日志文件当中,可以配置在http、server、location或if当中,需要日志级别为notice

   location / {
       default_type  text/plain;
       root /data/nginx/html/pc;
       rewrite_log on;
   }

5.2:rewrite指令

通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配,rewrite主要是针对用户请求的URL或者是URI做具体处理,以下是URL和URI的具体介绍

URI:通用资源定位符,标识一个资源的路径,可以不带协议
URL:统一资源定位符,只用于Internet中描述资源的字符串,是URI的子集,主要包括传输协议(scheme)、主机(IP、端口号或者域名)和资源具体地址(目录和文件名)等三部分,一般格式为 scheme://主机名[:端口号][/资源路径],如:
http://www.a.com:8080/path/file/index.html就是一个URL路径,URL必须带访问协议
每个URL都是一个URI,但是URI不都是URL
例如:
http://example.org:8080/path/to/resource.txt #URI/URL
ftp://example.org/resource.txt #URI/URL
/absolute/path/to/resource.txt #URI

rewrite的官方地址https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite,rewrite可以配置在server、location、if,其具体使用方式

rewrite regex replacement [flag];
rewrite 正则匹配客户端的请求 修改后的请求 标记为;

rewrite将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为表达式指定的新的URI

注意:如果在同一级配置块中存在多个rewrite规则,那么会自下而上逐个检查,隐含有循环机制,但不超过10次;如果超过,会提示500响应码,[flag]所表示的标志位用于控制循环机制,如果替换后的URL是以http://或https://开头,则替换结果会直接以重定向返回给客户端,及永久重定向301

5.2.1:rewrite flag使用介绍:

利用nginx的rewrite的指令,可以实现url的重新跳转,rewrite有四种不同的flag,分别是redirect(临时重定向,状态码302)、permanent(永久重定向,状态码301)、break和last。其中前两种是跳转型的flag,后两种是代理型,跳转型是指有客户端浏览器重新对新地址进行请求,代理型是在web服务器内部实现跳转的

Syntax:	rewrite regex replacement [flag];
Default:	—
Context:	server, location, if
rewrite:
#临时重定向,重写完成以后以临时重定向方式直接返回重写后生成的新url给客户端,由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302

permanent;
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求,状态码:301

last;
#重写完成后停止对当前URI在当前laction中后续的其他重写操作,而后对新的URL启动新一轮重写检查,不建议在多location配置环境中使用

break;
#重写完成后停止对当前url在当前location中后续的其他重写操作,而后直接将匹配结果反还给客户端及结束循环并返回数据给客户端,建议在多location配置环境中使用
5.2.2:rewrite案例-域名永久与临时重定向:

要求:因业务需要,将访问源域名pc.gf.com的请求永久重定向到www.baidu.com

临时重定向不会缓存域名解析记录(A记录),但是永久重定向会缓存。

    location / {
       default_type  text/plain;
       root /data/nginx/html/pc;
       #rewrite /  http://www.baidu.com permanent;
       rewrite /  http://www.baidu.com redirect;

   }
5.2.3: rewrite案例–break与last:

测试:访问break的请求被rewrite到test,而访问test1传递请求再次被rewrite到test2,以此测试last和break分别有什么区别:

5.2.3.1 break案例
   location /break {
      root /data/nginx;
      default_type  text/plain;
      index index.html;
      rewrite ^/break/(.*) /test1/$1 break; #会停止向下走
      rewrite ^/test1/(.*) /test2/$1 break;
   }


   location = /test1 {
     default_type  text/plain;
     return 999 test1;
     #root /data/nginx;
   }

   location = /test2 {
     default_type  text/plain;
     return 999 test2;
     #root /data/nginx;
   }
#最终的结果不会继续匹配当前location中后续的write规则,也不会跳出当前的location继续匹配其他location,而是直接放回数据给客户端。

break适用于不改变客户端访问方式,但是要将访问的目的URL做单次重写的场景,比如有个网站前端访问路径发生变化,旧版本的网站数据已经保存到了statics不能丢失,但是要将访问新版本的资源重写到新的静态资源路径到新的目录static:


   location /statics {#旧版本程序中的请求路径需要重写请求路径后在响应给客户端,不需要在跳转至其他location
     default_type  text/plain;
     root /data/nginx;
     rewrite ^/statics/(.*) /static/pool1/$1 break;
   }

   location /static/pool1 {#新版本程序的请求路径直接响应请求
     default_type  text/plain;

     root /data/nginx;
   }

5.2.3.2:last案例
last:对某个location的URL匹配成功后会停止当前location的后续rewrite规则,并结束当前location,然后将匹配生成的新URL跳转至其他location继续匹配,直到没有location可匹配后将最后一个location的数据返回给客户端

   location /last {
      root /data/nginx;
      default_type  text/plain;
      index index.html;
      rewrite ^/last/(.*) /test1/$1 last;
      rewrite ^/test1/(.*) /test2/$1 last; #如果第一条rewrite规则匹配成功则不执行本条,否则执行本条rewrite规则
   }

   location  =  /test1/index.html {
     default_type  text/plain;
     #return 999 test1;
     root /data/nginx;
   }

   location = /test2/index.html {
     default_type  text/plain;
     #return 999 test2;
     root /data/nginx;
   }

break:
     1. 结束当前location后续的write操作
     2. break结束后会直接返回数据,不会跳出当前location在对url进行和其他location的匹配

last:
  	1. 结束当前location后续的write操作
	2. 当前locaiton的write结束后会将生成新url跳出当前location进行与替他location的匹配
5.2.4:rewrite案例-自动跳转https:

要求基于通信安全考虑公司网站要求全站https,因此要求将在不影响用户的请求的情况下将http请求自动跳转至https,另外也可以实现部分location跳转

   location / {
       default_type  text/plain;
       root /data/nginx/html/pc;

       if ($scheme = http){ #为加条件判断,会导致死循环
         rewrite / https://pc.gf.com permanent;
       }
   }
5.2.5:rewrite案例-判断文件是否存在

**要求:当用户访问到公司网站的时输入了一个错误的URL,可以将用户重定向至官网首页

   location / {
       default_type  text/plain;
       root /data/nginx/html/pc;

       if ($scheme = http){
         rewrite / https://pc.gf.com permanent;
       }
       if (!-f $request_filename){
        rewrite (.*) https://pc.gf.com/index.html;
   }
   }

5.3:nginx防盗链

防盗链基于客户端携带的referer(https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referer)实现,referer是记录打开一个页面之前记录是从那个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer就是之前那个网站域名,正常的referer信息有一下几种:

none:请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信息
blocked:请求报文有referer首部,但无有效值,比如为空
server_names: referer首部中包含本主机名及nginx 监听的server_name
arbitrary_string: 自定义指定字符串,但可使用*作通配符
regular expression:被指定的正则表达式模式匹配到的字符串,要使用~开头,例如:~.*\.magedu\.com。
https://www.digitalocean.com/community/tools/nginx #nginx在线配置生成器

正常通过搜索引擎搜索web网站并访问网站的referer信息如下:

{"@timestamp":"2024-01-09T19:50:07+08:00","host":"172.16.10.105","clientip":"172.16.10.1","size":"138","responsetime":"0.000","upstreamhost":"-","http_host":"pc.gf.com","uri":"/","domain":"pc.gf.com","xff":"-","referer":"-","tcp_xff":"-","http_user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","status":"302"}
5.3.1:实现防盗链

基于访问安全考虑,nginx支持通过nginx_http_referer_module模块https://nginx.org/en/docs/http/ngx_http_referer_module.html检查访问请求的referer信息是否有效实现防盗链功能,定义方式如下

dl.gf.com
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>盗链网页</title>
</head>
<body>
<a href="http://dl.gf.com">测试盗链</a>
<img src="http://pc.gf.com/1.jpg">
</body>
</html>



服务器配置
    location ~* \.(gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js)$ {
       root /data/images;
       index index.html;
       valid_referers none blocked server_names
          ~\.baidu\.  ~\.google\.;
       if ($invalid_referer) {
            return 403;
          }
       }
    location ~* \.(gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js)$ {
       root /data/images;
       index index.html;
       valid_referers none blocked server_names
          ~\.baidu\.  ~\.google\.; #定义有效的referer
       if ($invalid_referer) {#假如时使用其他无效的referer访问
            return 403; #返回状态码
          }
       }

在这里插入图片描述

六:nginx反向代理功能

反向代理:反向代理也叫reverse proxy,指的是代理外网用户的请求到内部的指定web服务器,并将数据返回给用户的一种方式,这是用的比较多的一种方式。

nginx除了可以在企业提供高性能的web服务之外,另外还可以将本身不具备的请求通过某种预定义的协议转发至其它服务器处理,不同的协议就是nginx服务器与其他服务器进行通信的一种规范,主要在不同场景使用以下模块实现不同的功能:

ngx_http_proxy_module: 将客户端的请求以http协议转发至指定服务器进行处理。
ngx_stream_proxy_module:将客户端的请求以tcp协议转发至指定服务器处理。
ngx_http_fastcgi_module:将客户端对php的请求以fastcgi协议转发至指定服务器处理
ngx_http_uwsgi_module:将客户端对python的请求以uwsgi协议转发至指定服务器处理。

在这里插入图片描述

在这里插入图片描述

6.1:实现http反向代理

要求:将用户域pc.gf.com的请求转发到后端服务器处理,官方文档: https://nginx.org/en/docs/http/ngx_http_proxy_module.html

环境准备:

172.16.10.201 #nginx 代理服务器
172.16.10.7.50 #web A
172.16.10.7.61 #web b
6.1.1:nginx http反向代理入门

官方文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

proxy_pass 
#用来设置将客户端请求转发给后端服务器的主机,可以是主机名、ip地址;端口的方式,也可以代理到预先设置的主机群组,需要模块 ngx_http_upstream_module支持。
location /web {
       index index.html;
       proxy_pass http://pc.gf.com;
       #不带斜线将访问的/web,等于访问后端服务器 http://pc.gf.com/web/index.html,及后端服务器配置的站点根目录要有web目录才可以访问,这是一个追加/web到后端服务器 http://servername:port/web/index.html的操作
       
       proxy_pass http://pc.gf.com/;
       #带斜线,等于访问后端服务器的http://pc.gf.com/index.html内容返回给客户端
       }
       
       #重启nginx访问测试效果
proxy_hide_header field;
# 用户nginx作为反向代理时,在返回给客户端http响应的时候,隐藏后端服务版本相应头部信息,可以设置在http/server或location块
location /web {
     index index.html;
     proxy_pass http://pc.gf.com;
     proxy_hide_header ETag;
}
proxy_pass_header field;
#默认nginx在响应报文中不传递后端服务器的首部字段Date、Server、X-Pad、X-Accel等参数,如果要传递的话则要使用proxy_pass_header field声明将后端服务器返回的值传递给客户端
   location /web {
       index index.html;
       proxy_pass http://dl.gf.com;
       proxy_pass_header Date;
       proxy_hide_header ETag;
   }

proxy_pass_request_body on | off;
#是否向后端服务器发送HTTP包体部分,可以设置在http/server或location块,默认即为开启
proxy_pass_request_headers on | off;
#是否将客户端的请求头部转发给后端服务器,可以设置在http/server或location块,默认即为开启
proxy_set_header;
#可以添加或更改客户端的请求头部信息内容并转发给后端服务器,比如在后端服务器想要过去客户端的真实IP的时候,就要更改每一个报文的头部,如下:
nginx获取真实ip   "$http_x_forwarded_for"
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 添加HOST到报文头部,如果客户端为NAT上网那么其值为客户端的公用的公网IP地址,常用于在日志中记录客户端的真实IP地址

配置
   location /web {
       index index.html;
       #proxy_pass http://dl.gf.com;
       proxy_pass http://172.16.10.50;
       proxy_pass_header Date;
       proxy_hide_header ETag;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }
   
   apache
   
    LogFormat "\"%{X-Forwarded-For}i\"  %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
proxy_connect_timeout time;
#配置nginx服务器与后端服务器尝试建立连接的超时时间,默认为60秒,用法如下
proxy_connect_timeout 60;
#60s为自定义nginx与后端服务器建立连接的超时时间
proxy_read_time time;
#配置nginx服务器向后端服务器或服务器组发起read请求后,等待的超时时间,默认为60s
proxy_send_time time;
#配置nginx向后端服务器或服务器组发起write请求后,等待的超时时间,默认为60s
proxy_http_version 1.0;
#用于设置nginx提供代理服务的HTTP协议的版本,默认HTTP 1.0
proxy_ignore_client_abort off;
#当客户端网络中断请求时,nginx服务器中断其对后端服务器的请求。即如果此项设置为on开启,则服务器会忽略客户端中断并一直等着代理服务执行返回,如果设置为off,则客户端中断后nginx也会中断客户端请求并立即记录499日志,默认为off
proxy_headers_hash_bucket_size 128;
#当配置了 proxy_hide_header或proxy_set_header的时候,用于设置nginx保存HTTP报文头的hash表的上限。
proxy_headers_hash_max_size 512;
#设置proxy_headers_hash_bucket_size的最大可用空间


server_names_hash_bucket_size 512;
#server_name hash表申请空间大小
server_names_hash_max_size 512;
#设置服务器名称hash表的上限大小

6.1.1.1 反向代理实例

   location /web {
       index index.html;
       #proxy_pass http://dl.gf.com;
       proxy_pass http://172.16.10.50;
       proxy_pass_header Date;
       proxy_hide_header ETag;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }

6.1.1.2:反向代理实例-缓存功能

缓存功能默认关闭状态

proxy_cache zone | off; 默认off
#指明调用的缓存,或关闭缓存机制; Context:http,server,location
proxy_cache_key string;
#缓存中用于“键”的内容,默认值: proxy_cache_key $scheme$proxy_host$request_uri;
proxy_cache_valid [code ...] time;
#定义对特定响应码的响应内容的缓存时长,定义在http{...}中
	示例:
	proxy_cache_valid 200 302 10m;
	proxy_cache_valid 404 1m;
proxy_cache_path;
	定义可用于proxy功能的缓存;Context:http

proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [min_free=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_path /var/cache/nginx/proxy_cache #定义缓存保存路径,proxy_cache会自动创建
	levels=1:2:2 #定义缓存目录结构层次,1:2:2可以生成2^4x2^8x2^8=1048576个目录
	keys_zone=proxycache:20m #指内存中缓存的大小,主要用于存放key和metadata(如:使用次数)
	inactive=120s; #缓存有效时间
	max_size=1g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值

#调用缓存功能,需要定义在相应的配置段,如server{...};或者location等
	proxy_cache proxycache;
	proxy_cache_key $request_uri;
	proxy_cache_valid 200 302 301 10m;#指定的状态码返回的数据缓存多长时间
	proxy_cache_valid any 1m;
	proxy_cache_use_stale error http_502 http_503;
	#在被代理的后端服务器出现那种情况下,可直接使用过期的缓存响应客户端
	proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | off ...;#默认为off
proxy_cache_methods GET | HEAD | POST ..;
#对那些客户端请求方法对应的响应进行缓存,GET和HEAD方法总是被缓存
缓存配置

proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2:2 keys_zone=proxycache:20m inactive=120s max_size=1g;


   location /web {
       index index.html;
       #proxy_pass http://dl.gf.com;
       proxy_pass http://172.16.10.50;
       proxy_pass_header Date;
       proxy_hide_header ETag;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_cache proxycache;
       proxy_cache_key $request_uri;
       proxy_cache_valid 200 302 301 10m;
       proxy_cache_valid any 1m;
   }
   
   
   配置前
   [root@localhost html]# ab -n 2000 -c200 http://pc.gf.com/web/index.html  2000个请求  200个并发
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking pc.gf.com (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests


Server Software:        nginx
Server Hostname:        pc.gf.com
Server Port:            80

Document Path:          /web/index.html
Document Length:        9 bytes

Concurrency Level:      200
Time taken for tests:   0.723 seconds
Complete requests:      2000
Failed requests:        0
Write errors:           0
Total transferred:      452000 bytes
HTML transferred:       18000 bytes
Requests per second:    2767.94 [#/sec] (mean)//
Time per request:       72.256 [ms] (mean)
Time per request:       0.361 [ms] (mean, across all concurrent requests)
Transfer rate:          610.89 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   16   8.3     16      38
Processing:     3   53  43.9     45     282
Waiting:        3   41  42.1     31     255
Total:         18   70  43.5     65     291

Percentage of the requests served within a certain time (ms)
  50%     65
  66%     72
  75%     77
  80%     79
  90%     83
  95%     97
  98%    288
  99%    290
 100%    291 (longest request)
 
 
 
 
 配置后
 [root@localhost html]# ab -n 2000 -c200 http://pc.gf.com/web/index.html
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking pc.gf.com (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests


Server Software:        nginx
Server Hostname:        pc.gf.com
Server Port:            80

Document Path:          /web/index.html
Document Length:        9 bytes

Concurrency Level:      200
Time taken for tests:   1.045 seconds
Complete requests:      2000
Failed requests:        0
Write errors:           0
Total transferred:      452000 bytes
HTML transferred:       18000 bytes
Requests per second:    1914.27 [#/sec] (mean)    /
Time per request:       104.478 [ms] (mean)
Time per request:       0.522 [ms] (mean, across all concurrent requests)
Transfer rate:          422.49 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   13   6.9     13      36
Processing:     8   53  84.3     37    1013
Waiting:        1   47  83.7     31    1013
Total:         18   67  83.3     51    1013

Percentage of the requests served within a certain time (ms)
  50%     51
  66%     54
  75%     60
  80%     61
  90%     74
  95%    248
  98%    265
  99%    267
 100%   1013 (longest request)
6.1.1.3:添加头部报文信息

nginx基于模块ngx_http_headers_module可以实现对头部报文添加指定的key与值,https://nginx.org/en/docs/http/ngx_http_headers_module.html

Syntax:	add_header name value [always];
Default:	—
Context:	http, server, location, if in location
#添加自定义首部,如下
add_header name value [always]
	add_header X-Via $server_addr;
	add_header X-Cache $upstream_cache_status;
	add_header X-Accel $server_name;
	
#添加自定义响应信息的尾部 1.13.2版本后支持
add_trailer name value [always]
6.1.1.4: 添加头部信息配置
   location /web {
       index index.html;
       proxy_pass http://172.16.10.50;
        add_header X-Via $server_addr; #下一条地址 ,根据服务器算
        add_header X-Cache $upstream_cache_status; #查看缓存是否命中
        add_header X-Accel $server_name;
   }

在这里插入图片描述

6.1.2:nginx http反向代理高级应用

在上一章节中nginx可以将客户端的请求转发至单台后端服务器但是无法转发至特特定的一组服务器,而且不能对后端服务器提供相应的服务器状态检测,但是nginx可以基于ngx_http_upstream_module模块提供服务器分组转发、权重分配、状态监测、调度算法等高级功能,官方文档:https://nginx.org/en/docs/http/ngx_http_upstream_module.html

6.1.2.1:http upstream配置参数
Syntax:	upstream name { ... }
Default:	—
Context:	http


upstream backend {
    server backend1.example.com weight=5;
    server 127.0.0.1:8080       max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;

    server backup1.example.com  backup;
}
server address [parameters]
#配置一个后端web服务器,配置在upstream内,至少要有一个server服务器配置
#server支持的parameters如下:
weight=number #设置权重,默认为1
max_conns=number #给当前server设置最大活动链接数,默认为0表示没有限制
fail_timeout=time #对后端服务器的失败检测超过时间,默认为10秒
max_fails=numbers #在fail_timeout时间对后端服务器连续检测失败多少次标记为不可用
proxy_next_upstream=error timeout; #指定在那种检测状态下将请求转发到其他服务器
backup #设置为备份服务器,当所有服务器不可用时将重新启用服务器
down #标记为down状态
resolve #当server定义的是主机名的时候,当A记录发生变化会自动应用新的IP而不用重启nginx
hash KEY consistent;
#基于指定key做hash计算,使用consistent参数,将使用ketama一致性hash算法,适用于后端是Cache服务器(如varnish)时使用,consistent定义使用一致性hash运算,一致性hash基于取模运算

hash $request_uri consistent;#基于用户请求的uri做hash
ip_hash;
#源地址hash调度方法,基于的客户端的remote_addr(源地址)做hash计算,以实现会话保持
least_conn;
#最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器
6.1.2.2:反向代理示例–多台web服务器
   upstream webserver {
       #hash $request_uri consistent;
       #ip_hash
       #least_conn;
       server 172.16.10.50:80 weight=1 fail_timeout=15s max_fails=3;
       server 172.16.10.61:80 weight=2 fail_timeout=15s max_fails=3;
       }
       
       
       
          location /web {
       index index.html;
       #proxy_pass http://dl.gf.com;
       proxy_pass http://webserver;
   }
6.1.2.3:反向代理示例–客户端IP透传:
    upstream webserver {
       #hash $request_uri consistent;
       #ip_hash
       #least_conn;
       server 172.16.10.50:80 weight=1 fail_timeout=15s max_fails=3;
       server 172.16.10.61:80 weight=2 fail_timeout=15s max_fails=3;
       server 172.16.10.62:80 weight=2 fail_timeout=15s max_fails=3 backup;
       }  
   location /web {
       index index.html;
       #proxy_pass http://dl.gf.com;
       proxy_pass http://webserver;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }
6.1.2.4: 反向代理实例-tomcat IP透传
 <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h  %{X-Forwarded-For}i  %l %u %t &quot;%r&quot; %s %b" />

6.2:实现nginx tcp负载均衡

nginx在1.9.0版本开始支持tcp模式的负载均衡,在1.9.13版本开始支持udp协议的负载,udp主要用于DNS的域名解析,其配置方式和指令和http代理类似,其基于ngx_stream_proxy_module模块实现tcp负载,另外基于模块ngx_stream_upstream_module实现后端服务器分组转发、权重分配、状态检测、调度算法等高级功能
官方文档:https://nginx.org/en/docs/stream/ngx_stream_core_module.html
6.2.1:tcp负载均衡配置参数:
 stream {
    upstream redis {
        #hash $remote_addr consistent;

        server 172.16.10.61:6379  max_fails=3 fail_timeout=30s;
    }
   server {
        listen 172.16.10.105:6379;
        proxy_connect_timeout 1s;
        proxy_timeout 3s;
        proxy_pass redis;
    }
}
~   


导入要在http以外
    include /apps/nginx/conf/tcp/*.conf;

6.3:实现FastCGI

CGI的由来

最早的web服务器只能简单的响应浏览器发来的http请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html文件(http://www.zbbz.com),但是后期随着网站功能增多网站开发越来越复杂,以至于出现动态技术,如果像php、java、python语言开发的网站,但是nginx/apache服务器并不能直接运行php、java这样的文件,apache实现的方式打补丁,但是nginx却通过与第三方基于协议实现,即通过某种特定协议将客户端请求转发给第三方服务处理,第三方服务器会新建新的进程处理用户的请求,处理完成后返回数据给nginx并回收进程,最后给nginx在返回给客户端,那这个约定就是通用网关接口(common gateway interface,简称CGI),CGI(协议)是web服务器和外部应用程序之间的接口标准,是cgi程序和web服务器之间传递信息的标准化接口

在这里插入图片描述

为什么会有FastCGI?

CGI协议虽然解决了语言解析器和web server之间通讯的问题,但是它的效率很低,因为web server没收到一个请求都会创建一个CGI进程,PHP解析器都会解析php.ini文件,初始化环境,请求结束的时候在关闭进程,对于每一个创建的CGI进程都会执行这些操作,所以效率很低,而FastCGI是用来提高CGI性能的,FastCGI每次处理完请求之后不会关闭进程,而是保留这个进程,使这个进程可以处理多个请求,这样的话每个请求都不用在重新创建一个进程了,大大提升了处理效率

在这里插入图片描述

什么是PHP-FPM?

php-fpm(FastCGI Process Manager: FastCGI进程管理器)是一个实现了FastCGI的管理程序,并且提供进程管理的功能,进程包括master进程和worker进程,master进程只有一个,负责监听端口,接受来自web server的请求,worker进程一般会有多个,每个进程中嵌入一个php解析器,进行php代码的处理

6.3.1:FastCGI配置指令:

nginx基于模块ngx_http_fastcgi_module实现通过fastcgi协议将指定的客户端请求转发至php-fpm处理,配置指令如下:

proxy_pass http://
fastcgi_pass 172.16.10.50:9000
#转发请求到后端服务器,address为后端的fastcgi server的地址,可用位置:location,if in locaiton

fastcgi_index  name;
#fastcgi默认的主要资源,实例:fastcgi_index  index.php;

fastcgi_param parameter value [if_not_empty];
#设置传递给FastCGI服务器的参数值,可以是文本,变量或组合,可用于将nginx的内置变量赋值给自定以key

fastcgi_param  REMOTE_ADDR        $remote_addr;#客户端的源ip
fastcgi_param  REMOTE_PORT        $remote_port;#客户端的源端口
fastcgi_param  SERVER_ADDR        $server_addr;#请求的服务器IP地址
fastcgi_param  SERVER_PORT        $server_port;#请求的服务器端口
fastcgi_param  SERVER_NAME        $server_name;#请求的server name
#nginx默认配置
#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;
        #}

缓存定义指令

	fastcgi_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [min_free=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];

定义fastcgi的缓存
	fastcgi_cache_path #缓存位置为磁盘的文件系统
		levels=1:2:2 #定义缓存目录结构层次,1:2:2可以生成2^4x2^8x2^8=1048576个目录
	keys_zone=proxycache:20m #指内存中缓存的大小,主要用于存放key和metadata(如:使用次数)
	inactive=120s; #缓存有效时间
	max_size=1g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值

缓存调用指令

fastcgi_cache zone | off;
#调用指定的缓存空间来缓存数据,可用位置:http,server,location

fastcgi_cache_key string;
#定义用走缓存项的key的字符串 实例:fastcgi_cache_key $request_uri;

fastcgi_cache_methods GET | HEAD | POST ...;
#为那些请求方法使用缓存

fastcgi_cache_min_uses numbers;
#缓存空间中的缓存项在inactive定义的非活动时间内至少要被访问到此所指定的次数放可被人做活动项

fastcgi_keep_conn on |off;
#收到后端服务器响应后,fastcgi服务器是否关闭连接,建议启用长连接

fastcgi_cache_valid [code ...] time;
#不同响应码各自的缓存时长

fastcgi_hide_header field;#隐藏响应头指定信息
fastcgi_pass_header field;#放回响应头指定新,默认不会将status、X-Accel 返回
6.3.2:fastcgi实例–nginx与php-fpm在同一服务器
6.3.2.1:基础环境
yum install php-fpm php-mysql -y 
systemctl start php-fpm 
6.3.2.2:php相关配置优化
[root@k8s-vip ~]# grep ^"[a-Z]" /etc/php-fpm.conf 
include=/etc/php-fpm.d/*.conf
pid = /run/php-fpm/php-fpm.pid
error_log = /var/log/php-fpm/error.log
daemonize = no #是否后台启动

cat /etc/php-fpm.d/www.conf
[www]
listen = 127.0.0.1:9000 #监听地址及IP
listen.allowed_clients = 127.0.0.1 #永许客户端从哪个源IP地址访问,要永许所有行首加;注释即可
user = nginx #php-fpm启动的用户和组,会涉及到后期文件的权限问题
group = nginx
pm = dynamic #动态模式进程管理
pm.max_children = 50 #静态模式下开启的php-fpm进程数量,在动态方式下他限定php-fpm最大进程数
pm.start_servers = 5 #动态模式下初始进程数,必须大于pm.min_spare_servers 和小于等于pm.max_children的值
pm.min_spare_servers = 5#最小空闲进程数
pm.max_spare_servers = 35 #最大空闲进程数
pm.max_requests = 500#进程累计请求回收值,会回收并重新生成新的子进程
pm.status_path = /status#状态返回URL
ping.path = /ping#ping访问地址
ping.response = pong #平返回值
slowlog = /var/log/php-fpm/www-slow.log#慢日志路径
php_admin_value[error_log] = /var/log/php-fpm/www-error.log#错误日志
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 128M
php_value[session.save_handler] = files#phpsession保存方式路径
php_value[session.save_path] = /var/lib/php/session#当时使用file保存session的文件路径
6.3.2.3:准备php测试页面
[root@k8s-vip ~]# cat /data/nginx/php/index.php 
<?php
  phpinfo();
?>
6.3.2.4:nginx配置转发
        location ~ \.php$ {
            root           /data/nginx/php; #$document_root调用root目录
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /data/nginx/php$fastcgi_script_name;
            #fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            #如果SCRIPT_FILENAME是绝对路径可以省略root /data/nginx/php;
            include        fastcgi_params;
        }

chattr命令详解

[root@localhost ~]# chattr [+-=] [属性] 文件或目录名

属性选项	功能
i	如果对文件设置 i 属性,那么不允许对文件进行删除、改名,也不能添加和修改数据;
如果对目录设置 i 属性,那么只能修改目录下文件中的数据,但不允许建立和删除文件;
a	如果对文件设置 a 属性,那么只能在文件中増加数据,但是不能删除和修改数据;
如果对目录设置 a 属性,那么只允许在目录中建立和修改文件,但是不允许删除文件;
u	设置此属性的文件或目录,在删除时,其内容会被保存,以保证后期能够恢复,常用来防止意外删除文件或目录。
s	和 u 相反,删除文件或目录时,会被彻底删除(直接从硬盘上删除,然后用 0 填充所占用的区域),不可恢复。

七:系统参数优化:

sysctl -p 加载选项
默认的linux内核参数考虑的是最通用场景,不符合用于支持高并发访问的web服务器的定义,根据业务特点来进行调整,当nginx作为静态web内容服务器、反向代理或者提供压缩服务器的服务器时,内核参数的调整都是不同的,此处针对最通用的、使nginx支持更多并发请求的TCP网络参数做简答配置,
修改/etc/sysctl.conf来更改内核参数
net.ipv4.ip_nonlocal_bind = 1 #永许非本地IP地址socket监听,永许本地没有本地的ip绑定
net.ipv4.ip_forward = 1 #开启IPv4转发
net.ipv4.tcp_timestamps = 0 #是否开启数据包时间戳(负载均衡不要开,会检查接收的报文,多数人打开同一个连接,可能会丢失)
net.ipv4.tcp_tw_reuse = 1 #端口复用(时用户打开网页,没有操作,服务器尝试断开连接)
net.ipv4.tcp_tw_recycle = 1 #快速回收TIME_WAIT状态,用于大量TIME_OUT场景 (时用户打开网页,没有操作,服务器尝试断开连接)


fs.file-max = 190638 
#表示单个进程较大可以打开的句柄数

net.ipv4.tcp_tw_reuse = 1
#参数设置为1,表示永许将TIME_WAIT状态的socket重新用于新的TCP连接,这将对于服务器来说意义重大,因为总有大量TIME_WAIT状态的连接存在

net.ipv4.tcp_keepalive_time=600
#当keepalive启动时,tcp发送keepalive消息的频度;默认时2小时,将其设置为10分钟,可更快的清理无效连接

net.ipv4.tcp_fin_timeout = 30
#当服务器主动关闭链接时,socket保持FIN_WAIT_2状态的较大时间,默认60s

net.ipv4.tcp_max_tw_buckets = 5000
#表示操作系统永许TIME_WAIT套接字数量的较大值,如超过此值,TIME_WAIT套接字将立刻清除并打印警告信息,默认为8000,过多的TIME_WAIT套接字会使web服务器变慢

net.ipv4.ip_local_port_range = 1024 65000
#定义udp和tcp链接的本地端口的取值范围

net.ipv4.tcp_rmem = 10240 87380 12582912
#定义了TCP接受socket请求缓存的内存最小值、默认值、较大值

net.ipv4.tcp_wmem = 10240 87380 12582912
#定义了TCP发送缓存的最小值、默认值、较大值


net.core.netdev_max_backlog = 8096
#当网卡接收数据包的速度大于内核处理速度时,会有一个队列保存这些数据包,这个参数表示该列队的较大值

net.core.rmem_default = 6291456
#表示内核套接字接收缓存区默认大小

net.core.wmem_default = 6291456
#表示内核套接字发送缓存区默认大小

net.core.rmem_max = 12582912
#表示内核套接字接收缓存区较大大小

net.core.wmem_max = 12582912
#表示内核套接字发送缓存区较大大小
注意:以上的四个参数,需要根据业务逻辑和实际的硬件成本来综合考虑

net.ipv4.tcp_syncookies=1
#与性能无关。用于解决TCP的SYN攻击

net.ipv4.tcp_max_syn_backlog = 8192
#这个参数表示TCP三次握手建立阶段接收SYN请求队列的较大长度,默认1024,将其设置的大一些可使出现nginx繁忙来不及accept新连接时,linux部至于丢失客户端发起的链接请求

net.ipv4.tcp_tw_recycle = 1
#这个参数用于设置启用timewait快速回收

net.core.somaxconn=262114
#选项默认值时128,这个参数用于调节系统同时发起的TCP连接数,在高并发的请求中,默认的值可能会导致链接超市或者重传,因此需要结合高并发请求数来调节此值

net.ipv4.tcp_max_orphanx=262114
#选项用于设定系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤立链接将立即被复位并输出警告信息。这个限制只是为了防止简单的DOS共集。不用过分依靠这个限制设置认为的减少这个值,更多的情况时增加这个值

2.2.6 修改系统文件描述符    系统优化
1.查看最大的标示符    ulimit -n 
2.调整文件描述符:  ulimit -SHn 65535  临时修改  S:soft limit  H:Hard limit
            大小写入: /etc/rc.local   永久修改
3.推荐控制文件描述符大小==> 
    更改:      <domain>   <type>   <item>   <value>
        echo '  *           -      nofile   65535' >> /etc/security/limits.conf
    更改后查看:tail -1 /etc/security/limits.conf   
        退出重新登陆后生效
    确认查看:ulimit -n

proxy_pass

在nginx中配置proxy_pass时,如果是按照^~匹配路径时,要注意proxy_pass后的url最后的/。当加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走;如果没有/,则会把匹配的路径部分也给代理走。

比如下面设置:
location ^~ /wangshibo/
{
proxy_cache js_cache;
proxy_set_header Host js.test.com;
proxy_pass http://js.test.com/;
}
如上面的配置,如果请求的url是http://servername/wangshibo/test.html会被代理成http://js.test.com/test.html
 
而如果这么配置
location ^~ /wangshibo/
{
proxy_cache js_cache;
proxy_set_header Host js.test.com;
proxy_pass http://js.test.com;
}
则请求的url是http://servername/wangshibo/test.html会被代理到http://js.test.com/wangshibo/test.html
 
当然,可以用如下的rewrite来实现/的功能
location ^~ /wangshibo/
{
proxy_cache js_cache;
proxy_set_header Host js.test.com;
rewrite /wangshibo/(.+)$ /$1 break;
proxy_pass http://js.test.com;
}

nginx负载均衡中后端节点服务器健康检查,阿里tengle模块

wget https://github.com/yaoweibin/nginx_upstream_check_module/archive/master.zip

正常情况下,nginx做反向代理,如果后端节点服务器宕掉的话,nginx默认是不能把这台realserver踢出upstream负载集群的,所以还会有请求转发到后端的这台realserver上面,这样势必造成网站访问故障。虽然nginx可以在localtion中启用proxy_next_upstream来解决返回给用户的错误页面,如下:



例如公司的网站访问的时候全部变成404页面,最后发现是后端的一台服务器不可用,直接访问那台后台的服务器的时候,返回的是404页面,因为upstream 里面设置了ip_hash。所以导致访问网站时怎么刷新都是404页面。这时可以使用nginx的一个功能,就是当后端的服务器返回给nginx502、504、404、执行超时等错误状态的时候,nginx会自动再把这个请求转发到upstream里面别的服务器上面,从而给网站用户提供更稳定的服务。
配置如下:
location /
{
#如果后端的服务器返回502、504、执行超时等错误,自动将请求转发到upstream负载均衡池中的另一台服务器,实现故障转移。
proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;
}
这样的话,也算是保障了后端服务器的一个高可用性。(下面实例配置中会用到)

proxy_pass

在nginx中配置proxy_pass时,如果是按照^~匹配路径时,要注意proxy_pass后的url最后的/。当加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走;如果没有/,则会把匹配的路径部分也给代理走。

比如下面设置:
location ^~ /wangshibo/
{
proxy_cache js_cache;
proxy_set_header Host js.test.com;
proxy_pass http://js.test.com/;
}
如上面的配置,如果请求的url是http://servername/wangshibo/test.html会被代理成http://js.test.com/test.html
 
而如果这么配置
location ^~ /wangshibo/
{
proxy_cache js_cache;
proxy_set_header Host js.test.com;
proxy_pass http://js.test.com;
}
则请求的url是http://servername/wangshibo/test.html会被代理到http://js.test.com/wangshibo/test.html
 
当然,可以用如下的rewrite来实现/的功能
location ^~ /wangshibo/
{
proxy_cache js_cache;
proxy_set_header Host js.test.com;
rewrite /wangshibo/(.+)$ /$1 break;
proxy_pass http://js.test.com;
}

nginx负载均衡中后端节点服务器健康检查,阿里tengle模块

wget https://github.com/yaoweibin/nginx_upstream_check_module/archive/master.zip

正常情况下,nginx做反向代理,如果后端节点服务器宕掉的话,nginx默认是不能把这台realserver踢出upstream负载集群的,所以还会有请求转发到后端的这台realserver上面,这样势必造成网站访问故障。虽然nginx可以在localtion中启用proxy_next_upstream来解决返回给用户的错误页面,如下:



例如公司的网站访问的时候全部变成404页面,最后发现是后端的一台服务器不可用,直接访问那台后台的服务器的时候,返回的是404页面,因为upstream 里面设置了ip_hash。所以导致访问网站时怎么刷新都是404页面。这时可以使用nginx的一个功能,就是当后端的服务器返回给nginx502、504、404、执行超时等错误状态的时候,nginx会自动再把这个请求转发到upstream里面别的服务器上面,从而给网站用户提供更稳定的服务。
配置如下:
location /
{
#如果后端的服务器返回502、504、执行超时等错误,自动将请求转发到upstream负载均衡池中的另一台服务器,实现故障转移。
proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;
}
这样的话,也算是保障了后端服务器的一个高可用性。(下面实例配置中会用到)


  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忙里偷闲学python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值