nginx

目录

nginx简介

nginx的特性与优点

nginx的特性

nginx的优点

nginx的功能及应用类别

nginx的基本功能

nginx的扩展功能

nginx的应用类别

nginx的模块与工作原理

nginx的模块分类

nginx的安装与配置

nginx的安装

nginx安装后配置

nginx的配置文件详解

访问控制

基于用户认证

https配置

开启状态界面

监控

nginx 平滑升级以及增加功能

location

rewrite

rewrite跳转场景

Rewrite的定义

rewrite 命令语法

if

常见的condition

基于浏览器实现分离案例

 防盗链案例

nginx负载均衡配置、nginx负载均衡调度器高可用配置

102安装httpd

103安装nginx

100安装nginx

 101安装nginx

​编辑 100和101安装keepalived做高可用

查看VIP

模拟


nginx简介

nginx(发音同engine x)是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like协议下发行。

nginx由俄罗斯的程序设计师Igor Sysoev所开发,最初供俄国大型的入口网站及搜寻引擎Rambler使用。

第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。2011年6月1日,nginx 1.0.4发布。

nginx的特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

nginx的特性与优点

nginx的特性

nginx是一个很牛的高性能Web和反向代理服务器,它具有很多非常优越的特性:

  • 在高连接并发的情况下,nginx是Apache服务器不错的替代品,能够支持高达50000个并发连接数的响应
  • 使用epoll and kqueue作为开发模型
  • nginx作为负载均衡服务器:nginx既可在内部直接支持和PHP程序对外进行服务,也可支持作为HTTP代理服务器对外进行服务
  • nginx采用C进行编写,不论系统资源开销还是CPU使用效率都比Perlbal要好很多

nginx的优点

  • 高并发连接:官方测试能够支撑5万并发连接,在实际生产环境中跑到2-3万并发连接数
  • 内存消耗少:在3万并发连接下,开启的10个nginx进程才消耗150M内存(15M*10=150M)
  • 配置文件非常简单:风格跟程序一样通俗易懂
  • 成本低廉:nginx为开源软件,可以免费使用。而购买F5 BIG-IP、NetScaler等硬件负载均衡交换机则需要十多万至几十万人民币
  • 支持Rewrite重写规则:能够根据域名、URL的不同,将HTTP请求分到不同的后端服务器群组
  • 内置的健康检查功能:如果Nginx Proxy后端的某台Web服务器宕机了,不会影响前端访问
  • 节省带宽:支持GZIP压缩,可以添加浏览器本地缓存的Header头
  • 稳定性高:用于反向代理,宕机的概率微乎其微
  • 模块化设计:模块可以动态编译
  • 外围支持好:文档全,二次开发和模块较多
  • 支持热部署:可以不停机重载配置文件
  • 支持事件驱动、AIO(AsyncIO,异步IO)、mmap(Memory Map,内存映射)等性能优化

nginx的功能及应用类别

nginx的基本功能

  • 静态资源的web服务器,能缓存打开的文件描述符
  • http、smtp、pop3协议的反向代理服务器
  • 缓存加速、负载均衡
  • 支持FastCGI(fpm,LNMP),uWSGI(Python)等
  • 模块化(非DSO机制),过滤器zip、SSI及图像的大小调整
  • 支持SSL

nginx的扩展功能

  • 基于名称和IP的虚拟主机
  • 支持keepalive
  • 支持平滑升级
  • 定制访问日志、支持使用日志缓冲区提高日志存储性能
  • 支持URL重写
  • 支持路径别名
  • 支持基于IP及用户的访问控制
  • 支持速率限制,支持并发数限制

nginx的应用类别

  • 使用nginx结合FastCGI运行PHP、JSP、Perl等程序
  • 使用nginx作反向代理、负载均衡、规则过滤
  • 使用nginx运行静态HTML网页、图片
  • nginx与其他新技术的结合应用

nginx的模块与工作原理

nginx由内核和模块组成。其中,内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端请求映射到一个location block(location是nginx配置中的一个指令,用于URL匹配),而在这个location中所配置的每个指令将会启动不同的模块去完成相应的工作。

nginx的模块分类

nginx的模块从结构上分为核心模块、基础模块和第三方模块

  • HTTP模块、EVENT模块和MAIL模块等属于核心模块
  • HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块属于基本模块
  • HTTP Upstream模块、Request Hash模块、Notice模块和HTTP Access Key模块属于第三方模块

用户根据自己的需要开发的模块都属于第三方模块。正是有了如此多模块的支撑,nginx的功能才会如此强大

nginx模块从功能上分为三类,分别是:

  • Handlers(处理器模块)。此类模块直接处理请求,并进行输出内容和修改headers信息等操作。handlers处理器模块一般只能有一个
  • Filters(过滤器模块)。此类模块主要对其他处理器模块输出的内容进行修改操作,最后由nginx输出
  • Proxies(代理器模块)。就是nginx的HTTP Upstream之类的模块,这些模块主要与后端一些服务比如fastcgi等操作交互,实现服务代理和负载均衡等功能

nginx模块分为:核心模块、事件模块、标准Http模块、可选Http模块、邮件模块、第三方模块和补丁等

  • nginx基本模块:所谓基本模块,指的是nginx默认的功能模块,它们提供的指令,允许你使用定义nginx基本功能的变量,在编译时不能被禁用,包括:
    • 核心模块:基本功能和指令,如进程管理和安全。常见的核心模块指令,大部分是放置在配置文件的顶部
    • 事件模块:在Nginx内配置网络使用的能力。常见的events(事件)模块指令,大部分是放置在配置文件的顶部
    • 配置模块:提供包含机制

