软负载Nginx详细配置及使用案例

news2024/9/21 14:45:09

Nginx使用与配置

什么是nginx

Nginx 是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务。

  1. 处理响应请求很快
  2. 高并发连接
  3. 低的内存消耗
  4. 具有很高的可靠性
  5. 高扩展性
  6. 热部署

master 管理进程与 worker 工作进程的分离设计,使得 Nginx 具有热部署的功能,可以在 7 × 24 小时不间断服务的前提下,升级 Nginx 的可执行文件,也可以在不停止服务的情况下修改配置文件,更换日志文件等功能。

可大量并行处理

Nginx 在官方测试的结果中,能够支持五万个并行连接,而在实际的运作中,可以支持二万至四万个并行连接,作为对比Tomcat的并行连接数只有几百个。

与 Apache 相比

Nginx 的编写有一个明确目标就是超越 Apache Web 服务器的性能

Nginx 提供开箱即用的静态文件,使用的内存比 Apache 少得多,每秒可以处理大约四倍于 Apache 的请求,低并发下性能与 Apache 相当,有时候还低于,但是在高并发下 Nginx 能保持低资源低消耗高性能,还有高度模块化的设计,模块编写简单,简洁。

这种性能提升的代价是降低了灵活性,例如能够以每个文件为基础覆盖系统范围的访问设置( Apache 使用.htaccess 文件来完成这个工作,而 Nginx 并没有内置这样的功能),以前,向 Nginx 添加第三方模块需要使用静态链接的模块从源代码重新编译应用程序。在版本 1.9.11 中部分地克服了这一点,增加了动态模块加载。但是,模块仍然必须与 Nginx 同时编译,而不是所有的模块都与这个系统兼容——有些需要更老的静态链接过程。

常用web服务器对比
对比项\服务器ApacheNginxLighttpd
Proxy代理非常好非常好一般
Rewriter非常好一般
Fcgi不好非常好
热部署不支持支持不支持
系统压力很大很小比较小
稳定性非常好不好
安全性一般一般
静态文件处理一般非常好
反向代理一般非常好一般

Nginx 模块

整体采用模块化设计是 Nginx 的一个重大特点,甚至 http 服务器核心功能也是一个模块

旧版本的 Nginx 的模块是静态的,添加和删除模块都要对 Nginx 进行重新编译,1.9.11 以及更新的版本已经支持动态模块加载。

高度模块化的设计是 Nginx 的架构基础,Nginx 服务器被分解为多个模块,每个模块就是一个功能模块,只负责自身的功能,模块之间严格遵循“高内聚,低耦合”的原则。

'xxs'

核心模块

核心模块是 Nginx 服务器正常运行必不可少的模块,提供错误日志记录、配置文件解析、事件驱动机制、进程管理等核心功能。

标准 HTTP 模块

标准 HTTP 模块提供 HTTP 协议解析相关的功能,如:端口配置、网页编码设置、HTTP 响应头设置等。

可选 HTTP 模块

可选 HTTP 模块主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,如:Flash 多媒体传输、解析 GeoIP 请求、SSL 支持等。

邮件服务模块

邮件服务模块主要用于支持 Nginx 的邮件服务,包括对 POP3 协议、IMAP 协议和 SMTP 协议的支持。

第三方模块

第三方模块是为了扩展 Nginx 服务器应用,完成开发者自定义功能,如:Json 支持、Lua 支持等。

nginx应用场景

Nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器;同时也是一个IMAP、POP3、SMTP代理服务器;Nginx可以作为一个HTTP服务器进行网站的发布处理,另外Nginx可以作为反向代理进行负载均衡的实现。

关于代理

此时就涉及到两个角色,一个是被代理角色,一个是目标角色,被代理角色通过这个代理访问目标角色完成一些任务的过程称为代理操作过程;如同生活中的专卖店~客人到adidas专卖店买了一双鞋,这个专卖店就是代理,被代理角色就是adidas厂家,目标角色就是用户。

正向代理

说反向代理之前,先看看正向代理,正向代理是最常接触的到的代理模式,会从两个方面来说关于正向代理的处理模式。

简而言之, 梯子!

上述这样的代理模式称为正向代理,正向代理最大的特点是客户端非常明确要访问的服务器地址;服务器只清楚请求来自哪个代理服务器,而不清楚来自哪个具体的客户端;正向代理模式屏蔽或者隐藏了真实客户端信息

客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,还有代理程序的端口。如图。

'xxs'

总结来说:正向代理,“它代理的是客户端,代客户端发出请求”,是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端,客户端必须要进行一些特别的设置才能使用正向代理。

正向代理的用途:

  1. 访问原来无法访问的资源,如Google
  2. 可以做缓存,加速访问资源
  3. 对客户端访问授权,上网进行认证
  4. 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息
反向代理

继续看关于反向代理的处理方式,举例如我大天朝的某宝网站,每天同时连接到网站的访问人数已经爆表,单个服务器远远不能满足人民日益增长的购买欲望了,此时就出现了一个大家耳熟能详的名词:分布式部署;也就是通过部署多台服务器来解决访问人数限制的问题;某宝网站中大部分功能也是直接使用Nginx进行反向代理实现的,并且通过封装Nginx和其他的组件之后起了个高大上的名字:Tengine,官网。

'xxs'

上述的图解中,多个客户端给服务器发送的请求,Nginx服务器接收到之后,按照一定的规则分发给了后端的业务处理服务器进行处理了,此时~请求的来源也就是客户端是明确的,但是请求具体由哪台服务器处理的并不明确了,Nginx扮演的就是一个反向代理角色。

客户端是无感知代理的存在的,反向代理对外都是透明的,访问者并不知道自己访问的是一个代理,因为客户端不需要任何配置就可以访问。

反向代理,“它代理的是服务端,代服务端接收请求”,主要用于服务器集群分布式部署的情况下,反向代理隐藏了服务器的信息

反向代理的作用:

  1. 保证内网的安全,通常将反向代理作为公网访问地址,Web服务器是内网
  2. 负载均衡,通过反向代理服务器来优化网站的负载
项目场景

通常情况下,在实际项目操作时,正向代理和反向代理很有可能会存在在一个应用场景中,正向代理代理客户端的请求去访问目标服务器,目标服务器是一个反向单利服务器,反向代理了多台真实的业务处理服务器,具体的拓扑图如下:

'xxs'

二者区别

截了一张图来说明正向代理和反向代理二者之间的区别,如图。

