快速带你玩转高性能web服务器后续

目录

一、Nginx 高级配置

1.1 Nginx 状态页

 1.2 Nginx 压缩功能

1.3 Nginx的版本隐藏

1.4 Nginx 变量使用

1.4.1 内置变量

二、 Nginx Rewrite 相关功能

2.1 ngx_http_rewrite_module 模块指令

2.1.1 if 指令

2.1.2 set 指令

2.1.3 break 指令

2.1.4 return 指令

2.2 rewrite 指令

2.2.1 rewrite flag 使用介绍

2.2.2 rewrite案例: 域名永久与临时重定向

2.2.2.1 永久重定向304

2.2.2.2 临时重定向301

2.2.3 rewrite 案例: break 与 last

2.2.4 rewrite案例: 自动跳转 https

2.2.5 rewrite 案例: 判断文件是否存在

2.3 Nginx 防盗链

2.3.1 实现盗链

2.3.2 实现防盗链

二、 Nginx 反向代理功能

2.1 实现 http 反向代理

2.1.1 http 协议反向代理

2.1.1.1 反向代理配置参数

2.1.1.2 实战案例: 反向代理单台 web 服务器

2.1.1.3 实战案例: 指定 location 实现反向代理

2.1.1.3.1 针对指定的 location

2.1.1.3.2 针对特定的资源实现代理

2.1.1.4 反向代理示例: 缓存功能

2.1.1.4.1 非缓存场景压测

2.1.1.4.2 准备缓存配置

2.1.1.4.3 访问并验证缓存文件

2.1.2 http 反向代理负载均衡

2.1.2.1 http upstream配置参数

2.1.2.2 反向代理示例: 后端多台 web服务器

2.2 实现 Nginx 四层负载均衡

2.2.1 tcp负载均衡配置参数

2.2.2 负载均衡实例: MySQL

2.2.3 udp 负载均衡实例: DNS

2.3 实现 FastCGI

2.3.1 FastCGI配置指令

2.3.2 FastCGI实战案例 : Nginx与php-fpm在同一服务器

2.3.3 php的动态扩展模块(php的缓存模块)

2.3.4 php高速缓存

3.1 openresty


一、Nginx 高级配置

1.1 Nginx 状态页

  • 基于nginx 模块 ngx_http_stub_status_module 实现,
  • 在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module
  • 否则配置完成之后监测会是提示法错误
注意: 状态页显示的是整个服务器的状态,而非虚拟主机的状态
# 配置示例:
location /nginx_status {
        stub_status;
        auth_basic "auth login";
        auth_basic_user_file /apps/nginx/conf/.htpasswd;
        allow 192.168.0.0/16;
        allow 127.0.0.1;
        deny all;
}
# 状态页用于输出 nginx 的基本状态信息:
# 输出信息示例:
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
上面三个数字分别对应 accepts,handled,requests 三个值
Reading: 6 Writing: 179 Waiting: 106
Active connections:         #当前处于活动状态的客户端连接数
                                        #包括连接等待空闲连接数=reading+writing+waiting
accepts:                         #统计总值,Nginx 自启动后已经接受的客户端请求连接的总数。
handled:                         #统计总值,Nginx自启动后已经处理完成的客户端请求连接总数
                                        #通常等于accepts,除非有因worker_connections限制等被拒绝的
连接
requests:                         #统计总值,Nginx自启动后客户端发来的总的请求数
Reading:                                 #当前状态,正在读取客户端请求报文首部的连接的连接数
                                                #数值越大,说明排队现象严重,性能不足
Writing:                                 #当前状态,正在向客户端发送响应报文过程中的连接数,数值越大, 说明访问量很大
Waiting:                                 #当前状态,正在等待客户端发出请求的空闲连接数
                                                        开启 keep-alive的情况下,这个值等于active –
(reading+writing)

 1.2 Nginx 压缩功能