具体的指令,请参考nginx官方文档

nginx的安装与配置

nginx的安装

//关闭防火墙和selinux子系统
[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# systemctl disable firewalld.service
[root@localhost ~]# sed -i s/SELINUX=enforcing/SELINUX=disabled/g /etc/selinux/config
[root@localhost ~]# setenforce 0

//创建系统用户nginx
[root@localhost ~]# useradd -r -M -s /sbin/nologin nginx

//安装依赖环境
[root@localhost ~]# yum -y install pcre-devel openssl openssl-devel gd-devel gcc gcc-c++   wget  make

[root@localhost ~]# yum -y groups mark install 'Development Tools'

//创建日志存放目录
[root@localhost ~]# mkdir -p /var/log/nginx
[root@localhost ~]# chown -R nginx.nginx /var/log/nginx

//下载nginx
//nginx 官网 https://nginx.org/en/download.html
[root@localhost ~]# cd /usr/local/src/
[root@localhost ~]# wget https://nginx.org/download/nginx-1.20.2.tar.gz

//编译安装
[root@localhost src]# ls
nginx-1.20.2.tar.gz
[root@localhost src]# tar -xf nginx-1.20.2.tar.gz 
[root@localhost src]# cd nginx-1.20.2/
[root@localhost nginx-1.20.2]# ./configure \
> --prefix=/usr/local/nginx \
> --user=nginx \
> --group=nginx \
> --with-debug \
> --with-http_ssl_module \
> --with-http_realip_module \
> --with-http_image_filter_module \
> --with-http_gunzip_module \
> --with-http_gzip_static_module \
> --with-http_stub_status_module \
> --http-log-path=/var/log/nginx/access.log \
> --error-log-path=/var/log/nginx/error.log

[root@localhost nginx-1.20.2]# make -j $(grep 'processor' /proc/cpuinfo | wc -l) && make install

nginx安装后配置

//配置环境变量
[root@localhost ~]# echo 'export PATH=/usr/local/nginx/sbin:$PATH' > /etc/profile.d/nginx.sh
[root@localhost ~]# . /etc/profile.d/nginx.sh

//服务控制方式,使用nginx命令
    -t  //检查配置文件语法
    -v  //输出nginx的版本
    -c  //指定配置文件的路径
    -s  //发送服务控制信号,可选值有{stop|quit|reopen|reload}
    

设置nginx 开机自启
[root@localhost ~]# cp /usr/lib/systemd/system/sshd.service  /usr/lib/systemd/system/nginx.service
[root@localhost ~]# vim /usr/lib/systemd/system/nginx.service 
[root@localhost ~]# cat /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx server daemon
After=network.target


[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecStop=/usr/local/nginx/sbin/nginx -s stop
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

[root@localhost ~]# systemctl daemon-reload 
[root@localhost ~]# systemctl enable --now nginx.service
[root@localhost ~]# ss -anlt
State          Recv-Q         Send-Q                   Local Address:Port                   Peer Address:Port         Process         
LISTEN         0              128                            0.0.0.0:80                          0.0.0.0:*                            
LISTEN         0              128                            0.0.0.0:22                          0.0.0.0:*                            
LISTEN         0              128                               [::]:22                             [::]:*  

nginx的配置文件详解

主配置文件:/usr/local/nginx/conf/nginx.conf

  • 默认启动nginx时,使用的配置文件是:安装路径/conf/nginx.conf文件
  • 可以在启动nginx时通过-c选项来指定要读取的配置文件

nginx常见的配置文件及其作用

配置文件作用
nginx.confnginx的基本配置文件
mime.typesMIME类型关联的扩展文件
fastcgi.conf与fastcgi相关的配置
proxy.conf与proxy相关的配置
sites.conf配置nginx提供的网站,包括虚拟主机

访问控制

用于location段
allow:设定允许哪台或哪些主机访问,多个参数间用空格隔开
deny:设定禁止哪台或哪些主机访问,多个参数间用空格隔开
示例:

allow 192.168.1.1/32 172.16.0.0/16;
deny all;
[root@nginx ~]#vim /usr/local/nginx/conf/nginx.conf
........
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }   
      location / {
           echo "A";
           deny 192.168.91.129;    //不允许这台主机访问
          }                          
      
........ 
[root@nginx ~]# systemctl restart nginx.service
[root@nginx ~]# curl http://192.168.91.129  //192这台主机访问就被拒绝访问了
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.22.0</center>
</body>
</html>

[root@localhost ~]# curl http://192.168.91.129     //使用另外一台就能成功访问
A                                


[root@nginx ~]#vim /usr/local/nginx/conf/nginx.conf
........
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }
        location / {
           echo "A";
         allow 192.168.91.129;   //允许这个IP访问
         deny all;                  //不允许所有人访问
        }
.......
[root@nginx ~]# systemctl restart nginx.service
[root@nginx ~]# curl http://192.168.91.129
A                                        //192这台主机可以访问

[root@localhost ~]# curl http://192.168.91.129    //其余的就被拒绝访问
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.22.0</center>
</body>
</html>

基于用户认证

nginx认证模块
ngx_http_auth_basic_module 模块实现让访问者,只有输入正确的用户密码才允许访问web内容。web上的一些内容不想被其他人知道,但是又想让部分人看到。nginx的http auth模块以及Apache http auth都是很好的解决方案。

默认情况下nginx已经安装了ngx_http_auth_basic_module模块,如果不需要这个模块,可以加上 --without-http_auth_basic_module