'xxs'

  • 在正向代理中,Proxy和Client同属于一个LAN(图中方框内),隐藏了客户端信息;
  • 在反向代理中,Proxy和Server同属于一个LAN(图中方框内),隐藏了服务端信息;

实际上,Proxy在两种代理中做的事情都是替服务器代为收发请求和响应,不过从结构上看正好左右互换了一下,所以把后出现的那种代理方式称为反向代理了。

Nginx的安装

解编译安装nginx

在centos下有两种安装nginx方式,一种是yum install这种方式,还有一种是编译安装,第一种方式更简单,但是有一定的缺点,无法使用第三方模块。

安装编译环境

一般系统中已经装了了make和g++,无须再装

安装make
yum -y install autoconf automake make
安装g++
yum -y install gcc gcc-c++
安装nginx依赖的库
yum -y install wget pcre pcre-devel zlib zlib-devel openssl openssl-devel
下载nginx
wget http://nginx.org/download/nginx-1.23.0.tar.gz
解压nginx
tar -zxvf nginx-1.21.1.tar.gz
目录结构

解压以后进入到这个目录下面可以看到图中的目录

'xxs'

首先进入到auto目录

'xxs'

cc是用于编译的,对所有的操作系统的判断在os里面,其他所有文件都是为了辅助configure文件在执行的时候去判定支持哪些模块,当前的操作系统有哪些特性可以供nginx使用

然后在看图1中,conf是配置文件的示例文件,方便在安装完以后可以直接把conf里面的配置文件复制到安装目录下面,CHANGES这个文件里面描述了nginx的哪些特性,CHANGES.ru是一个俄罗斯版本的描述,因为nginx的作者是一个俄罗斯人,configure是一个用来生成中间文件进行编译前的一个必备动作

接下来通过 ./configure --help | more命令来查看一下

'xxs'

如果不需要指定安装其他模块的话,默认只需要执行–prefix就可以了

如果需要安装其他模块就需要在编译的时候执行–with 也就是说你需要安装的这个模块默认是没有安装进nginx的,如果不需要某些模块这个时候就需要执行–without,也就是说without后面跟着的模块默认是安装进nginx的。

编译安装
./configure  --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
make && make install

'xxs'

编译配置
  • –prefix指定安装目录
  • –with-http_ssl_module安装https模块
  • creating objs/Makefile 代表编译成功
  • make编译
  • make install安装
配置环境变量

编辑/etc/profile

vi /etc/profile

在最后一行加入

export PATH=$PATH:/usr/local/nginx/sbin

生效环境变量

source /etc/profile
关闭防火墙
systemctl status firewalld
systemctl stop firewalld
systemctl disable firewalld
配置Hosts

因为需要通过虚拟主机配置需要配置hosts文件

192.168.245.198 www.abc.com
192.168.245.198 www.abc.cn
192.168.245.198 www.bbs.com
192.168.245.198 www.resources.com
192.168.245.198 www.demo.com
192.168.245.198 www.yyy.com

可以用switchhosts进行修改: 跳转安装

yum方式

添加源

默认情况Centos7中无Nginx的源,最近发现Nginx官网提供了Centos的源地址,因此可以如下执行命令添加源

sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
安装Nginx

通过yum search nginx看看是否已经添加源成功。如果成功则执行下列命令安装Nginx。

sudo yum install -y nginx
启动Nginx
sudo systemctl start nginx.service
设置开机自动运行
sudo systemctl enable nginx.service

Nginx常用命令

启动

nginx
# 如果执行配置文件
nginx -c nginx.conf #如果不指定,默认为NGINX_HOME/conf/nginx.conf

停止

nginx -s stop

退出

nginx -s quit

关闭

# 查看nginx进程号
ps -aux | grep nginx

# 杀掉进程
kill -9 nginx

重新加载配置文件

nginx -s reload

检查配置文件是否正确

nginx -t -c /路径/nginx.conf

查看nginx的版本信息

nginx -v

配置文件结构

Nginx配置文件一般位于Nginx安装目录下的conf目录下,整个文件以block形式组合而成,每一个block都使用"{}"大括号来表示,block中可以嵌套其他block层级,其中main层是最高层次。

Nginx配置文件主要有4部分,main(全局设置)、server(主机设置)、upstream(上游服务器设置,主要为反向代理,负载均衡相关配置)和location(url匹配特定位置的设置),每部分包含若干指令。

  • Main部分的设置影响其他所有部分的设置;
  • Server部分主要用于指定虚拟机主机域名,ip和端口;
  • Upstream的指令用于设置一系列的后端服务器,设置反向代理及后端服务器的负载均衡;
  • Location部分用于匹配网页位置(如,跟目录“/”,”/images”等)。

它们之间的关系是,server继承main,location继承server,upstream既不会继承指令也不会被继承。

在这四个部分当中,每个部分都包含若干指令,这些指令主要包含Nginx的主模块指令、事件模块指令、HTTP核心模块指令,同时每个部分还可以使用其他HTTP模块指令,例如Http SSL模块、HttpGzip Static模块和Http Addition模块等。

'xxs'

真实的nginx配置文件可能如下

########### 每个指令必须有分号结束。#################
#user administrator administrators;  #配置用户或者组,默认为nobody nobody。
#worker_processes 2;  #允许生成的进程数,默认为1
#pid /nginx/pid/nginx.pid;   #指定nginx进程运行文件存放地址
error_log log/error.log debug;  #制定日志路径,级别。这个设置可以放入全局块,http块,server块,级别以此为:debug|info|notice|warn|error|crit|alert|emerg
events {
    accept_mutex on;   #设置网路连接序列化,防止惊群现象发生,默认为on
    multi_accept on;  #设置一个进程是否同时接受多个网络连接,默认为off
    #use epoll;      #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
    worker_connections  1024;    #最大连接数,默认为512
}
http {
    include       mime.types;   #文件扩展名与文件类型映射表
    default_type  application/octet-stream; #默认文件类型,默认为text/plain
    #access_log off; #取消服务日志    
    log_format myFormat '$remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #自定义格式
    access_log log/access.log myFormat;  #combined为日志格式的默认值
    sendfile on;   #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
    sendfile_max_chunk 100k;  #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
    keepalive_timeout 65;  #连接超时时间,默认为75s,可以在http,server,location块。

    upstream mysvr {   
      server 127.0.0.1:7878;
      server 192.168.10.121:3333 backup;  #热备
    }
    error_page 404 https://www.baidu.com; #错误页
    server {
        keepalive_requests 120; #单连接请求上限次数。
        listen       4545;   #监听端口
        server_name  127.0.0.1;   #监听地址       
        location  ~*^.+$ {       #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
           #root path;  #根目录
           #index vv.txt;  #设置默认页
           proxy_pass  http://mysvr;  #请求转向mysvr 定义的服务器列表
           deny 127.0.0.1;  #拒绝的ip
           allow 172.18.5.54; #允许的ip           
        } 
    }
}