Nginx 支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,样有助于降低出口带宽的利用率,降低企业的IT 支出,不过会占用相应的CPU 资源。
Nginx 对文件的压缩功能是依赖于模块 ngx_http_gzip_module, 默认是内置模
配置指令如下:
# 启用或禁用 gzip 压缩,默认关闭
gzip on | off;
# 压缩比由低到高从 1 到 9 ,默认为 1 ,值越高压缩后文件越小,但是消耗 cpu 比较高。基本设定未 4 或者 5
gzip_comp_level 4;
# 禁用 IE6 gzip 功能,早期的 IE6 之前的版本不支持压缩
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;
# 预压缩,即直接从磁盘找到对应文件的 gz 后缀的式的压缩文件返回给用户,无需消耗服务器 CPU
# 注意 : 来自于 ngx_http_gzip_static_module 模块
gzip_static on | off;
示例:
# 重启 nginx 并进行访问测试压缩功能
[root@nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/data -p
[root@nginx ~]#  cp /usr/local/nginx/logs/access.log /webdata/nginx/timinglee.org/lee/data/data.txt
[root@nginx ~]# ll /webdata/nginx/timinglee.org/lee/data/data.txt
-rw-r--r-- 1 root root 2494866 Aug 20 23:18 /webdata/nginx/timinglee.org/lee/data/data.txt

[root@nginx ~]# echo test > /webdata/nginx/timinglee.org/lee/data/test.html         #小于1k 的文件测试是否会压缩
[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
gzip  on;
gzip_comp_level  5;
gzip_min_length  1k;
gzip_types text/plain application/javascript application/x-javascript text/css
application/xml text/javascript application/x-httpd-php image/gif image/png;
gzip_vary on;
# 重启 Nginx 并访问测试:

[root@nginx ~]# nginx -s reload
[root@nginx ~]# 

[root@nginx ~]# curl --head --compressed www.timinglee.org/data/test.html
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Tue, 20 Aug 2024 15:25:51 GMT
Content-Type: text/html
Content-Length: 5
Last-Modified: Tue, 20 Aug 2024 15:18:58 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "66c4b3e2-5"
Accept-Ranges: bytes

[root@nginx ~]# curl --head --compressed www.timinglee.org/data/data.txt
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Tue, 20 Aug 2024 15:26:08 GMT
Content-Type: text/plain
Last-Modified: Tue, 20 Aug 2024 15:18:05 GMT
Connection: keep-alive
Keep-Alive: timeout=60
Vary: Accept-Encoding
ETag: W/"66c4b3ad-261192"
Content-Encoding: gzip

1.3 Nginx的版本隐藏

用户在访问 nginx 的时候,我们可以从报文中获得 nginx 的版本,相对于裸漏版本号的 nginx ,我们把其隐藏起来更安全

[root@nginx ~]# cd nginx-1.24.0/
[root@nginx nginx-1.24.0]# vim src/core/nginx.h

#define nginx_version      1024000
#define NGINX_VERSION      "1.24.0"
#define NGINX_VER          "nginx/" NGINX_VERSION

1.4 Nginx 变量使用

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

1.4.1 内置变量

官方文档
http://nginx.org/en/docs/varindex.html
常用内置变量
$remote_addr;
# 存放了客户端的地址,注意是客户端的公网 IP
$args;
# 变量中存放了 URL 中的所有参数
# 例如 :https://search.jd.com/Search?keyword= 手机 &enc=utf-8
# 返回结果为 : keyword= 手机 &enc=utf-8
$is_args
# 如果有参数为 ? 否则为空
$document_root;
# 保存了针对当前资源的请求的系统根目录 , 例如 :/webdata/nginx/timinglee.org/lee 。
$document_uri;
# 保存了当前请求中不包含参数的 URI ,注意是不包含请求的指令
# 比如 :http://lee.timinglee.org/var?\id=11111 会被定义为 /var
# 返回结果为 :/var
$host;
# 存放了请求的 host 名称
limit_rate 10240;
echo $limit_rate;
# 如果 nginx 服务器使用 limit_rate 配置了显示网络速率,则会显示,如果没有设置, 则显示 0
$remote_port;
# 客户端请求 Nginx 服务器时随机打开的端口,这是每个客户端自己的端口
$remote_user;
# 已经经过 Auth Basic Module 验证的用户名
$request_body_file;
# 做反向代理时发给后端服务器的本地资源的名称
$request_method;
# 请求资源的方式, GET/PUT/DELETE 等
$request_filename;
# 当前请求的资源文件的磁盘路径,由 root 或 alias 指令与 URI 请求生成的文件绝对路径,
# 如 :webdata/nginx/timinglee.org/lee/var/index.html
$request_uri;
# 包含请求参数的原始 URI ,不包含主机名,相当于 :$document_uri?$args,
# 例如: /main/index.do?id=20190221&partner=search
$scheme;
# 请求的协议,例如 :http , https,ftp 等
$server_protocol;
# 保存了客户端请求资源使用的协议的版本,例如 :HTTP/1.0 , HTTP/1.1 , HTTP/2.0 等
$server_addr;
# 保存了服务器的 IP 地址
$server_name;
# 虚拟主机的主机名
$server_port;
# 虚拟主机的端口号
$http_user_agent;
# 客户端浏览器的详细信息
$http_cookie;
# 客户端的所有 cookie 信息
$cookie_<name>
#name 为任意请求报文首部字部 cookie 的 key 名
$http_<name>
#name 为任意请求报文首部字段 , 表示记录请求报文的首部字段, ame 的对应的首部字段名需要为小写,如果有横线需要替换为下划线
# 示例 :
echo $http_user_agent;
echo $http_host;
$sent_http_<name>
#name 为响应报文的首部字段, name 的对应的首部字段名需要为小写,如果有横线需要替换为下划线 , 此变量有问题
echo $sent_http_server;
$arg_<name>
# 此变量存放了 URL 中的指定参数, name 为请求 url 中指定的参数
echo $arg_id;
示例:
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf 
server {
    listen 80;
    server_name www.timinglee.org;
    root /webdata/nginx/timinglee.org/lee;
    location /var {
        default_type text/html;
        echo $remote_addr;
        echo $args;
        echo $document_root;
        echo $document_uri;
        echo $host;
        echo $http_user_agent;
        echo $request_filename;
        echo $scheme;
        echo $scheme://$host$document_uri?$args;
        echo $http_cookie;
        echo $cookie_key2;
        echo $http_Accept;
    }
}  
#测试

[root@nginx ~]# nginx -s reload
[root@nginx ~]# 

[root@nginx ~]# curl -b "title=lee;key1=lee,key2=timinglee" "www.timinglee.org/var?search=lee&&id=666666"

192.168.10.140

search=lee&&id=666666
/webdata/nginx/timinglee.org/lee
/var
lee.timinglee.org
curl/7.29.0
/webdata/nginx/timinglee.org/lee/var
http
http://lee.timinglee.org/var?search=lee&&id=666666
title=lee;key1=lee,key2=timinglee
timinglee
*/*
1.4.2 自定义变量
假如需要自定义变量名称和值,使用指令 set $variable value;
语法格式:
Syntax: set $variable value;
Default: —
Context: server, location, if
示例 :
set $name timinglee;
echo $name;
set $my_port $server_port;
echo $my_port;
echo "$server_name:$server_port";
[root@nginx ~]# mkdir -p /webdata/nginx/timinglee.org/lee/var
[root@nginx ~]# echo xixi > /webdata/nginx/timinglee.org/lee/var/index.html
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf 
server {
    listen 80;
    server_name www.timinglee.org;
    root /webdata/nginx/timinglee.org/lee;
    location /var {
        default_type text/html;
        set $name timinglee;
        echo $name;
        set $web_port $server_port;
        echo $web_port;
    }
}
#测试输出
[root@nginx ~]# nginx -s reload
[root@nginx ~]# 
[root@nginx ~]# curl www.timinglee.org/var
timinglee
80

二、 Nginx Rewrite 相关功能

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

2.1 ngx_http_rewrite_module 模块指令

官方文档 : https://nginx.org/en/docs/http/ngx_http_rewrite_module.html

2.1.1 if 指令

官方文档:
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#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         #判断请求的文件或目录是否存在和是否不存在 ( 包括文件,目录,软链接 )
#注意:
#如果$变量的值为空字符串或0,则if指令认为该条件为false,其他条件为true。
#nginx 1.0.1之前$变量的值如果以0开头的任意字符串会返回false
示例:
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf 
    location /test {
        index index.html;
        default_type text/html;
        if ( $scheme = http ){
        echo "if ---------> $scheme";
    }
    if ( $scheme = https ){
        echo "if ---------> $scheme";
     }
    }
    location /test2 {
      if ( !-e $request_filename ){
        echo "$request_filename is not exist";
        return 409;
      } 
    }   
#测试:
[root@nginx ~]# curl www.timinglee.org/test/
if ---------> http
[root@nginx ~]# curl www.timinglee.org/test2/test
/webdata/nginx/timinglee.org/lee/test2/test is not exist

2.1.2 set 指令

指定 key 并给其定义一个变量,变量可以调用 Nginx 内置变量赋值给 key
另外 set 定义格式为 set $key value , value 可以是 text, variables 和两者的组合。

[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf 

server {
listen 80;
server_name www.timinglee.org;
root /webdata/nginx/timinglee.org/lee;
location /test3{
set $name lee;
echo $name;
 }
}
#测试:
[root@nginx ~]# curl www.timinglee.org/test3/
lee

2.1.3 break 指令

用于中断当前相同作用域 (location) 中的其他 Nginx 配置
与该指令处于同一作用域的 Nginx 配置中,位于它前面的配置生效
位于后面的 ngx_http_rewrite_module 模块中指令就不再执行
Nginx 服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,、
该指令可以在 server 块和 locationif 块中使用
注意: 如果break指令在location块中后续指令还会继续执行,只是不执行 ngx_http_rewrite_module
模块的指令,其它指令还会执行
使用语法如下:
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
listen 80;
server_name www.timinglee.org;
root /webdata/nginx/timinglee.org/lee;
location /break{
default_type text/html;
set $name lee;
echo $name;
break;
set $port $server_port;
echo $port;
 }
}
#测试:
[root@nginx ~]# curl www.timinglee.org/break/        # 当未添加 break 时
lee
80
[root@nginx ~]# curl www.timinglee.org/break/        # 添加 break 后
lee

2.1.4 return 指令

return 用于完成对请求的处理,并直接向客户端返回响应状态码,比如 : 可以指定重定向 URL( 对于特殊重定向状态码,301/302 等 ) 或者是指定提示文本内容 ( 对于特殊状态码 403/500 等 ) ,处于此指令后的所有配置都将不被执行,return 可以在 server 、 if 和 location 块进行配置
语法格式:
return code; # 返回给客户端指定的 HTTP 状态码
return code [text]; # 返回给客户端的状态码及响应报文的实体内容
# 可以调用变量 , 其中 text 如果有空格 , 需要用单或双引号
return code URL; # 返回给客户端的 URL 地址
示例:
server {
listen 80;
server_name www.timinglee.org;
root /webdata/nginx/timinglee.org/lee;
location /return {
default_type text/html;
if ( !-e $request_filename){
return 301 http://www.baidu.com;
#return 666 "$request_filename is not exist";
}
echo "$request_filename is exist";
 }
}
测试:
[root@client ~]# curl www.timinglee.org/return
/webdata/nginx/timinglee.org/lee/return is exist
[root@client ~]# curl www.timinglee.org/return1
/webdata/nginx/timinglee.org/lee/return1 is not exist
# 测试 return 301 http://www.baidu.com;
可在浏览器直接访问 lee.timinglee.org/return1
return 示例:
location /test {
        default_type application/json;
        return 200 '{"status:"success"}';
}

2.2 rewrite 指令

通过正则表达式的匹配来改变 URI ,可以同时存在一个或多个指令,按照顺序依次对 URI 进行匹配,rewrite主要是针对用户请求的 URL 或者是 URI 做具体处理
官方文档:
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
语法格式 :
rewrite regex replacement [flag];
  • rewrite将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为表达式指定的新的URI
  • 注意:如果在同一级配置块中存在多个rewrite规则,那么会自下而下逐个检查;被某条件规则替换完成后,会重新一轮的替换检查,隐含有循环机制,但不超过10次;如果超过,提示500响应码,[flag]所表示的标志位用于控制此循环机制
  • 如果替换后的URL是以http://或https://开头,则替换结果会直接以重定向返回给客户端, 即永久重定向301
正则表达式格式
. # 匹配除换行符以外的任意字符
\w # 匹配字母或数字或下划线或汉字
\s # 匹配任意的空白符
\d # 匹配数字
\b # 匹配单词的开始或结束
^ # 匹配字付串的开始
$ # 匹配字符串的结束
* # 匹配重复零次或更多次
+ # 匹配重复一次或更多次
? # 匹配重复零次或一次
(n) # 匹配重复 n 次
{n,} # 匹配重复 n 次或更多次
{n,m} # 匹配重复 n 到 m 次
*? # 匹配重复任意次,但尽可能少重复
+? # 匹配重复 1 次或更多次,但尽可能少重复
?? # 匹配重复 0 次或 1 次,但尽可能少重复
{n,m}? # 匹配重复 n 到 m 次,但尽可能少重复
{n,}? # 匹配重复 n 次以上,但尽可能少重复
\W # 匹配任意不是字母,数字,下划线,汉字的字符
\S # 匹配任意不是空白符的字符
\D # 匹配任意非数字的字符
\B # 匹配不是单词开头或结束的位置
[^x] # 匹配除了 x 以外的任意字符
[^lee] # 匹配除了 magedu 这几个字母以外的任意字符

2.2.1 rewrite flag 使用介绍

利用 nginx 的 rewrite 的指令,可以实现 url 的重新跳转, rewrite 有四种不同的 flag ,分别是 redirect( 临时重定向302) 、 permanent( 永久重定向 301) 、 break 和 last 。其中前两种是跳转型的 flag ,后两种是代理型
  • 跳转型指由客户端浏览器重新对新地址进行请求
  • 代理型是在WEB服务器内部实现跳转
rewrite 格式
Syntax: rewrite regex replacement [flag]; # 通过正则表达式处理用户请求并返回替换后的数据包。
Default: —
Context: server, location, if
flag 说明
redirect;
# 临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新 URL 给客户端
# 由客户端重新发起请求 ; 使用相对路径 , 或者 http:// 或 https:// 开头,状态码: 302
permanent;
# 重写完成后以永久重定向方式直接返回重写后生成的新 URL 给客户端
# 由客户端重新发起请求,状态码: 301
break;
# 重写完成后 , 停止对当前 URL 在当前 location 中后续的其它重写操作
# 而后直接跳转至重写规则配置块之后的其它配置,结束循环,建议在 location 中使用
# 适用于一个 URL 一次重写
last;
# 重写完成后 , 停止对当前 URI 在当前 location 中后续的其它重写操作,
# 而后对新的 URL 启动新一轮重写检查,不建议在 location 中使用
# 适用于一个 URL 多次重写,要注意避免出现超过十次以及 URL 重写后返回错误的给用户

2.2.2 rewrite案例: 域名永久与临时重定向

域名的临时的调整,后期可能会变,之前的域名或者 URL 可能还用、或者跳转的目的域名和 URL 还会跳转,这种情况浏览器不会缓存跳转, 临时重定向不会缓存域名解析记录 (A 记录 ) ,但是永久重定向会缓存。
示例: 因业务需要,将访问源域名 www.timinglee.org 的请求永久重定向到 www.timinglee.com
location / {
        root /data/nginx/html/pc;
        index index.html;
        rewrite / http://www.timinglee.com permanent;
        #rewrite / http://www.timinglee.com redirect;
}
# 重启 Nginx 并访问域名 http://www.timinglee.org 进行测试
2.2.2.1 永久重定向304
  • 域名永久型调整,即域名永远跳转至另外一个新的域名,之前的域名再也不使用,跳转记录可以缓存到客户端浏览器
  • 永久重定向会缓存DNS解析记录, 浏览器中有 from disk cache 信息,即使nginx服务器无法访问,浏览器也会利用缓存进行重定向
  • 比如: 京东早期的域名 www.360buy.com 由于与360公司类似,于是后期永久重定向到了 www.jd.com
示例
[root@nginx lee]# echo 123456 > /webdata/nginx/timinglee.org/lee/index.html
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
    listen 80;
    server_name lee.timinglee.org;
    root /webdata/nginx/timinglee.org/lee;
    location / {
        #rewrite / http://lee.timinglee.com redirect;
        rewrite / http://lee.timinglee.com permanent;
    }
}   
server {
    listen 80;
    server_name lee.timinglee.com;
    root /webdata/nginx/timinglee.com/lee;
}

#测试:
[root@nginx ~]# nginx -s reload
[root@nginx ~]# 

2.2.2.2 临时重定向301
域名临时重定向,告诉浏览器域名不是固定重定向到当前目标域名,后期可能随时会更改,因此浏览器不会缓存当前域名的解析记录,而浏览器会缓存永久重定向的DNS 解析记录,这也是临时重定向与永久
重定向最大的本质区别。
即当 nginx 服务器无法访问时 , 浏览器不能利用缓存 , 而导致重定向失败
示例
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
        listen 80;
        server_name lee.timinglee.org;
        root /webdata/nginx/timinglee.org/lee;
        location / {
        rewrite / http://lee.timinglee.com redirect;
        #rewrite / http://lee.timinglee.com permanent;
        }
}
server {
        listen 80;
        server_name lee.timinglee.com;
        root /webdata/nginx/timinglee.com/lee;
}

2.2.3 rewrite 案例: break 与 last

[root@nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/{test1,test2,break}
[root@nginx ~]# echo test1 > /webdata/nginx/timinglee.org/lee/test1/index.html
[root@nginx ~]# echo test2 > /webdata/nginx/timinglee.org/lee/test2/index.html
[root@nginx ~]# echo break > /webdata/nginx/timinglee.org/lee/break/index.html
[root@nginx ~]#vim /usr/local/nginx/conf.d/vhosts.conf
server {
listen 80;
server_name lee.timinglee.org;
root /webdata/nginx/timinglee.org/lee;
location /break {
root /webdata/nginx/timinglee.org/lee;
rewrite ^/break/(.*) /test1/$1 last;
rewrite ^/test1/(.*) /test2/$1 break;
}
location /last {
root /webdata/nginx/timinglee.org/lee;
rewrite ^/last/(.*) /test1/$1 last;
rewrite ^/test1/(.*) /test2/$1 last;
}
location /test1 {
default_type text/html;
return 666 "new test1";
}
location /test2 {
root /webdata/nginx/timinglee.org/lee;
   }
}
[root@nginx ~]# curl -L lee.timinglee.org/break/index.html
test1
[root@nginx ~]#curl -L lee.timinglee.org/last/index.html
new test1

2.2.4 rewrite案例: 自动跳转 https

案例:基于通信安全考虑公司网站要求全站 https ,因此要求将在不影响用户请求的情况下将 http 请求全部自动跳转至 https ,另外也可以实现部分 location 跳转
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
        listen 443 ssl;
        listen 80;
        ssl_certificate /apps/nginx/certs/www.timinglee.org.crt;
        ssl_certificate_key /apps/nginx/certs/www.timinglee.org.key;
        ssl_session_cache shared:sslcache:20m;
        ssl_session_timeout 10m;
        server_name www.timniglee.org;
        location / { #针对全站跳转
        root /data/nginx/html/pc;
                index index.html;
                if ($scheme = http ){ #如果没有加条件判断,会导致死循环
                rewrite / https://$host redirect;
     }
}
                location /login { #针对特定的URL 进行跳转 https
                if ($scheme = http ){ #如果没有加条件判断,会导致死循环
                rewrite / https://$host/login redirect;
         }
   }
}
# 重启 Nginx 并访问测试
[root@nginx ~]#curl -ikL www.timinglee.org
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.18.0
Date: Thu, 08 Oct 2020 15:23:48 GMT
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: https://www.magedu.org
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Thu, 08 Oct 2020 15:23:48 GMT
Content-Type: text/html
Content-Length: 7
Last-Modified: Sat, 26 Sep 2020 01:18:32 GMT
Connection: keep-alive
ETag: "5f6e96e8-7"
Accept-Ranges: bytes
pc web

2.2.5 rewrite 案例: 判断文件是否存在

案例:当用户访问到公司网站的时输入了一个错误的 URL ,可以将用户重定向至官网首页
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
location / {
        root /data/nginx/html/pc;
        index index.html;
        if (!-e $request_filename) {
                rewrite .* http://www.timinglee.org/index.html; #实现客户端浏览器的302 跳转
                #rewrite .* /index.html; #web服务器内部跳转
    }
}
# 重启 Nginx 并访问测试

2.3 Nginx 防盗链

防盗链基于客户端携带的 referer 实现, referer 是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer 就是之前的那个网站域名,正常的 referer 信息有以下几种:
none : # 请求报文首部没有 referer 首部,
# 比如用户直接在浏览器输入域名访问 web 网站,就没有 referer 信息。
blocked : # 请求报文有 referer 首部,但无有效值,比如为空。
server_names : #referer 首部中包含本主机名及即 nginx 监听的 server_name 。
arbitrary_string : # 自定义指定字符串,但可使用 * 作通配符。示例 : *.timinglee.org
www.timinglee.*
regular expression : # 被指定的正则表达式模式匹配到的字符串 , 要使用 ~ 开头,例如:
~.*\.timinglee\.com
正常通过搜索引擎搜索 web 网站并访问该网站的 referer 信息如下:
172.25.254.1 - - [22/Jul/2024:09:27:36 +0800] "GET /favicon.ico HTTP/1.1" 404 149
"http://lee.timinglee.org/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0)
Gecko/20100101 Firefox/115.0"
2024/07/22 09:27:36 [error] 34596#0: *205 open()
"/webdata/nginx/timinglee.org/lee/favicon.ico" failed (2: No such file or
directory), client: 172.25.254.1, server: lee.timinglee.org, request: "GET
/favicon.ico HTTP/1.1", host: "lee.timinglee.org", referrer:
"http://lee.timinglee.org/"

2.3.1 实现盗链

在一个 web 站点盗链另一个站点的资源信息,比如 : 图片、视频等
# 新建一个主机 192.168.10.141, 盗取另一台主机 lee.timinglee.org/images/logo.png 的图片
[root@client ~]# yum install httpd -y
[root@client html]# vim /var/www/html/index.html
# 准备盗链 web 页面:
<html>
<head>
<meta http-equiv=Content-Type content="text/html;charset=utf-8">
<title> 盗链 </title>
</head>
<body>
<img src="http://lee.timinglee.org/images/logo.png" >
<h1 style="color:red"> 欢迎大家 </h1>
<p><a href=http://lee.timinglee.org> 狂点老李 </a> 出门见喜 </p>
</body>
</html>
# 重启 apache 并访问 http://192.168.10.140  测试
# 验证两个域名的日志,是否会在被盗连的 web 站点的日志中出现以下盗链日志信息:
[root@Nginx ~]# cat /usr/local/nginx/logs/access.log
192.168.10.1 - - [22/Jul/2024:09:50:01 +0800] "GET /images/logo.png HTTP/1.1" 304
0 "http:/192.168.10.140/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Edg/126.0.0.0"
192.168.10.1 - - [22/Jul/2024:09:50:18 +0800] "GET / HTTP/1.1" 304 0
"http://192.168.10.140/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Edg/126.0.0.0"

2.3.2 实现防盗链

基于访问安全考虑, nginx 支持通过 ngx_http_referer_module 模块 , 检查访问请求的 referer 信息是否有效实现防盗链功能
官方文档 :
https://nginx.org/en/docs/http/ngx_http_referer_module.html
示例 : 定义防盗链:
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
listen 80;
server_name lee.timinglee.org;
root /webdata/nginx/timinglee.org/lee;
location /images {
valid_referers none blocked server_names *.timinglee.org ~\.baidu\.;
if ($invalid_referer){
#return 403;
rewrite ^/ http://lee.timinglee.org/daolian.png permanent;
     }
  }
}
# 重启 Nginx 并访问测试
http://192.168.10.140

二、 Nginx 反向代理功能

  • 反向代理:reverse proxy,指的是代理外网用户的请求到内部的指定的服务器,并将数据返回给用户的一种方式,这是用的比较多的一种方式。
  • Nginx 除了可以在企业提供高性能的web服务之外,另外还可以将 nginx 本身不具备的请求通过某种预定义的协议转发至其它服务器处理,不同的协议就是Nginx服务器与其他服务器进行通信的一种规范,主要在不同的场景使用以下模块实现不同的功能
ngx_http_proxy_module: # 将客户端的请求以 http 协议转发至指定服务器进行处理
ngx_http_upstream_module # 用于定义为 proxy_pass,fastcgi_pass,uwsgi_pass
                                                #等指令引用的后端服务器分组
ngx_stream_proxy_module: # 将客户端的请求以 tcp 协议转发至指定服务器处理
ngx_http_fastcgi_module: # 将客户端对 php 的请求以 fastcgi 协议转发至指定服务器助理
ngx_http_uwsgi_module: # 将客户端对 Python 的请求以 uwsgi 协议转发至指定服务器处理
逻辑调用关系:

访问逻辑图:

  • 同构代理:用户不需要其他程序的参与,直接通过http协议或者tcp协议访问后端服务器
  • 异构代理:用户访问的资源时需要经过处理后才能返回的,比如php,python,等等,这种访问资源需要经过处理才能被访问

2.1 实现 http 反向代理

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

2.1.1 http 协议反向代理

2.1.1.1 反向代理配置参数
# 官方文档: 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://172.25.254.30:8080;         #8080后面无uri, 即无 / 符号 ,
                                                                #需要将location后面url 附加到proxy_pass指定的
url 后面
                                                                        #此行为类似于root
                                                                #proxy_pass指定的uri不带斜线将访问的/web
                                                                        #等于访问后端服务器
proxy_pass http://172.25.254.40:8080/;                         #8080后面有uri,即有 / 符号
                                                               #相当于置换,即访问/web时实际返回proxy_pass后面
uri 内容
                                                                #此行为类似于alias
                                                                #proxy_pass指定的uri带斜线
                                                                #等于访问后端服务器的
                                                                #http://172.25.254.40:8080/index.html
                                                                #内容返回给客户端
}                                                                         # http://nginx/web/index.html ==>
http://1:8080
# 重启 Nginx 测试访问效果:
#curl -L http://www.timinglee.org/web
# 如果 location 定义其 uri 时使用了正则表达式模式 ( 包括 ~,~*, 但不包括 ^~) ,则 proxy_pass 之后必须不能使用uri
# 即不能有 / , 用户请求时传递的 uri 将直接附加至后端服务器之后
server {
        ...
        server_name HOSTNAME;
        location ~|~* /uri/ {
                proxy_pass http://host:port;                 #proxy_pass后面的url 不能加/
       }
        ...
    }
http://HOSTNAME/uri/ --> http://host/uri/
proxy_hide_header field;                         #用于nginx作为反向代理的时候
                                                                #在返回给客户端http响应时
                                                                #隐藏后端服务器相应头部的信息
                                                                #可以设置在http,server或location块
# 示例 : 隐藏后端服务器 ETag 首部字段
location /web {
        index index.html;
        proxy_pass http://10.0.0.18:8080/;
        proxy_hide_header ETag;
}
proxy_pass_header field; # 透传
# 默认 nginx 在响应报文中不传递后端服务器的首部字段 Date, Server, X-Pad, X-Accel 等参数
# 如果要传递的话则要使用 proxy_pass_header field 声明将后端服务器返回的值传递给客户端
#field 首部字段大小不敏感
# 示例 : 透传后端服务器的 Server 和 Date 首部给客户端 , 同时不再响应报中显示前端服务器的 Server 字段
proxy_pass_header Server;
proxy_pass_header Date;
proxy_pass_request_body on | off;
# 是否向后端服务器发送 HTTP 实体部分 , 可以设置在 http,server 或 location 块,默认即为开启
proxy_pass_request_headers on | off;
# 是否将客户端的请求头部转发给后端服务器,可以设置在 http,server 或 location 块,默认即为开启
proxy_set_header;
# 可更改或添加客户端的请求头部信息内容并转发至后端服务器,比如在后端服务器想要获取客户端的真实 IP 的
时候,就要更改每一个报文的头部
# 示例 :
location ~ /web {
proxy_pass http://172.25.254.20:80;
proxy_hide_header ETag;
proxy_pass_header Server;
proxy_pass_request_body on;
proxy_pass_request_headers on;
proxy_set_header X-Forwarded-For $remote_addr;
}
[root@apache20 ~]# vim /etc/httpd/conf/httpd.conf
LogFormat "\"%{X-Forwarded-For}i\" %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%
{User-Agent}i\"" combined
访问后看后端服务器日志
proxy_connect_timeout time;
# 配置 nginx 服务器与后端服务器尝试建立连接的超时时间,默认为 60 秒
用法如下: proxy_connect_timeout 6s;
#60s 为自定义 nginx 与后端服务器建立连接的超时时间 , 超时会返回客户端 504 响应码
proxy_read_timeout time;
# 配置 nginx 服务器向后端服务器或服务器组发起 read 请求后,等待的超时时间,默认 60s
proxy_send_timeout 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 。
2.1.1.2 实战案例: 反向代理单台 web 服务器
要求:将用户对域 www.timinglee.org 的请求转发给后端服务器处理
[root@nginx ~]# cat /usr/local/nginx/conf.d/vhosts.conf
server {
        listen 80;
        server_name www.timinglee.org;
        location / {
        proxy_pass http://192.168.10.141;
        }
}
# 重启 Nginx 并访问测试
2.1.1.3 实战案例: 指定 location 实现反向代理
2.1.1.3.1 针对指定的 location
server {
        listen 80;
        server_name www.timinglee.org;
        location / {
        proxy_pass http://192.168.10.141;
        }
        location ~ /static {
                proxy_pass http://192.168.10.140:8080;
        }
}
# 后端 web 服务器必须要有相对于的访问 URL
[root@nginx ~]## mkdir /var/www/html/static
[root@nginx ~]## echo static  192.168.10.140 > /var/www/html/static/index.html
[root@nginx2 ~]#]# echo 192.168.10.141 > /var/www/html/index.html
# 重启 Nginx 并访问测试:
[root@nginx ~]# curl www.timinglee.org/static/
static  192.168.10.140
[root@nginx ~]# curl www.timinglee.org
192.168.10.141
2.1.1.3.2 针对特定的资源实现代理

[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
        listen 80;
        server_name www.timinglee.org;
        location / {
                proxy_pass http://192.168.10.141;
        }
        location ~ \.(png|jpg|gif) {
                proxy_pass http://192.168.10.140:8080;
        }
}
2.1.1.4 反向代理示例: 缓存功能
缓存功能默认关闭状态 , 需要先动配置才能启用
proxy_cache zone_name | off; 默认 off
# 指明调用的缓存,或关闭缓存机制 ;Context:http, server, location
#zone_name 表示缓存的名称 . 需要由 proxy_cache_path 事先定义
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=zone_name:size [inactive=time] [max_size=size] [manager_files=number]
[manager_sleep=time] [manager_threshold=time] [loader_files=number]
[loader_sleep=time] [loader_threshold=time] [purger=on|off]
[purger_files=number] [purger_sleep=time] [purger_threshold=time];
# 示例:在 http 配置定义缓存信息
proxy_cache_path /var/cache/nginx/proxy_cache # 定义缓存保存路径, proxy_cache 会自动创建
levels=1:2:2 # 定义缓存目录结构层次
#1:2:2 可以生成
2^4x2^8x2^8=2^20=1048576 个目录
keys_zone=proxycache:20m # 指内存中缓存的大小,主要用于存放 key 和 metadata
(如:使用次数)
# 一般 1M 可存放 8000 个左右的 key
inactive=120s # 缓存有效时间
max_size=10g; # 最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值
# 调用缓存功能,需要定义在相应的配置段,如 server{...}; 或者 location 等
proxy_cache proxycache;
proxy_cache_key $request_uri; # 对指定的数据进行 MD5 的运算做为缓存的 key
proxy_cache_valid 200 302 301 10m; # 指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m; # 除指定的状态码返回的数据以外的缓存多长时间 , 必须设置 ,
否则不会缓存
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 |
http_502 | http_503 | http_504 | http_403 | http_404 | off ; # 默认是 off
# 在被代理的后端服务器出现哪种情况下,可直接使用过期的缓存响应客户端
# 示例
proxy_cache_use_stale error http_502 http_503;
proxy_cache_methods GET | HEAD | POST ...;
# 对哪些客户端请求方法对应的响应进行缓存, GET 和 HEAD 方法总是被缓存
2.1.1.4.1 非缓存场景压测
# 准备后端 httpd 服务器
[root@apache20 static]# pwd
/var/www/html/static
[root@apache20 static]# cat /var/log/messages > ./log.html # 准备测试页面
[root@apache30 ~]# ab -n1000 -c100 http://www.timinglee.org/static/index.html
Concurrency Level: 100
Time taken for tests: 23.238 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 2011251000 bytes
HTML transferred: 2010991000 bytes
Requests per second: 43.03 [#/sec] (mean)
Time per request: 2323.789 [ms] (mean)
Time per request: 23.238 [ms] (mean, across all concurrent requests)
Transfer rate: 84521.97 [Kbytes/sec] received
2.1.1.4.2 准备缓存配置
[root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf
#gzip on;
proxy_cache_path /apps/nginx/proxy_cache levels=1:2:2 keys_zone=proxycache:20m
inactive=120s max_size=1g; # 配置在 nginx.conf http 配置段
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
location ~ /static { # 要缓存的 URL 或者放在 server 配置项对所有 URL 都进行缓存
proxy_pass http://172.25.254.20:8080;
proxy_cache proxycache;
proxy_cache_key $request_uri;
proxy_cache_valid 200 302 301 10m;
proxy_cache_valid any 1m; # 必须指定哪些响应码的缓存
}
#/data/nginx/proxycache/ 目录会自动生成
[root@Nginx ~]# ll /apps/nginx/proxy_cache/ -d
drwx------ 3 nginx root 4096 8 月 20 20:07 /apps/nginx/proxy_cache/
[root@Nginx ~]# tree /apps/nginx/proxy_cache/
/data/nginx/proxycache/
0 directories, 0 files
2.1.1.4.3 访问并验证缓存文件
# 访问 web 并验证缓存目录
[root@nginx ~]# ab -n1000 -c100 http://www.timinglee.org/static/index.html
[root@nginx ~]# ab -n 2000 -c200 http://www.magedu.org/static/log.html
Concurrency Level: 100
Time taken for tests: 10.535 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 2011251000 bytes
HTML transferred: 2010991000 bytes
Requests per second: 94.92 [#/sec] (mean)
Time per request: 1053.507 [ms] (mean)
Time per request: 10.535 [ms] (mean, across all concurrent requests)
Transfer rate: 186435.60 [Kbytes/sec] received
# 验证缓存目录结构及文件大小
[root@Nginx ~]# tree /apps/nginx/proxy_cache/
/apps/nginx/proxy_cache/
└── e
        └── 50
                └── 99
                        └── 319432ef3663735a9d3cb4e0c1d9950e
3 directories, 0 files

2.1.2 http 反向代理负载均衡

在上一个节中 Nginx 可以将客户端的请求转发至单台后端服务器但是无法转发至特定的一组的服务器,而且不能对后端服务器提供相应的服务器状态监测,Nginx 可以基于 ngx_http_upstream_module 模块提 供服务器分组转发、权重分配、状态监测、调度算法等高级功能
官方文档: https://nginx.org/en/docs/http/ngx_http_upstream_module.html
2.1.2.1 http upstream配置参数
# 自定义一组服务器,配置在 http 块内
upstream name {
server .....
......
}
# 示例
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, 实现类似于 LVS 中的 WRR,WLC 等
max_conns=number # 给当前后端 server 设置最大活动链接数,默认为 0 表示没有限制
max_fails=number # 后端服务器的下线条件 , 当客户端访问时 , 对本次调度选中的后端服务器连续进行检
测多少次 , 如果都失败就标记为不可用 , 默认为 1 次 , 当客户端访问时 , 才会利用 TCP 触发对探测后端服务器健康性
检查 , 而非周期性的探测
fail_timeout=time # 后端服务器的上线条件 , 对已经检测到处于不可用的后端服务器 , 每隔此时间间隔再
次进行检测是否恢复可用,如果发现可用 , 则将后端服务器参与调度 , 默认为 10 秒
backup # 设置为备份服务器,当所有后端服务器不可用时 , 才会启用此备用服务器
down # 标记为 down 状态 , 可以平滑下线后端服务器
resolve # 当 server 定义的是主机名的时候,当 A 记录发生变化会自动应用新 IP 而不用重启
Nginx
hash KEY [consistent];
# 基于指定请求报文中首部字段或者 URI 等 key 做 hash 计算,使用 consistent 参数,将使用 ketama 一致性
hash 算法,适用于后端是 Cache 服务器(如 varnish )时使用, consistent 定义使用一致性 hash 运算,一致
性 hash 基于取模运算
hash $request_uri consistent; # 基于用户请求的 uri 做 hash
hash $cookie_sessionid # 基于 cookie 中的 sessionid 这个 key 进行 hash 调度 , 实现会话绑
定
ip_hash;
# 源地址 hash 调度方法,基于的客户端的 remote_addr( 源地址 IPv4 的前 24 位或整个 IPv6 地址 ) 做 hash 计算,以实现会话保持
least_conn;
# 最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器 , 相当于 LVS 中的 WLC
2.1.2.2 反向代理示例: 后端多台 web服务器
环境说明:
192.168.10.10 #Nginx 代理服务器
192.168.10.20 #后端 web A , Apache 部署
192.168.10.30 #后端 web B , Apache 部署
部署后端 Apache 服务器
[root@apache20 ~]# yum install httpd -y
[root@apache20 ~]# echo "web1 192.168.10.20" > /var/www/html/index.html
[root@apache20 ~]# systemctl enable --now httpd
[root@apache30 ~]# yum install httpd -y
[root@apache30 ~]# echo "web2 192.168.10.30" >> /var/www/html/index.html
[root@apache30 ~]# systemctl enable --now httpd
# 访问测试
[root@centos8 ~]# curl http://192.168.10.20
web1 192.168.10.20
[root@centos8 ~]# curl http://192.168.10.30
web2 192.168.10.30
配置 nginx 反向代理
注意 : 本节实验过程中先关闭缓存
[root@nginx ~]# cat /usr/local/nginx/conf/conf.d/pc.conf
upstream webserver {        
        #ip_hash;
        #hash $request_uri consistent;
        #hash $cookie_lee
        #least_conn;
        server 192.168.10.20:8080 weight=1 fail_timeout=15s max_fails=3;
        server 192.168.10.30:80 weight=1 fail_timeout=15s max_fails=3;
        server 192.168.10.10:80 backup;
}
server {
        listen 80;
        server_name www.timinglee.org;
        location ~ / {
                proxy_pass http://webserver;
        }
}
# 重启 Nginx 并访问测试
[root@nginx ~]# curl www.timinglee.org
web1 192.168.10.20
[root@nginx ~]# curl www.timinglee.org
web2 192.168.10.30
#关闭192.168.10.20和192.168.10.30,测试 nginx backup 服务器可用性:
[root@nginx ~]# while true; do curl http://www.timinglee.org; sleep 1; done
实战案例 : 基于 Cookie 实现会话绑定
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
http {
        upstream websrvs {
                hash $cookie_hello; #hello是cookie 的 key 的名称
                server 10.0.0.101:80 weight=2;
                server 10.0.0.102:80 weight-1;
        }
}
[root@nginx ~]# vim /usr/local/nginx/conf/conf.d/pc.conf
upstream webserver {
        #ip_hash;
        #hash $request_uri consistent;
        hash $cookie_lee;
        #least_conn;
        server 192.168.10.20:8080 weight=1 fail_timeout=15s max_fails=3;
        server 192.168.10.30:80 weight=1 fail_timeout=15s max_fails=3;
        #server 192.168.10.10:80 backup;
}
server {
        listen 80;
        server_name www.timinglee.org;
        location ~ / {
        proxy_pass http://webserver;
        }
}
# 测试
[root@nginx ~]# curl -b lee=1 www.timinglee.org

2.2 实现 Nginx 四层负载均衡

Nginx 在 1.9.0 版本开始支持 tcp 模式的负载均衡,在 1.9.13 版本开始支持 udp 协议的负载, udp 主要用于DNS的域名解析,其配置方式和指令和 http 代理类似,其基于 ngx_stream_proxy_module 模块实现 tcp负载,另外基于模块ngx_stream_upstream_module 实现后端服务器分组转发、权重分配、状态监测、调度算法等高级功能。
如果编译安装 , 需要指定 --with-stream 选项才能支持 ngx_stream_proxy_module 模块
官方文档:
https://nginx.org/en/docs/stream/ngx_stream_proxy_module.htm

2.2.1 tcp负载均衡配置参数

stream { # 定义 stream 相关的服务;
Context:main
upstream backend { # 定义后端服务器
hash $remote_addr consistent; # 定义调度算法
server backend1.example.com:12345 weight=5; # 定义具体 server
server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
upstream dns { # 定义后端服务器
server 10.0.0.1:53; # 定义具体 server
server dns.example.com:53;
}
server { # 定义 server
listen 12345; # 监听 IP:PORT
proxy_connect_timeout 1s; # 连接超时时间
proxy_timeout 3s; # 转发超时时间
proxy_pass backend; # 转发到具体服务器组
}
server {
listen 127.0.0.1:53 udp reuseport;
proxy_timeout 20s;
proxy_pass dns;
}
server {
listen [::1]:12345;
proxy_pass unix:/tmp/stream.socket;
}
}

2.2.2 负载均衡实例: MySQL

后端服务器安装 MySQL

# 在 apache20 中安装 mysql
[root@apache20 ~]# yum install mariadb-server -y
[root@apache20 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=20
[root@apache20 ~]# systemctl start mariadb
[root@apache20 ~]# mysql -e "grant all on *.* to lee@'%' identified by 'lee';"
[root@apache30 ~]# mysql -ulee -plee -h192.168.10.20 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
| 20 |
+-------------+
# 在 apache30 重复以上步骤并在 apache20 上测试
nginx 配置
[root@Nginx ~]# vim /apps/nginx/conf/tcp/tcp.conf
stream {
upstream mysql_server {
server 192.168.10.20:3306 max_fails=3 fail_timeout=30s;
server 192.168.10.30:3306 max_fails=3 fail_timeout=30s;
}
server {
listen192.168.10.10:3306;
proxy_pass mysql_server;
proxy_connect_timeout 30s;
proxy_timeout 300s;
}
}
# 重启 nginx 并访问测试:
[root@Nginx ~]# nginx -s reload
# 测试通过 nginx 负载连接 MySQL :
[root@apache30 ~]# mysql -ulee -plee -h192.168.10.10 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
| 20 |
+-------------+
[root@apache30 ~]# mysql -ulee -plee -h192.168.10.10 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
| 30 |
+-------------+
# 在 10.0.0.28 停止 MySQL 服务
[root@apache20 ~]# systemctl stop mariadb
# 再次测试访问 , 只会看到 mysql-server1.timinglee.org 进行响应
[root@apache30 ~]# mysql -ulee -plee -h192.168.10.10 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
| 30 |
+-------------+
[root@apache30 ~]# mysql -ulee -plee -h192.168.10.10 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
| 30 |
+-------------+

2.2.3 udp 负载均衡实例: DNS

stream {
upstream dns_server{
server 192.168.10.20:53 max_fails=3 fail_timeout=30s;
server 192.168.10.30:53 max_fails=3 fail_timeout=30s;
}
server {
listen 192.168.10.10:53 udp;
proxy_pass dns_server;
proxy_timeout 1s;
proxy_responses 1; # 使用 UDP 协议时,设置代理服务器响应客户端期望的数据报文数
# 该值作为会话的终止条件
error_log logs/dns.log;
   }
}
测试:
[root@apache30 named]# dig www.timinglee.org @192.168.10.10
; <<>> DiG 9.16.23 <<>> www.timinglee.org @192.168.10.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33888
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 701447f1bdd8acea0100000066a27b465426b2b4bc7f1dc3 (good)
;; QUESTION SECTION:
;www.timinglee.org. IN A
;; ANSWER SECTION:
www.timinglee.org. 86400 IN A 192.168.10.20
;; Query time: 2 msec
;; SERVER: 192.168.10.10#53(192.168.10.10)
;; WHEN: Fri Jul 26 00:20:22 CST 2024
;; MSG SIZE rcvd: 90
[root@apache30 named]# dig www.timinglee.org @192.168.10.10
; <<>> DiG 9.16.23 <<>> www.timinglee.org @192.168.10.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8932
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 8ecb61bbfe2716df0100000066a27b47a3bb0c3d8e537858 (good)
;; QUESTION SECTION:
;www.timinglee.org. IN A
;; ANSWER SECTION:
www.timinglee.org. 86400 IN A 172.25.254.30
;; Query time: 1 msec
;; SERVER: 172.25.254.10#53(172.25.254.10)
;; WHEN: Fri Jul 26 00:20:23 CST 2024
;; MSG SIZE rcvd: 90

2.3 实现 FastCGI

CGI 的由来:
最早的 Web 服务器只能简单地响应浏览器发来的 HTTP 请求,并将存储在服务器上的 HTML 文件返回给浏
览器,也就是静态 html 文件,但是后期随着网站功能增多网站开发也越来越复杂,以至于出现动态技
术,比如像 php(1995 年 ) 、 java(1995) 、 python(1991) 语言开发的网站,但是 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代码的处理。

2.3.1 FastCGI配置指令

Nginx 基于模块 ngx_http_fastcgi_module 实现通过 fastcgi 协议将指定的客户端请求转发至 php-fpm 处理,其配置指令如下:
fastcgi_pass address:port;
# 转发请求到后端服务器, address 为后端的 fastcgi server 的地址,可用位置: location, if in
location
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 /scripts;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # 默认脚本路径
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; # 此文件默认系统已提供 , 存放的相对路径为
prefix/conf
}

2.3.2 FastCGI实战案例 : Nginx与php-fpm在同一服务器

编译安装更方便自定义参数或选项,所以推荐大家使用源码编译
官方网站: www.php.net
源码编译 php
# 利用 yum 解决 php 依赖
[root@Nginx ~]# yum install -y bzip2 systemd-devel libxml2-devel sqlite-devel
libpng-devel libcurl-devel oniguruma-devel
# 解压源码并安装
[root@Nginx ~]# ./configure \
--prefix=/usr/local/php \ # 安装路径
--with-config-file-path=/usr/local/php/etc \ # 指定配置路径
--enable-fpm \ # 用 cgi 方式启动程序
--with-fpm-user=nginx \ # 指定运行用户身份
--with-fpm-group=nginx \
--with-curl \ # 打开 curl 浏览器支持
--with-iconv \ # 启用 iconv 函数,转换字符编码
--with-mhash \ #mhash 加密方式扩展库
--with-zlib \ # 支持 zlib 库,用于压缩 http 压缩传输
--with-openssl \ # 支持 ssl 加密
--enable-mysqlnd \ #mysql 数据库
--with-mysqli \ --with-pdo-mysql \
--disable-debug \ # 关闭 debug 功能
--enable-sockets \ # 支持套接字访问
--enable-soap \ # 支持 soap 扩展协议
--enable-xml \ # 支持 xml
--enable-ftp \ # 支持 ftp
--enable-gd \ # 支持 gd 库
--enable-exif \ # 支持图片元数据
--enable-mbstring \ # 支持多字节字符串
--enable-bcmath \ # 打开图片大小调整 , 用到 zabbix 监控的时候用到了这个模块
--with-fpm-systemd # 支持 systemctl 管理 cgi
php 相关配置优化
[root@Nginx etc]# cp php-fpm.conf.default php-fpm.conf
[root@Nginx etc]# vim php-fpm.conf
去掉注释
pid = run/php-fpm.pid # 指定 pid 文件存放位置
[root@Nginx etc]# cd php-fpm.d/
[root@Nginx php-fpm.d]# cp www.conf.default www.conf
# 生成主配置文件
[root@Nginx php-fpm.d]# cd /root/php-8.3.9/
[root@Nginx php-8.3.9]# cp php.ini-production /usr/local/php/etc/php.ini
[root@Nginx ~]# vim /usr/local/php/etc/php.ini
[Date]
; Defines the default timezone used by the date functions
; https://php.net/date.timezone
date.timezone = Asia/Shanghai # 修改时区
# 生成启动文件
[root@Nginx ~]# cd /root/php-8.3.9/
[root@Nginx php-8.3.9]# cp sapi/fpm/php-fpm.service /lib/systemd/system/
# Mounts the /usr, /boot, and /etc directories read-only for processes invoked by
this unit.
#ProtectSystem=full # 注释该内容
[root@Nginx php-8.3.9]# systemctl start php-fpm.service
[root@Nginx php-8.3.9]# netstat -antlupe | grep php
tcp 0 0 192.0.0.1:9000 0.0.0.0:* LISTEN 0
820758 176202/php-fpm: mas
准备 php 测试页面
[root@Nginx ~]# mkdir /data/php -p
[root@centos8 ~]# cat /data/php/index.php #php 测试页面
<?php
phpinfo();
?>
Nginx 配置转发
Nginx 安装完成之后默认生成了与 fastcgi 的相关配置文件,一般保存在 nginx 的安装路径的 conf 目录当中,比如/apps/nginx/conf/fastcgi.conf 、 /apps/nginx/conf/fastcgi_params 。
[root@Nginx ~]# vim /apps/nginx/conf.d/php.conf
server {
listen 80;
server_name php.timinglee.org;
root /data/php;
location ~ \.php$ {
fastcgi_pass 192.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
# 重启 Nginx 并访问 web 测试
[root@Nginx ~]# nginx -s reload
访问验证 php 测试页面

添加 php 环境变量
[root@Nginx ~]# vim .bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin:/apps/nginx/sbin:/usr/local/php/bin
export PATH
[root@Nginx ~]# source .bash_profile

2.3.3 php的动态扩展模块(php的缓存模块)

软件下载: http://pecl.php.net/package/memcache

安装 memcache 模块
[root@Nginx ~]# tar zxf memcache-8.2.tgz
[root@Nginx ~]# cd memcache-8.2/
[root@Nginx memcache-8.2]# yum install autoconf
[root@Nginx memcache-8.2]# phpize
[root@Nginx memcache-8.2]# ./configure && make && make install
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non
zts-20230831/
[root@Nginx memcache-8.2]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts-
20230831/
memcache.so opcache.so
复制测试文件到 nginx 发布目录中
[root@Nginx ~]# cd memcache-8.2/
[root@Nginx memcache-8.2]# ls
autom4te.cache config.log configure.ac example.php Makefile.fragments
README
build config.m4 config.w32 include Makefile.objects run
tests.php
config9.m4 config.nice CREDITS libtool memcache.la src
config.h config.status docker LICENSE memcache.php
tests
config.h.in configure Dockerfile Makefile modules
[root@Nginx memcache-8.2]# cp example.php memcache.php /data/php/
[root@Nginx ~]# vim /data/php/memcache.php
define('ADMIN_USERNAME','admin'); // Admin Username
define('ADMIN_PASSWORD','lee'); // Admin Password
define('DATE_FORMAT','Y/m/d H:i:s');
define('GRAPH_SIZE',200);
define('MAX_ITEM_DUMP',50);
$MEMCACHE_SERVERS[] = 'localhost:11211'; // add more as an array
#$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array
配置 php 加载 memcache 模块
[root@Nginx ~]# vim /usr/local/php/etc/php.ini
;extension=zip
extension=memcache
;zend_extension=opcache
[root@Nginx ~]# systemctl reload php-fpm
[root@Nginx no-debug-non-zts-20230831]# php -m | grep mem
memcache
部署 memcached
[root@Nginx ~]# yum install memcached -y
[root@Nginx ~]# systemctl enable --now memcached.service
[root@Nginx ~]# netstat -antlupe | grep memcache
tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN
976 1037243 186762/memcached
[root@Nginx ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 127.0.0.1,::1"
测试:
访问 http://php.timinglee.org/example.php 不断刷新
访问 http://php.timinglee.org/memcache.php 查看命中效果

性能对比
[root@apache20 ~]# ab -n500 -c10 http://php.timinglee.org/index.php
Concurrency Level: 10
Time taken for tests: 0.514 seconds
Complete requests: 500
Failed requests: 44
(Connect: 0, Receive: 0, Length: 44, Exceptions: 0)
[root@apache20 ~]# ab -n500 -c10 http://php.timinglee.org/example.php
Concurrency Level: 10
Time taken for tests: 0.452 seconds
Complete requests: 500
Failed requests: 0

2.3.4 php高速缓存

部署方法
在我们安装的 nginx 中默认不支持 memc 和 srcache 功能,需要借助第三方模块来让 nginx 支持此功能,所以nginx 需要重新编译
[root@Nginx ~]# rm -fr /apps/nginx/
[root@Nginx ~]# tar zxf srcache-nginx-module-0.33.tar.gz
[root@Nginx ~]# tar zxf memc-nginx-module-0.20.tar.gz
[root@Nginx ~]# cd nginx-1.26.1/
[root@Nginx nginx-1.26.1]# ./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-stream --with-stream_ssl_module --with-stream_realip_module --
add-module=/root/memc-nginx-module-0.20 --add-module=/root/srcache-nginx-module-
0.33
[root@Nginx nginx-1.26.1]# make && make install
[root@Nginx ~]# vim /apps/nginx/conf.d/php.conf
upstream memcache {
server 127.0.0.1:11211;
keepalive 512;
}
server {
listen 80;
server_name php.timinglee.org;
root /data/php;
location /memc {
internal;
memc_connect_timeout 100ms;
memc_send_timeout 100ms;
memc_read_timeout 100ms;
set $memc_key $query_string; # 使用内置变量 $query_string 来作为 key
set $memc_exptime 300; # 缓存失效时间 300 秒
memc_pass memcache;
}
location ~ \.php$ {
set $key $uri$args; # 设定 key 的值
srcache_fetch GET /memc $key; # 检测 mem 中是否有要访问的 php
srcache_store PUT /memc $key; # 缓存为加载的 php 数据
fastcgi_pass 192.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
[root@Nginx ~]# systemctl start nginx.service
测试结果:
[root@apache20 ~]# ab -n500 -c10 http://php.timinglee.org/index.php
Concurrency Level: 10
Time taken for tests: 0.255 seconds
Complete requests: 500
Failed requests: 0
三、 nginx 二次开发版本

3.1 openresty

Nginx 是俄罗斯人发明的, Lua 是巴西几个教授发明的,中国人章亦春把 LuaJIT VM 嵌入到 Nginx 中,
实现了 OpenResty 这个高性能服务端解决方案
OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方
模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、 Web 服
务和动态网关。
OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx
有效地变成一个强大的通用 Web 应用平台。这样, Web 开发人员和系统工程师可以使用 Lua 脚本语言
调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高
性能 Web 应用系统。
OpenResty 由于有功能强大且方便的的 API, 可扩展性更强 , 如果需要实现定制功能 ,OpenResty 是个不错的选择
官网 : http://openresty.org/cn/
3.2 编译安装 openresty
[root@Nginx ~]#dnf -y install gcc pcre-devel openssl-devel perl
[root@Nginx ~]#useradd -r -s /sbin/nologin nginx
[root@Nginx ~]#cd /usr/local/src
[root@Nginx src]#wget https://openresty.org/download/openresty-1.17.8.2.tar.gz
[root@Nginx src]#tar xf openresty-1.17.8.2.tar.gz
[root@Nginx src]#cd openresty-1.17.8.2/
[root@Nginx openresty-1.17.8.2]#./configure \
--prefix=/apps/openresty \
--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-stream \
--with-stream_ssl_module \
--with-stream_realip_module
[root@Nginx openresty-1.17.8.2]#make && make install
[root@Nginx openresty-1.17.8.2]#ln -s /apps/openresty/bin/* /usr/bin/
[root@Nginx openresty-1.17.8.2]#openresty -v
nginx version: openresty/1.17.8.2
[root@Nginx openresty-1.17.8.2]#openresty
[root@Nginx openresty-1.17.8.2]#ps -ef |grep nginx
[root@Nginx ~]#curl 10.0.0.18

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/diannao/52067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【卡码网C++基础课 1.A+B问题1】

文章目录 题目描述与分析一、C函数基础二、输入输出流三、变量四、写入数据五、输出数据六、尝试第一次提交七、循环输入输出八、延伸 题目描述与分析 题目描述&#xff1a; 你的任务是计算ab。 输入描述&#xff1a; 输入包含一系列的a和b对&#xff0c;通过空格隔开。一对a…

【UE5】基于摄像机距离逐渐剔除角色

效果 步骤 1. 新建一个工程&#xff0c;在内容浏览器中添加第三人称游戏内容包 2. 找到第三人称角色的材质实例“MI_Quinn_01”并打开 找到材质实例的父项材质“M_Mannequin” 打开材质“M_Mannequin” 在材质图表中添加如下节点 此时运行效果如文章开头所示。 参考视频&#…

【vue教程】七. Vue 的动画和过渡

文章目录 往期列表回顾本章涵盖知识点Vue 的内置动画系统基本的进入和离开过渡列表过渡 CSS 过渡CSS 过渡基础Vue 中的 CSS 过渡 JavaScript 动画使用 JavaScript 钩子 第三方动画库的使用集成 Animate.css 实例演示创建一个简单的动画应用 结语 往期列表 【vue教程】一. 环境…

RabbitMQ如何保证消息不丢失

RabbitMQ消息丢失的三种情况 第一种&#xff1a;生产者弄丢了数据。生产者将数据发送到 RabbitMQ 的时候&#xff0c;可能数据就在半路给搞丢了&#xff0c;因为网络问题啥的&#xff0c;都有可能。 第二种&#xff1a;RabbitMQ 弄丢了数据。MQ还没有持久化自己挂了。 第三种…

《深入浅出WPF》读书笔记.4名称空间详解

《深入浅出WPF》读书笔记.4名称空间详解 背景 主要讲明名称空间概念&#xff0c;可以理解为命名空间的引用。 xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml" &#x1f446;如x可以理解为一些列命名空间的引用。 不一一列举&#xff0c;只讲几个特殊的…

Java基础——注释

在开发中注释是必不可少的&#xff0c;帮助我们更好的标记阅读代码&#xff0c;下面介绍几种常用的注释方式。 一、注释种类 1. 单行注释 使用//一行代码来进行注释&#xff0c;只能注释一行内容 2. 多行注释 使用斜杠星号的方式 /*注释多行代码*/&#xff0c;注释多行代…

2024最新急速暴走小米运动自动刷步卡密版PHP源码

2023最新发布的急速暴走小米运动自动刷步卡密版PHP源码。该源码使用PHPTP6layui-Mini开发&#xff0c;旨在实现小米运动自动刷步功能。该程序支持通过微信修改步数&#xff0c;并采用卡密认证方式&#xff0c;用户只需提交提供的卡密&#xff0c;即可每日自助修改步数。 需要注…

UDP网络攻击

UDP&#xff08;User Datagram Protocol&#xff09;作为一种无连接的网络传输协议&#xff0c;以其速度快和资源消耗小的特点&#xff0c;在多种网络服务中发挥着重要作用&#xff0c;UDP的无连接特性也使其成为DDoS攻击的优选协议。 UDP攻击概念 UDP攻击是一种网络攻击手段…

USB HiFi 声卡

USB HiFi声卡就像是你电脑上的一对超级耳朵&#xff0c;它能将你从普通音质中拯救出来&#xff0c;带你进入一个音乐细节丰富的世界。无论你是音乐迷、游戏玩家还是电影发烧友&#xff0c;这些声卡都是你的音频升级好帮手。设计师在设计USB HiFi声卡的过程&#xff0c;就像是调…

Linux虚拟机磁盘管理-添加磁盘

添加磁盘--添加前请选关闭虚拟机 添加步骤&#xff1a; 1.编辑虚拟机设置 2.选择硬盘 3.选择SCSI 4.创建新虚拟磁盘 5.设置磁盘大小 6.点击完成 开机的时候会去读取有几块硬盘&#xff0c;总共我们是有4块硬盘&#xff0c;sda\sdb\sdc\sdd 注意&#xff1a;新加的硬盘实际我们…

华为OD机试(C卷,100分)- 游戏分组

题目描述 部门准备举办一场王者荣耀表演赛,有 10 名游戏爱好者参与,分为两队,每队 5 人。 每位参与者都有一个评分,代表着他的游戏水平。为了表演赛尽可能精彩,我们需要把 10 名参赛者分为示例尽量相近的两队。 一队的实力可以表示为这一队 5 名队员的评分总和。 现在给你…

鸿萌数据恢复服务:SQL Server 中的“PFS 可用空间信息不正确”错误

天津鸿萌科贸发展有限公司从事数据安全服务二十余年&#xff0c;致力于为各领域客户提供专业的数据恢复、数据备份、网络及终端数据安全等解决方案与服务。 同时&#xff0c;鸿萌是国际主流数据恢复软件(Stellar、UFS、R-Studio、ReclaiMe Pro 等)的授权代理商&#xff0c;为专…

爬虫案例3——爬取彩票双色球数据

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正 任务&#xff1a;从500彩票网中爬取双色球数据 目标网页地址&#xff1a;https://datachart.500.com/ssq/ 一、思路和过程 目标网页具体内容如下&#xff1a; ​​​​​ 我们的任务是将上图中…

使用AWS Lambda轻松开启Amazon Rekognition之旅

这是本系列文章的第一篇&#xff0c;旨在通过动手实践&#xff0c;帮助大家学习亚马逊云科技的生成式AI相关技能。通过这些文章&#xff0c;大家将掌握如何利用亚马逊云科技的各类服务来应用AI技术。 那么让我们开始今天的内容吧&#xff01; 介绍 什么是Amazon Rekognition&…

前端宝典之五:React源码解析之深度剖析Diff算法

本文主要针对React源码进行解析&#xff0c;内容有&#xff1a; 1、Diff算法原理、两次遍历 2、Diff瓶颈及限制 3、Diff更新之单节点和多节点原理 一、Diff源码解析 以下是关于 React Diff 算法的详细解析及实例&#xff1a; 1、React Diff 算法的基本概念和重要性 1.1 概念…

【LeetCode每日一题】——301.删除无效的括号

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 广度优先搜索 二【题目难度】 困难 三【题目编号】 301.删除无效的括号 四【题目描述】 给…

ROS 2中,CMakeList.txt常见语法

在ROS 2中&#xff0c;CMakeList.txt 文件扮演着配置和管理构建过程的重要角色。这个文件遵循CMake的语法&#xff0c;用于定义如何编译和链接源代码。下面是一些在ROS 2项目CMakeList.txt文件中常见的语法和用法。 1. 基本结构和命令 cmake_minimum_required(VERSION )&…

【设计模式】装饰器模式和适配模式

装饰器模式 装饰器模式能够很好的对已有功能进行拓展&#xff0c;这样不会更改原有的代码&#xff0c;对其他的业务产生影响&#xff0c;这方便我们在较少的改动下对软件功能进行拓展。 类似于 router 的前置守卫和后置守卫。 Function.prototype.before function (beforeFn)…

【C++】————智能指针

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年8月20日 一&#xff0c;什么是智能指针 在C中没有垃圾回收机制&#xff0c;必须自己释放分配的内存&#xff0c;否则就会造成内存泄露。解决这个问题最有效的方法是使用智能指针&…

异常信息转储预研笔记-堆栈地址转换

addr2line命令 addr2line -e <exec> <addr> -f | xargs cfilt<exec>: 进程名 <addr>&#xff1a;堆栈地址eg&#xff1a; addr2line -e backtrace 0x4009d2 -f | xargs cfilt此方案测试了&#xff0c;不知道什么原因只显示?? ??:0 &#xff0c;而…