nginx官网的介绍

配置中的file,需要包括密码,密码必须先加密

创建加密文件

//安装htpasswd这个命令
[root@nginx ~]# dnf provides *bin/htpasswd
Last metadata expiration check: 1:55:18 ago on Thu 13 Oct 2022 12:29:54 PM CST.
httpd-tools-2.4.37-41.module_el8.5.0+977+5653bbea.x86_64 : Tools for use with the Apache HTTP Server
Repo        : AppStream
Matched from:
Other       : *bin/htpasswd

httpd-tools-2.4.37-43.module_el8.5.0+1022+b541f3b1.x86_64 : Tools for use with the Apache HTTP Server
Repo        : @System
Matched from:
Other       : *bin/htpasswd

[root@nginx ~]# yum -y install httpd-tools     //htpasswd这个命令是由httpd-tools这个工具包

//安装在/usr/local/nginx/conf/.htpasswd下设置成隐藏文件,设置一个用户名(这个用户不是主机上的,是访问认证时需要输入的用户名)
[root@nginx ~]# htpasswd -c -m /usr/local/nginx/conf/.htpasswd  du
New password: 
Re-type new password: 
Adding password for user du
[root@nginx ~]# ls -a /usr/local/nginx/conf/       //已经生成了.htpasswd这个文件
.             fastcgi.conf.default    .htpasswd  mime.types          nginx.conf.default   uwsgi_params
..            fastcgi_params          koi-utf    mime.types.default  scgi_params          uwsgi_params.default
fastcgi.conf  fastcgi_params.default  koi-win    nginx.conf
[root@nginx ~]# cat /usr/local/nginx/conf/.htpasswd 
du:$apr1$OAeR1Qld$QZB5.VU6I2G.aUjXaqzHB1        //用户名是du密码已经加密了

[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
..... 
  server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }
        
          location / {
          auth_basic  "aabb";                
          auth_basic_user_file .htpasswd;    //.htpasswd和nginx.conf在同一个目录下所以直接写名字
          echo "A";
        }
....

 

https配置

生成私钥,生成证书签署请求并获得证书,然后在nginx.conf中配置如下内容:

server {
  listen       443 ssl;
  server_name  www.idfsoft.com;
  ssl_certificate      /etc/nginx/ssl/nginx.crt;
  ssl_certificate_key  /etc/nginx/ssl/nginx.key;
  ssl_session_cache    shared:SSL:1m;
  ssl_session_timeout  5m;
  ssl_ciphers  HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers  on;
  location / {
    root   html;
    index  index.html index.htm;
  }
}

openssl实现私有CA**:
CA的配置文件:/etc/pki/tls/openssl.cnf
CA生成一对密钥

[root@nginx ~]# mkdir /etc/pki/CA
[root@nginx ~]# cd /etc/pki/CA 
[root@nginx CA]# mkdir private
[root@nginx CA]# (umask 077;openssl genrsa -out private/cakey.pem 2048)
Generating RSA private key, 2048 bit long modulus (2 primes)
................................+++++
..+++++
e is 65537 (0x010001)
[root@nginx CA]# openssl rsa -in private/cakey.pem -pubout

CA生成自签署证书

[root@nginx CA]# openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 365
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) []:HB
Locality Name (eg, city) [Default City]:WH
Organization Name (eg, company) [Default Company Ltd]:www.1314.com  //公司名称
Organizational Unit Name (eg, section) []:www.1314.com             //组织的名称
Common Name (eg, your name or your server's hostname) []:www.1314.com //域名
Email Address []:2279236475@qq.com                                  //邮箱

[root@nginx CA]# openssl x509 -text -in cacert.pem    //读出cacert.pem证书的内容
[root@nginx CA]# mkdir certs newcerts crl
[root@nginx CA]# touch index.txt && echo 01 > serial

在nginx配置文件下生成密钥

[root@nginx ~]# cd /usr/local/nginx/conf/
[root@nginx conf]# mkdir ssl
[root@nginx conf]# cd ssl/
[root@nginx ssl]# (umask 077;openssl genrsa -out nginx.key 2048)
Generating RSA private key, 2048 bit long modulus (2 primes)
…+++++
…+++++
e is 65537 (0x010001)
[root@nginx ssl]# ls
nginx.key

生成证书签署请求

[root@nginx ssl]# openssl req -new -key nginx.key -days 365 -out nginx.csr
Ignoring -days; not generating a certificate
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) []:HB
Locality Name (eg, city) [Default City]:WH
Organization Name (eg, company) [Default Company Ltd]:www.1314.com
Organizational Unit Name (eg, section) []:www.1314.com
Common Name (eg, your name or your server's hostname) []:www.1314.com
Email Address []:2279236475@qq.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@nginx ssl]# ls
nginx.csr  nginx.key

CA签署证书

[root@nginx ssl]# openssl ca -in nginx.csr -out nginx.crt -days 365
.....
Certificate is to be certified until Oct 13 07:16:42 2023 GMT (365 days)
Sign the certificate? [y/n]:y               //要不要签名 
1 out of 1 certificate requests certified, commit? [y/n]y   //要不要提交
Write out database with 1 new entries
[root@nginx ssl]# ls
nginx.crt  nginx.csr  nginx.key        //保留crt和key就行了
[root@nginx ssl]# rm -rf  nginx.csr   //这个就不需要了

配置nginx.conf配置文件