配置文件位置

nginx配置为简化日常维护而设计,并且提供了简单的手段用于web服务器将来的扩展。

**配置文件是一些文本文件,通常位于nginx安装路径/etc/nginx/etc/nginx,主配置文件通常命名为nginx.conf,**为了保持整洁,部分配置可以放到单独的文件中,再自动地被包含到主配置文件,但应该注意的是,nginx目前不支持Apache风格的分布式配置文件(如.htaccess文件),所有和nginx行为相关的配置都应该位于一个集中的配置文件目录中。

Nginx的全局配置

user nobody nobody;
worker_processes 2;
error_log logs/error.log notice;
pid logs/nginx.pid;

events{
    use epoll;
    worker_connections 65536;
}
user

user是个主模块指令,指定Nginx Worker进程运行用户以及用户组,默认由nobody账号运行。

这个地方如果写错了就会出现获取不到用户的错误

'xxs'

worker_processes

是个主模块指令,指定了Nginx要开启的进程数,每个Nginx进程平均耗费10M~12M内存,建议指定和CPU的数量一致即可。

这个地方如果配置配置了worker_processes 2;那么他的工作进程就有两个

'xxs'

error_log

是个主模块指令,用来定义全局错误日志文件,日志输出级别有debug、info、notice、warn、error、crit可供选择,其中,debug输出日志最为最详细,而crit输出日志最少。

日志文件路径一般在nginx安装目录的logs目录中

'xxs'

pid

是个主模块指令,用来指定进程pid的存储文件位置。

进行成和nginx的master的进程号是一致的,只有nginx运行时才存在,如果nginx停止了 pid也会被删除掉

'xxs'

events事件指令

events事件指令是设定Nginx的工作模式及连接数上限:

use

use是个事件模块指令,用来指定Nginx的工作模式

Nginx支持的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll,其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用在Linux平台上,而kqueue用在BSD系统中,对于Linux系统,epoll工作模式是首选。

worker_connections

也是个事件模块指令,用于定义Nginx每个进程的最大连接数,默认是1024。

最大客户端连接数由worker_processes和worker_connections决定,即Max_client=worker_processes*worker_connections 在作为反向代理时,max_clients变为:max_clients = worker_processes * worker_connections/4。 进程的最大连接数受Linux系统进程的最大打开文件数限制,在执行操作系统命令“ulimit -n 65536”后worker_connections的设置才能生效

HTTP服务器配置