[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
    server {
        listen       443 ssl;
        server_name  localhost;

        ssl_certificate      ssl/nginx.crt;    //写证书的位置(ssl和conf在同级目录下)
        ssl_certificate_key  ssl/nginx.key;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        location / {
            root   html;
            index  index.html index.htm;
        }
     }
[root@nginx ~]# systemctl restart nginx.service 
[root@nginx ~]# ss -anlt
State          Recv-Q         Send-Q                   Local Address:Port                   Peer Address:Port         Process         
LISTEN         0              128                            0.0.0.0:22                          0.0.0.0:*                            
LISTEN         0              128                            0.0.0.0:443                         0.0.0.0:*                            
LISTEN         0              128                            0.0.0.0:111                         0.0.0.0:*                            
LISTEN         0              128                            0.0.0.0:80                          0.0.0.0:*                            
LISTEN         0              128                               [::]:22                             [::]:*                            
LISTEN         0              128                               [::]:111                            [::]:* 

验证测试

开启状态界面

开启status:

location /status {
  stub_status {on | off};
  allow 172.16.0.0/16;
  deny all;
}

状态页面信息详解:

状态码表示的意义
Active connections 2当前所有处于打开状态的连接数
accepts总共处理了多少个连接
handled成功创建多少握手
requests总共处理了多少个请求
Readingnginx读取到客户端的Header信息数,表示正处于接收请求状态的连接数
Writingnginx返回给客户端的Header信息数,表示请求已经接收完成, 且正处于处理请求或发送响应的过程中的连接数
Waiting开启keep-alive的情况下,这个值等于active - (reading + writing), 意思就是Nginx已处理完正在等候下一次请求指令的驻留连接

开启状态页面

在安装nginx的时候需要 --with-http_stub_status_module这个模块才能开启状态页面

 server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }


         location = /status {           //开启状态页面
             stub_status;
          }

验证

Active connections: 3         
server accepts handled requests
 3 3 1                       //前两个跟打开浏览器访问有关,后面一个和请求有关
Reading: 0 Writing: 1 Waiting: 2 

Active  connections:当前所有处于打开状态的活动连接数

accepts :已经接收连接数

handled : 已经处理过的连接数

requests : 已经处理过的请求数,在保持连接模式下,请求数量可能会大于连接数量

Reading: 正处于接收请求的连接数

Writing: 请求已经接收完成,处于响应过程的连接数

Waiting : 保持连接模式,处于活动状态的连接数

 使用zabbix监控nginx端的状态页,使用脚本监控的是Waiting和Reading的值

[root@nginx ~]# mkdir /scripts
[root@nginx ~]# cd /scripts/
[root@nginx scripts]# vim check_status.sh
[root@nginx scripts]# cat check_status.sh 
#!/bin/bash
  
IP=$(ip a|grep 'inet ' |grep -v '127.0.0.1'|awk -F'[ /]+' '{print $3}')  # 获取本机IP

# 取到对应的三个值
case $1 in
    "Reading")
    curl -s http://$IP/status |awk 'NF==6 {print $2}';;
    "Writing")
    curl -s http://$IP/status |awk 'NF==6 {print $4}';;
    "Waiting")
    curl -s http://$IP/status  |awk 'NF==6 {print $6}';;
esac

安装 zabbix_agtend端
修改nginx端的 zabbix_agtend.conf 配置文件

[root@nginx ~]# useradd  -r -M -s /sbin/nologin zabbix
[root@nginx ~]# dnf -y install gcc gcc-c++ vim make pcre-devel openssl openssl-devel
[root@nginx ~]# cd /usr/src/
[root@nginx src]# wget https://cdn.zabbix.com/zabbix/sources/stable/6.2/zabbix-6.2.2.tar.gz
[root@nginx src]# cd zabbix-6.2.2/
[root@nginx zabbix-6.2.2]#  ./configure --enable-agent
[root@nginx zabbix-6.2.2]# make install
[root@nginx zabbix-6.2.2]# vim /usr/local/etc/zabbix_agentd.conf
.....
109 # Mandatory: yes, if StartAgents is not explicitly set to 0
110 # Default:
111 # Server=
113 Server=192.168.91.134  服务端IP (被动模式)
.....
163 # Mandatory: no
164 # Default:
165 # ServerActive=
167 ServerActive=192.168.91.134  服务端IP(主动模式)
......
178 Hostname=aa     (网页里面看到的名称不是主机名,可以随便写但是网页上的名字要和这个一样)

......
UnsafeUserParameters=1   # 取消注释,把默认的0改成1
### Option: UserParameter
#       User-defined parameter to monitor. There can be several user-defined parameters.
#       Format: UserParameter=<key>,<shell command>
#       See 'zabbix_agentd' directory for examples.
#
# Mandatory: no
# Default:
UserParameter=check_nginx_status[*],/bin/bash /scripts/check_status.sh $1
            //(此key必须与web界面创建监控项时输入的key一致) 

[root@nginx zabbix-6.2.2]# zabbix_agentd
[root@nginx zabbix-6.2.2]# ss -anlt
State          Recv-Q         Send-Q                  Local Address:Port                    Peer Address:Port         Process         
LISTEN         0              128                           0.0.0.0:22                           0.0.0.0:*                            
LISTEN         0              128                           0.0.0.0:443                          0.0.0.0:*                            
LISTEN         0              128                           0.0.0.0:10050                        0.0.0.0:*                            
LISTEN         0              128                           0.0.0.0:111                          0.0.0.0:*                            
LISTEN         0              128                           0.0.0.0:80                           0.0.0.0:*                            
LISTEN         0              128                              [::]:22                              [::]:*                            
LISTEN         0              128                              [::]:111                             [::]:* 

监控

创建主机组