Nginx对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"';
    # 启动零拷贝提高性能
    sendfile        on;
    # 设置keepalive长连接超时时间
    keepalive_timeout  65;
    # 引入子配置文件
    include /usr/local/openresty/nginx/conf/conf.d/*.conf;
}

下面的代码实现对日志格式的设定:下面详细介绍下这段代码中每个配置选项的含义。

include

include是个主模块指令,实现对配置文件所包含的文件的设定,可以减少主配置文件的复杂度,可以将其他各个模块的具体配置分散在不同的文件夹中。

default_type

default_type属于HTTP核心模块指令,这里设定默认类型为二进制流,也就是当文件类型未定义时使用这种方式,例如在没有配置PHP环境时,Nginx是不予解析的,此时,用浏览器访问PHP文件就会出现下载窗口。

log_format

log_format是Nginx的HttpLog模块指令,用于指定Nginx日志的输出格式。main为此日志输出格式的名称,可以在下面的access_log指令中引用。

log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';

log_format download '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_range" "$sent_http_content_range"';

Nginx路由匹配

准备工作

初始化目录

先初始化以下测试目录

mkdir -p /root/www/nginx/{abc,bbs}/
创建Index文件

创建abc目录下得Index文件

vi /root/www/nginx/abc/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>abc</title>
  <head>
  <body>
      <H1>
          www.abc.com
      </H1>
  </body>
</html>

创建bbs目录下得Index文件

vi /root/www/nginx/bbs/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>bbs</title>
  <head>
  <body>
      <H1>
          www.bbs.com
      </H1>
  </body>
</html>
编译安装echo

又涉及到echo操作的地方需要安装echo模块,使用--add-module重新编译安装

./configure  --prefix=/usr/local/nginx --add-module=/usr/local/nginx/modules/echo-nginx-module-master

make && make install

虚拟主机

所谓虚拟主机,在 Web 服务里就是一个独立的网站站点,这个站点对应独立的域名(也可能是IP 或端口),具有独立的程序及资源,可以独立地对外提供服务供用户访问。

在 Nginx 中,使用一个 server{} 标签来标识一个虚拟主机,一个 Web 服务里可以有多个虚拟主机标签对,即可以同时支持多个虚拟主机站点。

虚拟主机有两种类型:基于域名的虚拟主机、基于IP+端口的虚拟主机。

完全匹配虚拟主机

在 conf.d文件夹下创建vhostserver.conf配置文件内容如下

server {
        listen       80;
        charset utf-8;
        server_name  www.abc.com;

        location /{
            alias '/root/www/nginx/abc/';
            index  index.html index.htm;
            expires  7d;
        }
}

server {
        listen       80 ;
        charset utf-8;
        server_name  www.bbs.com;

        location /{
            alias '/root/www/nginx/bbs/';
            index  index.html index.htm;
            expires  7d;
        }
}
修改host文件

更新配置文件后配置本地host

192.168.64.150 www.abc.com
192.168.64.150 www.bbs.com
访问测试

访问www.abc.com

'xxs'

访问 www.bbs.com

'xxs'

访问不同的域名访问的地址是不一样的这样就像是有多个物理机一样

通配符配置虚拟主机

虚拟主机还支持通配符方式进行配置

server {
        listen       80;
        charset utf-8;
        server_name  *.com;

        location /{
        default_type text/html;
         echo "通配符在前";
        }
}

server {
        listen       80;
        charset utf-8;
        server_name  www.abc.*;

        location /{
        default_type text/html;
         echo "通配符在后";
        }
}
访问测试

访问 www.abc.com 发现出现如下页面

'xxs'

虚拟主机匹配顺序

通过上面的实验可以得出如下结论

  • 最高优先级:完全匹配
  • 第二优先级:通配符在前
  • 第三优先级:通配符在后
默认主机匹配

默认虚拟主机的作用就是:如果有多个访问的域名指向这台web服务器,但某个域名未添加到nginx虚拟主机中,就会访问默认虚拟主机(泛解析)

server {
    # 将域名bbs.com 设置为默认虚拟主机
        listen       80 default;
        charset utf-8;
        server_name  www.bbs.com;

        location /{
            alias '/root/www/nginx/bbs/';
            index  index.html index.htm;
            expires  7d; 
        }
}
测试

使用未配置的域名或者IP地址访问

'xxs'

如果访问一个没有配置的虚拟主机就会跳到bbs的页面

location的作用

location有“定位”的意思,根据请求不同的URL来进行不同的处理,在虚拟主机中(server),location配置是必不可少的,可以把网站不同的部分定位到不同的处理方式上。

location规则

location区段,通过指定模式来与客户端请求的URI相匹配

允许根据用户请求的URI来匹配定义的各location,匹配到时,此请求将被响应的location配置快中的配置所处理,例如做访问控制等功能

语法
location [修饰符] pattern {…}
常用的修饰符说明
修饰符功能
前缀匹配 能够匹配以需要匹配的路径为前缀的uri
=精确匹配
~正则表达式模式匹配,区分大小写
~*正则表达式模式匹配,不区分大小写
^~精确前缀匹配,类似于无修饰符的行为,也是以指定模块开始,不同的是,如果模式匹配,那么就停止搜索其他模式了,不支持正则表达式
/通用匹配,任何请求都会匹配到。

前缀匹配

没有修饰符表示必须以指定模式开始,指定模式前面没有任何修饰符,直接在location后写需要匹配的uri,它的优先级次于正则匹配

server {
    server_name www.demo.com;
    charset   utf-8;
    location /abc {
        default_type text/html;
        echo "前缀匹配-abc...";
    }
}

那么如下内容可以就可以正确匹配:

  • www.demo.com/abc
  • www.demo.com/abc/
  • www.demo.com/abc?.…

通用匹配

通用匹配使用一个 / 表示,可以匹配所有请求,一般nginx配置文件最后都会有一个通用匹配规则,当其他匹配规则均失效时,请求会被路由给通用匹配规则处理;如果没有配置通用匹配,并且其他所有匹配规则均失效时,nginx会返回 404 错误

server {
    server_name www.demo.com;
    charset   utf-8;
    location /{
        default_type text/html;
        echo "通用匹配-default";
    }
}

那么如下内容可以就可以正确匹配所有请求

精确匹配

精确匹配使用 = 表示,nginx进行路由匹配的时候,精确匹配具有最高的优先级,请求一旦精确匹配成功nginx会停止搜索其他到匹配项

server {
    server_name www.demo.com;
    charset   utf-8;
    location = /abc {
        default_type text/html;
        echo "精确匹配-abc-accurate";
    }
}

那么如下内容可正确匹配:

  • www.demo.com/abc
  • www.demo.com/abc?.…

如下内容则无法匹配:

  • www.demo.com/abc/
  • www.demo.com/abc/adcde

精确前缀匹配

精确前缀匹配的优先级仅次于精确匹配,nginx对一个请求精确前缀匹配成功后,停止继续搜索其他到匹配项

server {
    server_name www.demo.com;
    charset   utf-8;
    location ^~ /abc {
        default_type text/html;
        echo "精确前缀匹配-abc-prefix";
    }
}

那么如下内容可以就可以正确匹配:

  • www.demo.com/abc
  • www.demo.com/abc/
  • www.demo.com/abc?.…

正则表达式

正则匹配分为区分大小写和不区分大小写两种,分别用 ~~* 表示;一个请求精确匹配和精确前缀匹配都失败后,如果配置有相关的正则匹配location,nginx会尝试对该请求进行正则匹配。需要说明的是正则匹配之间没有优先级一说,而是按照在配置文件中出现的顺序进行匹配,一旦匹配上一个,就会停止向下继续搜索

区分大小写

~:表示指定的正则表达式要区分大小写,如:

server {
    server_name www.demo.com;
    charset   utf-8;
    location ~ ^/abc$ {
          default_type text/html;
          echo "正则区分大小写-abc-regular-x";
    }
}

那么如下内容可以正确匹配:

  • www.demo.com/abc
  • www.demo.com/abc?.…

如下内容则无法匹配:

  • www.demo.com/abc/
  • www.demo.com/ABC
  • www.demo.com/abcde
不区分大小写

~*:表示指定的正则表达式不区分大小写,如:

server {
    server_name www.demo.com;
    charset   utf-8;
    location ~* ^/abc$ {
         default_type text/html;
         echo "正则不区分大小写-abc-regular-Y";
    }
}

那么如下内容就可以正确匹配:

  • www.demo.com/abc
  • www.demo.com/abc?.…
  • www.demo.com/ABC

如下内容则无法匹配:

  • www.demo.com/abc/
  • www.demo.com/abcde

完整例子

server {
        server_name www.demo.com;
        default_type text/html;
        charset   utf-8;
        location = / {
          echo "规则A";
        }
        location = /login {
            echo "规则B";
        }
        location ^~ /static/ {
            echo "规则C";
        }
        location ^~ /static/files {
            echo "规则X";
        }
        location ~ \\.(gif|jpg|png|js|css)$ {
            echo "规则D";
        }
        location ~* \\.js$ {
            echo "规则E";
        }
        location /img {
            echo "规则Y";
        }
        location / {
           echo "规则F";
        }
}
请求uri匹配路由规则
http://www.demo.com/规则A
http://www.demo.com/login规则B
http://www.demo.com/register规则F
http://www.demo.com/static/a.html规则C
http://www.demo.com/static/files/a.txt规则X
http://www.demo.com/a.png规则D
http://www.demo.com/a.PNG规则F
http://www.demo.com/img/a.gif规则D
http://www.demo.com/img/a.tiff规则Y

匹配顺序

'xxs'

匹配顺序和优先级,由高到底依次为

  • 带有“=”的精确匹配优先
  • 正则表达式
  • 没有修饰符的精确匹配

具体匹配规则如下:

  • =精准匹配命中时,停止location动作,直接走精准匹配,
  • 一般匹配(含精确前缀匹配)命中时,先收集所有的普通匹配,最后对比出最长的那一条
  • 如果最长的那一条普通匹配声明为精确前缀匹配,直接此条匹配,停止location
  • 如果最长的那一条普通匹配不是精确前缀匹配,继续往下走正则location
  • 按代码顺序执行正则匹配,当第一条正则location命中时,停止location

注:有多个正则表达式出现时,按照它们在配置文件中定义的顺序

path匹配过程

'xxs'

假设http请求路径为 http://192.168.0.132:8088/mvc/index?id=2 ,匹配过程如下:

  • 将整个url拆解为域名/端口/path/params
  • 先由域名/端口,对应到目标server虚拟主机
  • path部分参与location匹配,path = path1匹配部分 + path2剩余部分
  • 进入location方法体内部流程。
  • 若是静态文件处理,则进入目标目录查找文件:root指令时找path1+path2对应的文件;alias指令时找path2对应的文件
  • 若是proxy代理,则形如proxy_pass=ip:port时转发path1+path2路径到tomcat;形如proxy_pass=ip:port/xxx时转发path2路径到tomcat。params始终跟随转发。

实际使用建议

所以实际使用中,个人觉得至少有三个匹配规则定义,如下:

#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
#这里是直接转发给后端应用服务器了,也可以是一个静态首页
# 第一个必选规则
location = / {
    proxy_pass http://tomcat:8080/index
}
# 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
# 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
    alias /webroot/static/;
}
location ~* \\.(gif|jpg|jpeg|png|css|js|ico)$ {
    root /webroot/res/;
}
# 第三个规则就是通用规则,用来转发动态请求到后端应用服务器
# 非静态文件请求就默认是动态请求,自己根据实际把握
# 毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了
location / {
    proxy_pass http://tomcat:8080/
}

Nginx负载均衡

负载均衡用于从“upstream”模块定义的后端服务器列表中选取一台服务器接受用户的请求,一个最基本的upstream模块是这样的,模块内的server是服务器列表:

#动态服务器组
upstream dynamicserver {
  server 172.16.44.47:9001; #tomcat 1
  server 172.16.44.47:9002; #tomcat 2
  server 172.16.44.47:9003; #tomcat 3
  server 172.16.44.47:9004; #tomcat 4
}

在upstream模块配置完成后,要让指定的访问反向代理到服务器列表:

#其他页面反向代理到tomcat容器
location ~.*$ {
  index index.jsp index.html;
  proxy_pass http://dynamicserver;
}

这就是最基本的负载均衡实例,但这不足以满足实际需求;目前Nginx服务器的upstream模块支持6种方式的分配

完整配置文件如下

upstream dynamicserver {
  server 192.168.64.1:9001; #tomcat 1
  server 192.168.64.1:9002; #tomcat 2
  server 192.168.64.1:9003; #tomcat 3
  server 192.168.64.1:9004; #tomcat 4
}
server {
        server_name www.demo.com;
        default_type text/html;
        charset   utf-8;

        location ~ .*$ {
            index index.jsp index.html;
            proxy_pass http://dynamicserver;
       }
}

常用参数

参数描述
server反向服务地址 加端口
weight权重
fail_timeout与max_fails结合使用。
max_fails设置在fail_timeout参数设置的时间内最大失败次数,如果在这个时间内,所有针对该服务器的请求都失败了,那么认为该服务器会被认为是停机了
max_conns允许最大连接数
fail_time服务器会被认为停机的时间长度,默认为10s
backup标记该服务器为备用服务器,当主服务器停止时,请求会被发送到它这里。
down标记服务器永久停机了
slow_start当节点恢复,不立即加入

负载均衡策略

在这里,只详细说明Nginx自带的负载均衡策略,第三方不多描述。

负载策略描述
轮询默认方式
weight权重方式
ip_hash依据ip分配方式
least_conn最少连接方式
fair(第三方)响应时间方式
url_hash(第三方)依据URL分配方式
轮询

最基本的配置方法,上面的例子就是轮询的方式,它是upstream模块默认的负载均衡默认策略,每个请求会按时间顺序逐一分配到不同的后端服务器。

#动态服务器组
upstream dynamicserver {
  server 192.168.64.1:9001; #tomcat 1
  server 192.168.64.1:9002; #tomcat 2
  server 192.168.64.1:9003; #tomcat 3
  server 192.168.64.1:9004; #tomcat 4
}
注意
  • 在轮询中,如果服务器down掉了,会自动剔除该服务器。
  • 缺省配置就是轮询策略。
  • 此策略适合服务器配置相当,无状态且短平快的服务使用。

配置示例

upstream dynamicserver {
  server 192.168.64.1:9001; #tomcat 1
  server 192.168.64.1:9002; #tomcat 2
  server 192.168.64.1:9003; #tomcat 3
  server 192.168.64.1:9004; #tomcat 4
}

server {
        server_name www.demo.com;
        default_type text/html;
        charset   utf-8;

        location ~ .*$ {
            index index.jsp index.html;
            proxy_pass http://dynamicserver;
       }
}
weight

权重方式,在轮询策略的基础上指定轮询的几率

#动态服务器组
upstream dynamicserver {
  server 192.168.64.1:9001  weight=2;   #tomcat 1
  server 192.168.64.1:9002; #tomcat 2
  server 192.168.64.1:9003; #tomcat 3
  server 192.168.64.1:9004; #tomcat 4
}

weight参数用于指定轮询几率,weight的默认值为1,;weight的数值与访问比率成正比,比如Tomcat 7.0被访问的几率为其他服务器的两倍。

注意
  • 权重越高分配到需要处理的请求越多。
  • 此策略可以与least_conn和ip_hash结合使用。
  • 此策略比较适合服务器的硬件配置差别比较大的情况。
ip_hash

指定负载均衡器按照基于客户端IP的分配方式,这个方法确保了相同的客户端的请求一直发送到相同的服务器,以保证session会话,这样每个访客都固定访问一个后端服务器,可以解决session不能跨服务器的问题

upstream dynamicserver {
  ip_hash;  #保证每个访客固定访问一个后端服务器
  server 192.168.64.1:9001  weight=2;   #tomcat 1
  server 192.168.64.1:9002; #tomcat 2
  server 192.168.64.1:9003; #tomcat 3
  server 192.168.64.1:9004; #tomcat 4
}
注意
  • 在nginx版本1.3.1之前,不能在ip_hash中使用权重(weight)。
  • ip_hash不能与backup同时使用
  • 此策略适合有状态服务,比如session。
  • 当有服务器需要剔除,必须手动down掉。
least_conn

把请求转发给连接数较少的后端服务器,轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高,这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。

upstream dynamicserver {
  least_conn;  #把请求转发给连接数较少的后端服务器
  server 192.168.64.1:9001  weight=2;   #tomcat 1
  server 192.168.64.1:9002; #tomcat 2
  server 192.168.64.1:9003; #tomcat 3
  server 192.168.64.1:9004; #tomcat 4
}
注意
  • 此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况。

重试策略

现在对外服务的网站,很少只使用一个服务节点,而是部署多台服务器,上层通过一定机制保证容错和负载均衡。

基础失败重试

为了方便理解,使用了以下配置进行分析(proxy_next_upstream 没有特殊配置)

重试配置
upstream dynamicserver {
      server 192.168.64.1:9001 fail_timeout=60s max_fails=3; #Server A
      server 192.168.64.1:9002 fail_timeout=60s max_fails=3; #Server B
}
配置说明

max_fails=3 fail_timeout=60s代表在60秒内请求某一应用失败3次,认为该应用宕机,后等待60秒,这期间内不会再把新请求发送到宕机应用,而是直接发到正常的那一台,时间到后再有请求进来继续尝试连接宕机应用且仅尝试1次,如果还是失败,则继续等待60秒…以此循环,直到恢复

模拟异常

模拟后端异常的方式是直接将对应服务关闭,造成 connect refused 的情况,对应 error 错误。

在最初始阶段,所有服务器都正常,请求会按照轮询方式依次转发给 AB 两个 Server 处理。假设这时 A 节点服务崩溃,端口不通,则会出现这种情况:

  1. 请求 1 转到 A 异常,再重试到 B 正常处理,A fails +1
  2. 请求 2 转到 B 正常处理
  3. 请求 3 转到 A 异常,再重试到 B 正常处理,A fails +1 达到 max_fails 将被屏蔽 60s
  4. 屏蔽 A 的期间请求都只转给 B 处理,直到屏蔽到期后将 A 恢复重新加入存活列表,再按照这个逻辑执行

如果在 A 的屏蔽期还没结束时,B 节点的服务也崩溃,端口不通,则会出现:

  1. 请求 1 转到 B 异常,此时所有线上节点异常,会出现:

    • AB 节点一次性恢复,都重新加入存活列表
    • 请求转到 A 处理异常,再转到 B 处理异常
    • 触发 no live upstreams 报错,返回 502 错误
    • 所有节点再次一次性恢复,加入存活列表
  2. 请求 2 依次经过 AB 均无法正常处理, 触发 no live upstreams 报错,返回 502 错误

错误重试

有时候系统出现500等异常的情况下,希望nginx能够到其他的服务器进行重试,可以配置那些错误码才进行重试

配置说明

在nginx的配置文件中,proxy_next_upstream项定义了什么情况下进行重试,官网文档中给出的说明如下

Syntax: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ...;
Default:    proxy_next_upstream error timeout;
Context:    http, server, location

默认情况下,当请求服务器发生错误或超时时,会尝试到下一台服务器,还有一些其他的配置项如下:

错误状态描述
error与服务器建立连接,向其传递请求或读取响应头时发生错误;
timeout在与服务器建立连接,向其传递请求或读取响应头时发生超时;
invalid_header服务器返回空的或无效的响应;
http_500服务器返回代码为500的响应;
http_502服务器返回代码为502的响应;
http_503服务器返回代码为503的响应;
http_504服务器返回代码504的响应;
http_403服务器返回代码为403的响应;
http_404服务器返回代码为404的响应;
http_429服务器返回代码为429的响应(1.11.13);
non_idempotent通常,请求与 非幂等 方法(POST,LOCK,PATCH)不传递到请求是否已被发送到上游服务器(1.9.13)的下一个服务器; 启用此选项显式允许重试此类请求;
off禁用将请求传递给下一个服务器。
配置说明

这里面配置了500等错误的时候会进行重试

upstream dynamicserver {
  server 192.168.64.1:9001 fail_timeout=60s max_fails=3; #tomcat 1
  server 192.168.64.1:9002 fail_timeout=60s max_fails=3; #tomcat 2
}

server {
        server_name www.demo.com;
        default_type text/html;
        charset   utf-8;

        location ~ .*$ {
            index index.jsp index.html;
            proxy_pass http://dynamicserver;
            #下一节点重试的错误状态
            proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
       }
}
模拟异常

在正常的情况下如果500错误会直接出现异常页面,现在加入了以上500重试策略,重试错误的流程和上面流程是一样的

backup 服务器

Nginx 支持设置备用节点,当所有线上节点都异常时启用备用节点,同时备用节点也会影响到失败重试的逻辑,因此单独列出来介绍。

backup 处理逻辑

upstream 的配置中,可以通过 backup 指令来定义备用服务器,其含义如下

  1. 正常情况下,请求不会转到到 backup 服务器,包括失败重试的场景
  2. 当所有正常节点全部不可用时,backup 服务器生效,开始处理请求
  3. 一旦有正常节点恢复,就使用已经恢复的正常节点
  4. backup 服务器生效期间,不会存在所有正常节点一次性恢复的逻辑
  5. 如果全部 backup 服务器也异常,则会将所有节点一次性恢复,加入存活列表
  6. 如果全部节点(包括 backup)都异常了,则 Nginx 返回 502 错误
配置说明
upstream dynamicserver {
  server 192.168.64.1:9001 fail_timeout=60s max_fails=3; #Service A
  server 192.168.64.1:9002 fail_timeout=60s max_fails=3; #Server B
  server 192.168.64.1:9003 backup; #backup
}

server {
        server_name www.demo.com;
        default_type text/html;
        charset   utf-8;

        location ~ .*$ {
            index index.jsp index.html;
            proxy_pass http://dynamicserver;
            #下一节点重试的错误状态
            proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
       }
}

在最初始阶段,所有服务器都正常,请求会按照轮询方式依次转发给 AB 两个节点处理。当只有 A 异常的情况下,与上文没有 backup 服务器场景处理方式一致,这里就不重复介绍了。

假设在 A 的屏蔽期还没结束时,B 节点的服务也崩溃,端口不通,则会出现:

  1. 请求 1 转到 B 处理,异常,此时所有线上节点异常,会出现:

    • AB 节点一次性恢复,都重新加入存活列表
    • 请求转到 A 处理异常,再重试到 B 处理异常,两者 fails 都 +1
    • 因 AB 都异常,启用 backup 节点正常处理,并且 AB 节点一次性恢复,加入存活列表
  2. 请求 2 再依次经过 A、B 节点异常,转到 backup 处理,两者 fails 都达到 max_fails:

    • AB 节点都将会被屏蔽 60s,并且不会一次性恢复
    • backup 节点正式生效,接下来所有请求直接转到 backup 处理
    • 直到 AB 节点的屏蔽到期后,重新加入存活列表

假设 AB 的屏蔽期都还没结束时,C 节点的服务也崩溃,端口不通,则会出现

  1. 请求 1 转到 C 异常,此时所有节点(包括 backup)都异常,会出现:

    • ABC 三个节点一次性恢复,加入存活列表
    • 请求转到 A 处理异常,重试到 B 处理异常,最后重试到 C 处理异常
    • 触发 no live upstreams 报错,返回 502 错误
    • 所有节点再次一次性恢复,加入存活列表
  2. 请求 2 依次经过 AB 节点异常,重试到 C 异常,最终结果如上个步骤,返回 502 错误

限制重试方式

默认配置是没有做重试机制进行限制的,也就是会尽可能去重试直至失败,Nginx 提供了以下两个参数来控制重试次数以及重试超时时间

  • proxy_next_upstream_tries:设置重试次数,默认 0 表示无限制,该参数包含所有请求 upstream server 的次数,包括第一次后之后所有重试之和;
  • proxy_next_upstream_timeout:设置重试最大超时时间,默认 0 表示不限制,该参数指的是第一次连接时间加上后续重试连接时间,不包含连接上节点之后的处理时间
配置说明
upstream dynamicserver {
      server 192.168.64.1:9001 fail_timeout=60s max_fails=3; #Server A
      server 192.168.64.1:9002 fail_timeout=60s max_fails=3; #Server B
}

server {
        server_name www.demo.com;
        default_type text/html;
        charset   utf-8;

        location ~ .*$ {
            index index.jsp index.html;
            proxy_pass http://dynamicserver;
            # 表示重试超时时间是3s
            proxy_connect_timeout 3s;
            #表示在 6 秒内允许重试 3 次,只要超过其中任意一个设置,Nginx 会结束重试并返回客户端响应
            proxy_next_upstream_timeout 6s;
            proxy_next_upstream_tries 3;
       }
}

Nginx 常用案例

代理静态文件

server {
        listen       10086;
        server_name  www.demo.com;

        location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
        }
    
        location /data/ {
            alias '/usr/local/data/'; 
            #这里是重点,就是代理这个文件夹 
            expires    7d;
        }
}

访问 http://localhost:10086/data/下面的资源就是访问/usr/local/data文件夹的资源

反向代理

server {
    listen       80;
    server_name  www.demo.com;;

    location / {
        proxy_pass http://127.0.0.1:8080;
        index  index.html index.htm .jsp;
    }
}

跨域配置

server {
        listen       80;
        server_name  www.demo.com;

    if ( $host ~ (.*).demo.com){
        set $domain $1;##记录二级域名值
    }
    #是否允许请求带有验证信息
    add_header Access-Control-Allow-Credentials true;
    #允许跨域访问的域名,可以是一个域的列表,也可以是通配符*
    add_header Access-Control-Allow-Origin  *;
    #允许脚本访问的返回头
    add_header Access-Control-Allow-Headers 'x-requested-with,content-type,Cache-Control,Pragma,Date,x-timestamp';
    #允许使用的请求方法,以逗号隔开
    add_header Access-Control-Allow-Methods 'POST,GET,OPTIONS,PUT,DELETE';
    #允许自定义的头部,以逗号隔开,大小写不敏感
    add_header Access-Control-Expose-Headers 'WWW-Authenticate,Server-Authorization';
    #P3P支持跨域cookie操作
    add_header P3P 'policyref="/w3c/p3p.xml", CP="NOI DSP PSAa OUR BUS IND ONL UNI COM NAV INT LOC"';
    if ($request_method = 'OPTIONS') {##OPTIONS类的请求,是跨域先验请求
            return 204;##204代表ok
     }
}

防盗链

通过Referer实现防盗链比较基础,仅可以简单实现方式资源被盗用,构造Referer的请求很容易实现

场景:由于图片链接可以跨域访问,所以图片链接往往被其他网站盗用,从而增加服务器负担;

解决方案:nginx可以通过valid_referers配置进行防盗链配置

valid_referers 指令

指定合法的来源’referer’, 他决定了内置变量$invalid_referer的值,如果referer头部包含在这个合法网址里面,这个变量被设置为0,否则设置为1. 需要注意的是:这里并不区分大小写的.

  • 语法: valid_referers none | blocked | server_names | string …;
  • 配置段: server, location
配置说明
  • none : 允许没有http_refer的请求访问资源;

  • blocked : 允许不是http://开头的,不带协议的请求访问资源;

  • 192.168.0.1 : 只允许指定ip来的请求访问资源;

  • *.google.com:允许*.google.com的域名请求访问资源

配置代码
# 需要防盗的后缀
location ~* \\.(jpg|jpeg|png|gif|bmp|swf|rar|zip|doc|xls|pdf|gz|bz2|mp3|mp4|flv)$
    #设置过期时间
    expires     30d;
    # valid_referers 就是白名单的意思
    # 支持域名或ip
    # 允许ip 192.168.0.1 的请求
    # 允许域名 *.google.com 所有子域名
    valid_referers none blocked 192.168.0.1 *.google.com;
    if ($invalid_referer) {
        # return 403;
        # 盗链返回的图片,替换盗链网站所有盗链的图片
        rewrite ^/ https://site.com/403.jpg;
    }
    root  /usr/share/nginx/img;
}

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

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

相关文章

Quartz表达式在线生成器

Quartz Cron表达式生成器 - devTest.run Quartz是一款高效的定时任务调度框架&#xff0c;由于其稳定性&#xff0c;高可用性和灵活性&#xff0c;Quartz已成为Java企业级开发中应用最为广泛的定时任务调度框架之一。 Quartz的主要特点包括&#xff1a;可配置的作业触发器&…

学C的第二十五天【指针的进阶】

相关代码gitee自取&#xff1a;C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第二十四天【练习&#xff1a;1. 打印菱形&#xff1b;2. 打印自幂数&#xff1b;3. 求Snaaa..n项之和&#xff1b;4. 喝汽水问题&#xff1b;5. 调整数组使奇数位于偶数前面&…

第三章——处理数据

面向对象编程&#xff08;OOP&#xff09;的本质是设计并扩展自己的数据类型。设计自己的数据类型就是让类型与数据匹配。在创建自己的类型之前必须先了解C内置的类型。 内置的C类型分为两组&#xff1a;基本类型和复合类型 简单变量 程序通常都需要存储信息&#xff0c;为把…

git commit history导出

git log --after"2022-1-1" --dateshort --prettyformat:"%H","%an","%ae","%ad","%s" --shortstat --no-merges再简洁一点 git log --after"2022-4-1" --dateshort --prettyformat:%H,%an,%ae,%ad,%…

Network Neuroscience:整个生命周期的功能连接体指纹

导读 随着年龄的增长&#xff0c;人脑功能结构发生了系统性的变化。然而&#xff0c;功能连接(FC)作为一种检测独特“连接体指纹”的强大特征&#xff0c;使个体能够在同龄人中被识别出来。虽然已在年轻人样本中观察到这种指纹&#xff0c;但该方法在整个生命周期内的可靠性尚…

ACL 2023|大模型时代,自然语言领域还有什么学术增长点?

国际计算语言学年会&#xff08;Annual Meeting of the Association for Computational Linguistics&#xff0c;简称 ACL&#xff09;是自然语言处理&#xff08;NLP&#xff09;领域的顶级国际会议&#xff0c;ACL 2023 将于2023年7月9-14日在加拿大多伦多举行。随着人工智能…

电脑高手的选择:为何只需一款杀毒软件?

对于电脑高手来说&#xff0c;保护计算机免受恶意软件和病毒的侵害至关重要。然而&#xff0c;有些人可能认为安装多个杀毒软件能够提供更优质的防护能力。但事实上&#xff0c;电脑高手通常只选择安装一款杀毒软件&#xff0c;这其中包含着一定的原因和考虑。本文将探讨为什么…

Java版本企业电子招投标采购系统源码功能模块功能描述+数字化采购管理 采购招投标

功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外部…

基于Python+MySQL所写的医院管理系统

点击以下链接获取源码资源&#xff1a; https://download.csdn.net/download/qq_64505944/87985429?spm1001.2014.3001.5503 目录 摘要 I 1 需求分析 1 1.1 任务描述 1 1.2 需求分析的过程 1 1.3 业务需求 2 1.4 功能描述 2 2 总体设计 3 2.1 系统开发环境 3 2.2 系统功能流…

【云原生】Pod 的生命周期

Pod 的生命周期 本文讲解的是 Kubernetes 中 Pod 的生命周期&#xff0c;包括生命周期的不同阶段、存活和就绪探针、重启策略等。 Pod phase Pod 的 status 字段是一个 PodStatus 对象&#xff0c;PodStatus中有一个 phase 字段。 Pod 的相位&#xff08;phase&#xff09;…

DOM事件机制(事件流、事件委托、事件类型)以及BOM

HTML DOM 允许 JavaScript 对 HTML 事件作出反应。JavaScript 能够在事件发生时执行&#xff0c;比如当用户点击某个 HTML 元素时。 JavaScript与HTML之间的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。 虽然 ECMAScript 把浏览器对象模型&…

【面试题28】什么是PHP-FPM?它与PHP和Nginx有什么关系

文章目录 一、前言二、什么是PHP-FPM&#xff1f;三、PHP-FPM的生命周期3.1 启动阶段3.2 初始化阶段3.3 请求处理阶段3.4 关闭阶段 四、PHP-FPM与PHP的关系五、PHP-FPM与Nginx的通信方式六、总结 一、前言 本文已收录于PHP全栈系列专栏&#xff1a;PHP面试专区。 计划将全覆盖P…

【视觉SLAM入门】2.旋转--李群与李代数

"川泽纳污" 0. 一个例子1. 群和李群2. 李代数2.1 推导和性质2.2 s o ( 3 ) \mathscr{so(3)} so(3) 和 s e ( 3 ) \mathscr{se(3)} se(3)2.3 计算李代数的幂 e x p ( ϕ \;exp(\phi exp(ϕ^ ) ) )2.4 李代数乘法2.5 从李代数乘法到导数&#xff1a;2.5.1 直接求导2.…

100天精通Golang(基础入门篇)——第14天:深入解析Go语言函数->从概念到实践,助您精通基础知识!(基础)

&#x1f337; 博主 libin9iOak带您 Go to Golang Language.✨ &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &#x1f30a; 《I…

第11章:C语言数据结构与算法初阶之排序

系列文章目录 文章目录 系列文章目录前言排序的概念及其运用排序的概念常见的排序算法 常见排序算法的实现1.直接插入排序2. 希尔排序&#xff08;缩小增量排序&#xff09;3. 直接选择排序4. 堆排序5. 冒泡排序6. 快速排序将区间按照基准值划分为左右两半部分的常见方式&#…

使用selenium爬取猫眼电影榜单数据

文章目录 前言导入所需的库&#xff1a;设置ChromeDriver的路径&#xff0c;并创建一个Chrome浏览器实例&#xff1a;打开目标网页&#xff0c;这里以猫眼电影榜单页面为例&#xff1a;使用XPath定位电影信息。通过查看网页源代码&#xff0c;发现电影信息所在的<dd>标签…

深度学习之目标检测Faster RCNN模型算法流程详解说明(超详细理论篇)

1.Faster RCNN论文背景 2. Faster-RCNN算法流程 &#xff08;1&#xff09;Fast-RCNN算法流程 &#xff08;2&#xff09;特征提取conv layers &#xff08;3&#xff09;Region Proposal Networks(RPN) &#xff08;4&#xff09;ROI Pooling作用 &#xff08;5&#xff09;Cl…

Spring定时器调度实现的原理

1、使用Spring定时器任务实现 package com.suyun.modules.vehicle.timetask;import com.alibaba.schedulerx.worker.domain.JobContext; import com.alibaba.schedulerx.worker.processor.JavaProcessor; import com.alibaba.schedulerx.worker.processor.ProcessResult; impo…

arm学习cortex-A7中断按键控制led灯亮灭

main.c #include "key.h" extern void printf(const char *fmt, ...); void delay_ms(int ms) {int i,j;for(i 0; i < ms;i)for (j 0; j < 1800; j); } int main() {//rcc初始化 RCC->MP_AHB4ENSETR | (0x3 << 4);//初始化按键GPIOF模式为输入模式…