创建主机并把主机加入到主机组

 

创建自定义监控 Reading 值

 

创建触发器Reading 值

 

创建自定义监控 Writing 值

 

创建触发器 Writing 值

 

创建自定义监控 Waiting 值

 

创建触发器 Waiting 值

 

 查看仪表盘

nginx 平滑升级以及增加功能

升级告示:把nginx升级到1.22.0,并增加nginx模块echo功能

//模块可以去这里下载[Gitee - 基于 Git 的代码托管和研发协作平台](https://gitee.com/)

平滑升级过程

获取老版本的编译信息
获取新版本安装包或功能包
配置新版本或功能,配置时加上老版本的编译信息和新版本或功能(--add-module)
编译,编译完后不能执行安装操作
备份老版本程序
停掉老版本程序的进程
将新版本程序复制到老版本所在位置替换掉老版本
启动新版本程序

最后四步可以用一条命令,这样升级客户不会察觉
[root@nginx ~]# cd nginx-1.22.0/
[root@nginx nginx-1.22.0]# cp /usr/local/nginx/sbin/nginx{,-bak};pkill nginx;\cp  objs/nginx /usr/local/nginx/sbin/nginx;systemctl start nginx
//克隆下来需要git命令
[root@nginx ~]# yum -y install git
[root@nginx ~]# git clone https://gitee.com/drgxq/nginx_module_echo.git
[root@nginx ~]# ls
anaconda-ks.cfg  Desktop    Downloads      Music      nginx_module_echo

//下载nginx1.22.0版本(nginx-1.22.0要和echo功能模块在同一级目录)
[root@nginx ~]# wget https://nginx.org/download/nginx-1.22.0.tar.gz
[root@nginx ~]# ls
anaconda-ks.cfg  Desktop    Downloads   nginx_module_echo      nginx-1.22.0.tar.gz

//解压nginx 
[root@nginx ~]# tar -xf nginx-1.22.0.tar.gz 
[root@nginx ~]# ls
anaconda-ks.cfg  Desktop    Downloads     Music         nginx-1.22.0.tar.gz          nginx-1.22.0  nginx_module_echo

//查看nginx的版本以及安装了哪些功能
[root@nginx ~]# nginx -V
nginx version: nginx/1.20.2
built by gcc 8.5.0 20210514 (Red Hat 8.5.0-10) (GCC) 
built with OpenSSL 1.1.1k  FIPS 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-debug --with-http_ssl_module --with-http_realip_module --with-http_image_filter_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log

//添加新的功能,预编译以及编译之后(不能 不能make install安装)
[root@nginx nginx-1.22.0]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-debug --with-http_ssl_module --with-http_realip_module --with-http_image_filter_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module  --add-module=../nginx_module_echo

//备份老的nginx程序文件,以及干掉nginx进程,把新版本的nginx程序文件复制过去替换
[root@nginx ~]# mv /usr/local/nginx/sbin/nginx{,-bak}
[root@nginx ~]# cp nginx-1.22.0/objs/nginx /usr/local/nginx/sbin/
[root@nginx ~]# nginx -V             //版本已经升级到1.22.0,并且安装了echo功能模块
nginx version: nginx/1.22.0
built by gcc 8.5.0 20210514 (Red Hat 8.5.0-10) (GCC) 
built with OpenSSL 1.1.1k  FIPS 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-debug --with-http_ssl_module --with-http_realip_module --with-http_image_filter_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_stub_status_module --add-module=../nginx_module_echo
[root@nginx ~]# systemctl restart nginx.service 
[root@nginx ~]# ss -anlt
State          Recv-Q         Send-Q                   Local Address:Port                   Peer Address:Port         Process         
LISTEN         0              128                            0.0.0.0:111                         0.0.0.0:*                            
LISTEN         0              128                            0.0.0.0:80                          0.0.0.0:*                            
LISTEN         0              128                            0.0.0.0:22                          0.0.0.0:*                            
LISTEN         0              128                               [::]:111                            [::]:*                            
LISTEN         0              128                               [::]:22                             [::]:* 

location

在nginx中location分为两类:普通location和正则location。

普通 location ”是以“ = ”或“ ^~ ”为前缀或者没有任何前缀的 /uri/,包括“/”;“正则 location ”是以“ ~ ”或“ ~* ”为前缀的 /uri/ 。

那么如果一个 server 块中编写了多个 location 的时候,Nginx对于客户端请求匹配顺序如何呢?

官网说明如下:先匹配普通location,取的最大前缀匹配,再匹配正则location,如果匹配到则按照正则匹配,如果有多个正则可以匹配到,则按照第一个匹配结果处理,如果正则匹配失败则使用普通location的最大前缀匹配。Nginx也设置了几种机制可以打断这种顺序,分别是“^~ ”、“= ”或者location精确匹配。

简单的讲顺序如下:

首先普通location“=”精确匹配;

然后普通location的URL精确匹配;

然后普通location”^~"配置;

然后正则匹配;

然后其他普通location匹配;

最后“/”通用匹配

location 匹配的优先级(与location在配置文件中的顺序无关)
= 精确匹配会第一个被处理。如果发现精确匹配,nginx停止搜索其他匹配。
普通字符匹配,正则表达式规则和长的块规则将被优先和查询匹配,也就是说如果该项匹配还需去看有没有正则表达式匹配和更长的匹配。

^~ 则只匹配该规则,nginx停止搜索其他匹配,否则nginx会继续处理其他location指令。
最后匹配理带有"“和”*"的指令,如果找到相应的匹配,则nginx停止搜索其他匹配;当没有正则表达式或者没有正则表达式被匹配的情况下,那么匹配程度最高的逐字匹配指令会被使用。

常用修饰符说明

修饰符功能
=精确匹配
~正则表达式模式匹配,区分大小写
~*正则表达式模式匹配,不区分大小写
^~前缀匹配,类似于无修饰符的行为,也是以指定模块开始,不同的是,如果模式匹配,那么就停止搜索其他模式了,不支持正则表达式
@定义命名location区段,这些区段客户端不能访问,只可以由内部产生的请求来访问,如try_files或error_page等

正则表达式按照他们在配置文件中定义的顺序带有=的精确匹配优先查找顺序和优先级:由高到底依次为

带有^~修饰符的,开头匹配
带有~或~*修饰符的,如果正则表达式与URI匹配
没有修饰符的精确匹配
优先级次序如下:

( location = 路径 ) --> ( location ^~ 路径 ) --> ( location ~ 正则 ) --> ( location ~* 正则 ) --> ( location 路径 )

rewrite

rewrite跳转场景

1、URL看起来更规范、合理
2、企业会将动态URL地址伪装成静态地址提供服务
3、网址换新域名后,让旧的访问跳转到新的域名上
4、服务端某些业务调整

Rewrite的定义

1、rewrite功能就是使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。
2、rewrite只能放在 server { }, location { }, if { }中,并且只能对域名后边的除去传递的参数外的字符串起作用。

rewrite 命令语法

语法:rewrite <正则表达式> <跳转后的内容> [rewrite支持的flag标记]
 

rewrite ^/images/(.*\.jpg)$ /imgs/$1 break;

此处的$1用于引用(.*.jpg)匹配到的内容

rewrite ^/bbs/(.*)$ http://www.idfsoft.com/index.html redirect;

此处访问ip后面加上/abc 就访问到的是百度

[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
//此处访问  192.168.91.129/abc   就会访问到百度
location /abc {
        rewrite ^/abc/(.*)$  /aa/$1 last;
        }
//到此处变成  192.168.91.129/aa/xxxx
      location /aa {
          rewrite ^/aa/(.*)$  /ww/$1 last;
        }
//此处变成  192.168.91.129/ww/xxxx
      location /ww {
         rewrite ^/ww/(.*)$  http://www.baidu.com break ;
       }

常见的flag

flag作用
last基本上都用这个flag,表示当前的匹配结束,继续下一个匹配,最多匹配10个到20个 一旦此rewrite规则重写完成后,就不再被后面其它的rewrite规则进行处理 而是由UserAgent重新对重写后的URL再一次发起请求,并从头开始执行类似的过程
break中止Rewrite,不再继续匹配 一旦此rewrite规则重写完成后,由UserAgent对新的URL重新发起请求, 且不再会被当前location内的任何rewrite规则所检查
redirect以临时重定向的HTTP状态302返回新的URL
permanent以永久重定向的HTTP状态301返回新的URL

rewrite模块的作用是用来执行URL重定向。这个机制有利于去掉恶意访问的url,也有利于搜索引擎优化(SEO)

rewrite与location比较
1、相同点
都能实现跳转
2、不同点
rewrite是在同一域名内更改获取资源的路径
location是对一类路径做控制访问或反向代理,还可以proxy_pass到其他机器
3、rewrite会写在location里,执行顺序
执行server块里面的rewrite指令
执行location匹配
执行选定的location中的rewrite指令

nginx使用的语法源于Perl兼容正则表达式(PCRE)库,基本语法如下:

标识符意义
^必须以^后的实体开头
$必须以$前的实体结尾
.匹配任意字符
[]匹配指定字符集内的任意字符
[^]匹配任何不包括在指定字符集内的任意字符串
|匹配 | 之前或之后的实体
()分组,组成一组用于匹配的实体,通常会有 | 来协助

if

语法:if (condition) {...}

应用场景:

  • server段
  • location段

常见的condition

  • 变量名(变量值为空串,或者以“0”开始,则为false,其它的均为true)
  • 以变量为操作数构成的比较表达式(可使用=,!=类似的比较操作符进行测试)
  • 正则表达式的模式匹配操作
    • ~:区分大小写的模式匹配检查
    • ~*:不区分大小写的模式匹配检查
    • !和!*:对上面两种测试取反
  • 测试指定路径为文件的可能性(-f,!-f)
  • 测试指定路径为目录的可能性(-d,!-d)
  • 测试文件的存在性(-e,!-e)
  • 检查文件是否有执行权限(-x,!-x)

基于浏览器实现分离案例

if ($http_user_agent ~ Firefox) {
  rewrite ^(.*)$ /firefox/$1 break;
}

if ($http_user_agent ~ MSIE) {
  rewrite ^(.*)$ /msie/$1 break;
}

if ($http_user_agent ~ Chrome) {
  rewrite ^(.*)$ /chrome/$1 break;
}

 防盗链案例

location ~* \.(jpg|gif|jpeg|png)$ {
  valid_referers none blocked www.idfsoft.com;
  if ($invalid_referer) {
    rewrite ^/ http://www.idfsoft.com/403.html;
  }
}

valid_referers(有效连接)如果访问是通过网站主页点进来查看 .(jpg|gif|jpeg|png),我们就认为时有效连接就允许访问
invalid_referer(无效连接)直接通过网站输入整个的URL,不是通过网站的主页点击进去的我们就认为时无效连接,(rewrite)重新规则使无效连接访问到403.html

nginx负载均衡配置、nginx负载均衡调度器高可用配置

环境说明

系统信息主机名IP
CentOS8100 (nginx,keepalived)192.168.153.100
CentOS8101 (nginx,keepalived)192.168.153.101
CentOS8102 (httpd)192.168.153.102
CentOS8103 (nginx)192.168.153.103

102安装httpd

//在102上源码安装httpd
创建apache服务的用户和组
[root@102 ~]# groupadd -r apache
[root@102 ~]# useradd -r -M -s /sbin/nologin -g apache apache 

安装依赖包
[root@102 ~]# yum -y install openssl-devel pcre-devel expat-devel libtool gcc gcc-c++


下载安装apr apr-util
[root@102 ~]# wget https://mirrors.tuna.tsinghua.edu.cn/apache/apr/apr-1.7.0.tar.bz2
[root@102 ~]# wget https://mirrors.tuna.tsinghua.edu.cn/apache/apr/apr-util-1.6.1.tar.bz2

解压下载的源码包
[root@102 ~]#tar -jxf apr-1.7.0.tar.bz2 -C /usr/local/src/
[root@102 ~]#tar -jxf apr-util-1.6.1.tar.bz2 -C /usr/local/src/
   

安装apr
[root@102 ~]# cd /usr/local/src/apr-1.7.0/
[root@102 apr-1.7.0]# ./configure --prefix=/usr/local/apr
[root@102 apr-1.7.0]# make && make install


安装apr-util
[root@102 ~]# cd /usr/local/src/
[root@102 apr-util-1.6.1]# ./configure --prefix=/usr/local/apr-util  --with-apr=/usr/local/apr
[root@102 apr-util-1.6.1]#make && make install

安装httpd
[root@102 ~]#wgt https://downloads.apache.org/httpd/httpd-2.4.54.tar.bz2
[root@102 ~]# tar -jxf httpd-2.4.54.tar.bz2 -C /usr/local/src/
[root@102 ~]#cd /usr/local/src/httpd-2.4.54 
[root@102 httpd-2.4.54]# ./configure --prefix=/usr/local/apache \
--sysconfdir=/etc/apache \
--enable-so \
--enable-ssl \
--enable-cgi \
--enable-rewrite \
--with-zlib \
--with-pcre \
--with-apr=/usr/local/apr \
--with-apr-util=/usr/local/apr-util/ \
--enable-modules=most \
--enable-mpms-shared=all \
--with-mpm=prefork
[root@102 httpd-2.4.54]#make && make install

安装后配置
[root@102 ~]# echo 'export PATH=/usr/local/apache/bin:$PATH' > /etc/profile.d/httpd.sh
[root@102 ~]# source /etc/profile.d/httpd.sh
[root@102 ~]# ln -s /usr/local/apache/include/ /usr/include/httpd
[root@102 ~]# echo 'MANDATORY_MANPATH /usr/local/apache/man' >> /etc/man_db.conf

取消ServerName前面的注释
[root@102 ~]# sed -i '/#ServerName/s/#//g' /etc/apache/httpd.conf

设置源码安装apache能使用systemctl 开启、关闭、重启、开机自启
[root@102 ~]# cd /usr/lib/systemd/system
[root@102 system]# cp sshd.service apache.service复制sshd.service,改名为httpd.service
[root@102 system]#vim apache.service             进入apache.service进行修改,保存退出
[root@102 system]#cat apache.service             显示修改后的文件内容
[Unit]
Description=httpd server daemon
After=network.target sshd-keygen.target

[Service]
Type=forking
ExecStart=/usr/local/apache/bin/apachectl
ExecStop=/usr/local/apache/bin/apachectl  stop
ExecReload=/bin/kill -HUP $MAINPID

[root@102 ~]#systemctl start httpd.service         开启apache服务
[root@102 ~]# ss -anlt
State      Recv-Q     Send-Q          Local Address:Port           Peer Address:Port     Process     
LISTEN     0          128                   0.0.0.0:22                  0.0.0.0:*                    
LISTEN     0          128                         *:80                        *:*                    
LISTEN     0          128                      [::]:22                     [::]:* 

103安装nginx

//在103上源码部署nginx
//创建系统用户nginx
[root@103 ~]# useradd -r -M -s /sbin/nologin nginx

//安装依赖环境
[root@103 ~]# yum -y install pcre-devel openssl openssl-devel gd-devel gcc gcc-c++   wget  make

[root@103 ~]# yum -y groups mark install 'Development Tools'

//创建日志存放目录
[root@103 ~]# mkdir -p /var/log/nginx
[root@103 ~]# chown -R nginx.nginx /var/log/nginx

//下载nginx
//nginx 官网 https://nginx.org/en/download.html
[root@103 ~]# cd /usr/local/src/
[root@103 ~]# wget https://nginx.org/download/nginx-1.20.2.tar.gz

//编译安装
[root@103 src]# ls
nginx-1.20.2.tar.gz
[root@103 src]# tar -xf nginx-1.20.2.tar.gz 
[root@103 src]# cd nginx-1.20.2/
[root@103 nginx-1.20.2]# ./configure \
 --prefix=/usr/local/nginx \
 --user=nginx \
 --group=nginx \
 --with-debug \
 --with-http_ssl_module \
 --with-http_realip_module \
 --with-http_image_filter_module \
 --with-http_gunzip_module \
 --with-http_gzip_static_module \
 --with-http_stub_status_module \
 --http-log-path=/var/log/nginx/access.log \
 --error-log-path=/var/log/nginx/error.log

[root@103 nginx-1.20.2]# make -j $(grep 'processor' /proc/cpuinfo | wc -l) && make install

//配置环境变量
[root@103 ~]# echo 'export PATH=/usr/local/nginx/sbin:$PATH' > /etc/profile.d/nginx.sh
[root@103 ~]# . /etc/profile.d/nginx.sh

设置nginx 开机自启
[root@103 ~]# cp /usr/lib/systemd/system/sshd.service  /usr/lib/systemd/system/nginx.service
[root@103 ~]# vim /usr/lib/systemd/system/nginx.service 
[root@103 ~]# cat /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx server daemon
After=network.target


[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecStop=/usr/local/nginx/sbin/nginx -s stop
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

[root@103 ~]# systemctl daemon-reload 
[root@103 ~]# systemctl enable --now nginx.service
[root@103 ~]# ss -anlt
State      Recv-Q     Send-Q          Local Address:Port           Peer Address:Port     Process     
LISTEN     0          128                   0.0.0.0:80                  0.0.0.0:*                    
LISTEN     0          128                   0.0.0.0:22                  0.0.0.0:*                    
LISTEN     0          128                      [::]:22                     [::]:*   

100安装nginx

//在100上安装nginx
//源码安装nginx就行,这台只是做一个代理转发
[root@100 ~]# yum -y install nginx
[root@100 ~]# vim /etc/nginx/nginx.conf
.......
upstream webservers {
             server 192.168.153.102 weight=2;
             server 192.168.153.103;
      }
    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        proxy_pass http://webservers;      //做转发,转发到上面的upstream
        }

[root@100 ~]# systemctl enable --now  nginx.service

 101安装nginx

//在101上也安装nginx
//源码安装nginx就行,这台只是做一个代理转发
[root@101 ~]# yum -y install nginx

//应为100和101上的nginx配置是一样的都是做转发,直接把100上的nginx.conf复制去替换
[root@100 ~]# scp -r /etc/nginx/nginx.conf root@192.168.153.101:/etc/nginx/
[root@101 ~]# systemctl enable --now nginx.service

 100和101安装keepalived做高可用

 100为主

[root@100 ~]# yum -y install keepalived

//配置主keepalived
[root@100 ~]# cd /etc/keepalived/
[root@100 keepalived]# mv keepalived.conf keepalived.conf.bak
[root@100 keepalived]# vi keepalived.conf
[root@100 keepalived]# cat keepalived.conf

! Configuration File for keepalived

global_defs {
 router_id lb01
}

vrrp_instance VI_1 {
  state MASTER
  interface ens160
  virtual_router_id 51
  priority 100
  advert_int 1
  authentication {
      auth_type PASS
      auth_pass 123456
  }
  virtual_ipaddress {
      192.168.153.250
  }
}

virtual_server 192.168.153.250 80 {
  delay_loop 6
  lb_algo rr
  lb_kind DR
  persistence_timeout 50
  protocol TCP

  real_server 192.168.153.102 80 {
      weight 1
      TCP_CHECK {
          connect_port 80
          connect_timeout 3
          nb_get_retry 3
          delay_before_retry 3
      }
  }

  real_server 192.168.153.103 80 {
      weight 1
      TCP_CHECK {
          connect_port 80
          connect_timeout 3
          nb_get_retry 3
          delay_before_retry 3
      }
  }
}
[root@100 ~]# systemctl enable --now keepalived.service

101为备

[root@101 ~]# yum -y install keepalived
[root@101 keepalived]# scp keepalived.conf root@192.168.91.134:/etc/keepalived/
[root@101 ~]# vim /etc/keepalived/keepalived.conf 
[root@101 ~]# cat /etc/keepalived/keepalived.conf 

! Configuration File for keepalived

global_defs {
 router_id lb02
}

vrrp_instance VI_1 {
  state BACKUP
  interface ens160
  virtual_router_id 51
  priority 90
  advert_int 1
  authentication {
      auth_type PASS
      auth_pass 123456
  }
  virtual_ipaddress {
      192.168.153.250
  }
}

virtual_server 192.168.153.250 80 {
  delay_loop 6
  lb_algo rr
  lb_kind DR
  persistence_timeout 50
  protocol TCP

  real_server 192.168.153.102 80 {
      weight 1
      TCP_CHECK {
          connect_port 80
          connect_timeout 3
          nb_get_retry 3
          delay_before_retry 3
      }
  }

  real_server 192.168.153.103 80 {
      weight 1
      TCP_CHECK {
          connect_port 80
          connect_timeout 3
          nb_get_retry 3
          delay_before_retry 3
      }
  }
}
[root@101 ~]# systemctl enable --now keepalived.service

查看VIP

[root@100 keepalived]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:cc:2e:47 brd ff:ff:ff:ff:ff:ff
    inet 192.168.153.100/24 brd 192.168.153.255 scope global noprefixroute ens160
       valid_lft forever preferred_lft forever
    inet 192.168.153.250/32 scope global ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fecc:2e47/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever


[root@101 keepalived]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:54:9e:14 brd ff:ff:ff:ff:ff:ff
    inet 192.168.153.101/24 brd 192.168.153.255 scope global noprefixroute ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe54:9e14/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

 

模拟

当100的keepalived服务关闭后,101这台就有VIP了

[root@100 ~]# systemctl stop keepalived.service
[root@101 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:54:9e:14 brd ff:ff:ff:ff:ff:ff
    inet 192.168.153.101/24 brd 192.168.153.255 scope global noprefixroute ens160
       valid_lft forever preferred_lft forever
    inet 192.168.153.250/32 scope global ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe54:9e14/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
[root@101 ~]# systemctl restart nginx.service

 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值