随笔 - 50  文章 - 0  评论 - 0  阅读 - 3318

Nginx

NGINX

1、IO模型

1、同步|异步

# 机制
同步:点餐后老板不会通知你做好了,你得自己不停去问好了没
异步:点餐后饭好了老板主动叫你

2、阻塞|非阻塞

# 调用者状态
阻塞:点餐后等着饭,啥也干不了
非阻塞:点餐后想干嘛干嘛

2、网络IO

2.1 同步阻塞型


用户调用系统内核来进行IO操作
当发出指令后,需要等待内核接收到网络报文,并将其成功转发到用户空间才完成此次调用,在此期间啥也干不了,cpu分片时间未被充分利用,造成大量浪费
优缺点:
优: 程序简单,等待期间cpu使用率低,cpu负载低
缺: 每个请求均由独立的线程或进程完成,当并发量大时 cpu由于数量不足会频繁进行切换,且线程多了也占用内存,内存占用也高

2.2 同步非阻塞型

用户调用系统内核进行io操作
当发出指令后立即返回结果,需要不简单请求,在内核接收报文之前一直发起,直到内核收到报文将其转发给用户
此类型对cpu造成无意义的资源浪费,一般不直接使用此模型

2.3 多路io复用型

系统监视一组socket,当内核收到所监视的socket请求的io报文到达后,会通知用户进程,用户再执行io操作

2.4 信号驱动io模型

异步非阻塞
当调用内核io时不用阻塞,且内核会在数据达到后发信号通知用户

2.5 异步 I/O 模型

和信号驱动类似,但不是通知信号用户可以进行io而是进行完io后通知用户已完成

3、零拷贝

系统的内存及io操作是用户代码会单独分出一部分空间,要进行io需要从内核空间拿去,内核空间从文件或网络拿取,基于指针的映射关系,可以直接让传输发生在内存上而不需要经过用户内存空间,大大提升io效率,编程中的copy和指针引用

4、nginx介绍

4.1 功能

静态的web资源服务器html,图片,js,css,txt等静态资源
http/https协议的反向代理
结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求
tcp/udp协议的请求转发(反向代理)
imap4/pop3协议的反向代理

4.2 应用特点

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

4.3 web服务特点

虚拟主机(server)
支持 keep-alive 和管道连接(利用一个连接做多次请求)
访问日志(支持基于日志缓冲提高其性能)
url rewirte
路径别名
基于IP及用户的访问控制
支持速率限制及并发数限制
重新配置和在线升级而无须中断客户的工作进程

5、架构

5.1 程序

image-20231220150612170

5.2 进程架构

image-20231220151234392

5.2.1 master

对外接口:接收外部的操作(信号)
对内转发:根据外部的操作的不同,通过信号管理 Worker
监控:监控 worker 进程的运行状态,worker 进程异常终止后,自动重启 worker 进程
读取Nginx 配置文件并验证其有效性和正确性
建立、绑定和关闭socket连接
按照配置生成、管理和结束工作进程
接受外界指令,比如重启、升级及退出服务器等指令
不中断服务,实现平滑升级,重启服务并应用新的配置
开启日志文件,获取文件描述符
不中断服务,实现平滑升级,升级失败进行回滚处理
编译和处理perl脚本

5.2.2 worker

所有 Worker 进程都是平等的
实际处理:网络请求由 Worker 进程处理
Worker进程数量:一般设置为核心数,充分利用CPU资源,同时避免进程数量过多,导致进程竞争CPU资源,
增加上下文切换的损耗
接受处理客户的请求
将请求依次送入各个功能模块进行处理
I/O调用,获取响应数据
与后端服务器通信,接收后端服务器的处理结果
缓存数据,访问缓存索引,查询和调用缓存数据
发送请求结果,响应客户的请求
接收主程序指令,比如重启、升级和退出等

5.2.3 进程通信模型

5.2.3.1 主与worker

主进程根据配置生成worker进程,并且建立一张表来进行动态统计,并与每个worker建立单向的发送通道发送worker需要的信息

5.2.3.2 worker与worker

worker之间通信依赖于master,当需要通信时master会将其余worker的信息通过管道进行发送使其能建立通道进行连接,由于它们处于同一进程所以内存空间共享

5.2.3.3 主与外

通过信号接收请求,kill -s 

6、安装和升级

6.1 编译安装

SRC_DIR=/usr/local/src
NGINX_URL=http://nginx.org/download/
NGINX_FILE=nginx-1.20.0
TAR=.tar.gz
NGINX_INSTALL_DIR=/apps/nginx
CPUS=`lscpu |awk '/^CPU\(s\)/{print $2}'`

color () {
    RES_COL=60
    MOVE_TO_COL="echo -en \\033[${RES_COL}G"
    SETCOLOR_SUCCESS="echo -en \\033[1;32m"
    SETCOLOR_FAILURE="echo -en \\033[1;31m"
    SETCOLOR_WARNING="echo -en \\033[1;33m"
    SETCOLOR_NORMAL="echo -en \E[0m"
    echo -n "$1" && $MOVE_TO_COL
    echo -n "["
    if [ $2 = "success" -o $2 = "0" ] ;then
        ${SET1COLOR_SUCCESS}
        echo -n $"OK"
    elif [ $2 = "failure" -o $2 = "1" ] ;then
        ${SETCOLOR_FAILURE}
        echo -n $"FAILED"
    else
        ${SETCOLOR_WARNING}
        echo -n $"WARNING"
    fi
    ${SETCOLOR_NORMAL}
    echo -n "]"
    echo
}

os_type () {
  awk -F'[ "]' '/^NAME/{print $2}' /etc/os-release
}

os_version () {
  awk -F'"' '/^VERSION_ID/{print $2}' /etc/os-release
}

check () {
  [ -e ${NGINX_INSTALL_DIR} ] && { color "nginx 已安装,请卸载后再安装" 1; exit; }
  cd ${SRC_DIR}
  if [ -e ${NGINX_FILE}${TAR} ];then
    color "相关文件已准备好" 0http://nginx.org/download/
  else
    color '开始下载 nginx 源码包' 0
    wget ${NGINX_URL}${NGINX_FILE}${TAR}
    [ $? -ne 0 ] && { color "下载 ${NGINX_FILE}${TAR}文件失败" 1; exit; }
  fi
}

install () {
  color "开始安装 nginx" 0
  if id nginx &> /dev/null;then
    color "nginx 用户已存在" 1
  else
    useradd -s /sbin/nologin -r nginx
    color "创建 nginx 用户" 0
  fi
  color "开始安装 nginx 依赖包" 0
  if [ `os_type` == "CentOS" -a `os_version` == '8' ] ;then
    yum -y -q install make gcc-c++ libtool pcre pcre-devel zlib zlib-devel
    openssl openssl-devel perl-ExtUtils-Embed
  elif [ `os_type` == "CentOS" -a `os_version` == '7' ];then
    yum -y -q install make gcc pcre-devel openssl-devel zlib-devel perl-ExtUtils-Embed
  else
    apt update &> /dev/null
    apt -y install make gcc libpcre3 libpcre3-dev openssl libssl-dev zlib1g-dev &> /dev/null
  fi
  cd $SRC_DIR
  tar xf ${NGINX_FILE}${TAR}
  NGINX_DIR=`echo ${NGINX_FILE}${TAR}| sed -nr 's/^(.*[0-9]).*/\1/p'`
  cd ${NGINX_DIR}
  ./configure --prefix=${NGINX_INSTALL_DIR} --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
  make -j $CPUS && make install
  [ $? -eq 0 ] && color "nginx 编译安装成功" 0 || { color "nginx 编译安装失败,退出!" 1 ;exit; }
  echo "PATH=${NGINX_INSTALL_DIR}/sbin:${PATH}" > /etc/profile.d/nginx.sh
cat > /lib/systemd/system/nginx.service<<EOF
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=${NGINX_INSTALL_DIR}/logs/nginx.pid
ExecStartPre=/bin/rm -f ${NGINX_INSTALL_DIR}/logs/nginx.pid
ExecStartPre=${NGINX_INSTALL_DIR}/sbin/nginx -t
ExecStart=${NGINX_INSTALL_DIR}/sbin/nginx
ExecReload=/bin/kill -s HUP \$MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF

  systemctl daemon-reload
  systemctl enable --now nginx &> /dev/null
  systemctl is-active nginx &> /dev/null || { color "nginx 启动失败,退出!" 1 ;exit; }
  ln -sv /apps/nginx/sbin/nginx /usr/bin/
  color "nginx 安装完成" 0
}

check
install

6.2 升级

6.2.1 平滑升级(不停机升级)

6.2.1.1 原理

编译新的nginx二进制文件,并启动,对老的进程发送信号使两个进程共存,但老进程会在每一个worker退出后关闭线程直到所有线程被关闭优雅退出,这时候由新worker全面接替,容器环境下直接打镜像即可,无需这么麻烦

7、命令管理

# 帮助信息
nginx -h
# 查看版本信息
-V -v 
# 测试配置文件
-t
	立刻停止服务:stop,相当于信号SIGTERM,SIGINT
    优雅的停止服务:quit,相当于信号SIGQUIT
    平滑重启,重新加载配置文件: reload,相当于信号SIGHUP
    重新开始记录日志文件:reopen,相当于信号SIGUSR1,在切割日志时用途较大
    平滑升级可执行程序:发送信号SIGUSR2,在升级版本时使用
    优雅的停止工作进程:发送信号SIGWINCH,在升级版本时使用
# 和主进程通信
-s
# 手动指定错误日志路径
-e 
# 手动指定配置文件
-c 

8、配置

8.1 配置文件来源

# 主配置文件
nginx.conf
# 子配置文件
主配置文件include 定义的目录下的文件或文件
# 部分协议支持的配置
fastcgi uwsgi scgi
# mime
可以理解为自定义类型的配置文件
参考链接:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_Types

8.2 配置文件格式

# 配置文件由指令与指令块构成
  # 指令
worker_processes  1;
  # 指令块,指令块是指令的集合
  # 指令块可以嵌套
events {  
    worker_connections  1024;
}
# 每条指令以;分号结尾,指令与值之间以空格符号分隔
# include可以实现配置的分离增加可读性和维护的便利
# $符号表示变量
# # 用来进行注释

8.3 配置文件详解

8.3.1 主配置文件

# nginx.conf
主配置文件分四块
# 全局配置
默认以顶格写的配置
# 事件模块
event {
	...
}
# http块
http {
	...
}
# 用作负载的块
stream {
	...
}
# mail 用的少
mail {
	...
}

8.3.1.1 全局配置

user nginx nginx; # 指定运行nginx的用户和组
worker_processes 2; # 指定nginx启动后的工作线程
worker_cpu_affinity 00000001 00000010;# cpu亲和,将worker进程和cpu进行绑定减少cpu切换带来的损失 ps axo pid,cmd,psr |grep nginx  查看cpu绑定
error_log /apps/nginx/logs/error.log  [debug | info | notice | warn | error | crit| alert | emerg] # 错误日志自定义路径和输出级别
pid /apps/nginx/run/nginx.pid
worker_priority 0; # 工作进程的nice优先级
worker_rlimit_nofile 65536; # 工作进程能打开的fd数量 ,一般和ulimit -n 或者limits.conf的值保持一致
# cat /etc/security/limits.conf 看 * 用户的大小
*	soft	nofile	1000000
*	hard	nofile	1000000
*	-		nproc	1000000
daemon off; # 是否开启前台运行,可以用来调试

include	/etc/nginx/mime.types; # 指定包含mime配置
default_type	application/octet-stream; # 将除了mime中定义的类型的其余类型视为默认配置的类型

8.3.1.2 event块

event {
	# 作为web服务 最大并发= worker_connections * worker_processes 
	# 作为反向代理 worker_connections * worker_processes / 2 
	worker_connections 1024; # 单个worker能接受的最大并发
}

8.3.1.3 http块

 # 主要为web服务定义配置
http {
	include	mime.types; # 指定包含自定义类型
	default_type	application/octet-stream; #默认类型
	sendfile	on; # 零拷贝技术,加快操作效率,建议打开
	keepalive_timeout 65; # 长连接多长时间断开 单位 秒
	use epoll; # 开启epoll,提高性能
	accept_mutex on; # 惊群设置,建议打开,避免所有worker进行抢占
	multi_accept on; # 开启一个进程可以接受多个网络连接 
	log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # 定义一个名称为main的日志格式
	access_log logs/access.log main; # 指定访问日志使用main格式
	tcp_nopush on; # 开启sendfile下,合并请求统一发送
	tcp_nodelay off; # 长连接模式下是否开启延迟发送,延迟0.2s,on不延迟发送
	gzip on; # 是否开启文件压缩
	server_tokens on|off|build|string; # 是否在响应报文显示nginx版本
	# 虚拟主机,可以配置多个
	server {
		listen	80; # 指定监听端口
		server_name	localhost; # 指定本虚拟主机的服务名称
		charset utf-8; # 设置编码格式
		access_log	logs/host.access1.log main; #单独设置日志路径和格式
		# 指定匹配规则,可以使用多个
		location / { 
			root html; #默认页面路径,可以使用绝对路径
			index index.html index.htm; # 默认的页面文件名称,在上面目录下
			error_page	500 502 503 504	/50x.html; # 错误码对应的页面,可以自定义,比如404
            error_page 401 402 403 404 /40x.html
		}
		
		location = /50x.html{
			root	html; # 指定匹配条件满足时跳转根目录
		}
		
		location = /40x.html{
			root	html; # 指定匹配条件满足时跳转根目录
		}
	}
}

9、web应用

9.1 修改nginx对外显示版本和名称

修改源码
/src/core/nginx.h
define NGINX_VERSION	"1.68.9" #修改版本
define NGINX_VER	"gunginx/" NGINX_VERSION # 修改名称
修改配置
server_tokens on

9.2 做为web服务器

# 新建一个配置文件目录
mkdir /apps/nginx/conf/conf.d
# 修改主配置文件
vim nginx.conf
http{
	include /apps/nginx/conf/conf.d/*.conf
}

# 配置虚拟主机
root@nginx1 nginx]# cat conf/conf.d/pc.conf 
server {
    listen       81;
    server_name  pc;
    location / {
        root   html/pc;
        index  index_pc.html;
    }
}
[root@nginx1 nginx]# tree html/
html/
├── 40x.html
├── 50x.html
├── index.html
└── pc
    └── index_pc.html
    
# 配置第二个虚拟主机
root@nginx1 nginx]# cat conf/conf.d/phone.conf 
server {
    listen       82;
    server_name  phone;
    location / {
        root   html/phone;
        index  index_phone.html;
    }
}
conf/conf.d/
├── pc.conf
└── phone.conf

html/
├── 40x.html
├── 50x.html
├── index.html
├── pc
│   └── index_pc.html
└── phone
    └── index_phone.html

9.3 location 匹配规则

基于url的路径匹配,将文件与url进行映射,是web服务需要掌握的核心
参考资料
http://nginx.org/en/docs/http/ngx_http_core_module.html#location
# 匹配所需的资源url需后端文件存在,比如Aa.jpg

9.3.1 语法

location [ = | ~ | ~* | ^~ ] uri { ... }
# = 精准匹配,需完全符合匹配字符串,区分大小写
location = / {
    [ configuration A ]
}
# ^~ 以正则开头,不区分大小写
location ^~ / {
    [ configuration A ]
}
# ~ 包含正则 区分大小写
location ~ / {
    [ configuration A ]
}
# ~* 包含正则 不区分大小写
location ~* / {
    [ configuration A ]
}
# 无任何符号,匹配开头为 / 的所有路径
# ~ 包含正则 区分大小写
location / {
    [ configuration A ]
}
# \ 转义字符,将特殊符号转义为符号本身

9.3.2 精准匹配(=)

# http://172.31.3.112:81/meihualu.jpg
server {
    listen       81;
    server_name  pc;
    location / {
        root   html/pc;
        index  index_pc.html;
    }

    location = /meihualu.jpg {
        root   /data/test;
    }
}

../test
└── meihualu.jpg

9.3.3 正则开头(^~)

# http://172.31.3.112:81/image1
location ^~ /ima {
        root   /data/test;
    }

../test
├── image1
└── meihualu.jpg

9.3.4 正则-不区分大小写(~)

# http://172.31.3.112:81/Laohu.jpg
location ~ /.*aoH.*.jpg {
        root   /data/test;
}
    
../test
├── image1
├── Laohu.jpg
└── meihualu.jpg

9.3.5 正则-区分大小写(~*)

# http://172.31.3.112:81/TaiDi.jpg
location ~* /t.*i.jpg {
        root   /data/test;
}

../test
├── image1
├── Laohu.jpg
├── meihualu.jpg
└── TaiDi.jpg

9.3.6 匹配优先级

= > ^~ > ~/~* > /

9.4 基于四层的访问控制

location ~ /.*ao.*u.jpg {
        root   /data/test;
        # 权限控制注意从上至下的顺序为从小到大
        deny 172.31.3.1;
        allow 172.31.3.0/24;
        deny all;
}


[root@nexus ~]# curl 172.31.3.112:81/Laohu.jpg -I
HTTP/1.1 200 OK
Server: QianKun/v1.0
Date: Thu, 21 Dec 2023 05:33:31 GMT
Content-Type: image/jpeg
Content-Length: 1037344
Last-Modified: Thu, 21 Dec 2023 05:07:47 GMT
Connection: keep-alive
ETag: "6583c823-fd420"
Accept-Ranges: bytes

[root@nexus ~]# exit
登出
Connection to 172.31.3.111 closed.
(base) gu@python:~/download$ curl 172.31.3.112:81/Laohu.jpg -I
HTTP/1.1 403 Forbidden
Server: QianKun/v1.0
Date: Thu, 21 Dec 2023 05:35:02 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive

9.5 基于账户密码认证

yum -y install httpd-tools
apt -y install apache2-utils

# 生成用户名和密码  
htpasswd  -cb /apps/nginx/conf/.htpasswd gu 123456
# 配置

location ~* /t.*i.jpg {
        root   /data/test;
        auth_basic  "login password";
        auth_basic_user_file    /apps/nginx/conf/.htpasswd;
}

9.6 自定义错误页面

# 可用位置 http, server, location
error_page code ... [=[response]] uri;
error_page  404 403 402 401             /40x.html;

location = /40x.html {
    root   html;
}

9.7 自定义错误日志

# 可用位置 main, http, mail, stream, server, location
error_log file [level];
level: debug, info, notice, warn, error, crit, alert, emerg
error_log /apps/nginx/logs/xx-error.log

9.8 文件检测

location / {
        root   /data/test;
        index  index.html;
        # 依次匹配,若都匹配不到返回最后一个页面
        try_files $uri $uri/index.html $uri.html /ss/default.html;
}

9.9 长连接配置

keepalive_timeout timeout [header_timeout] # 长连接保持时长 
keepalive_requests number; # 一次长连接可以请求的资源最大数量

9.10 下载服务器

需要ngx_http_autoindex_module模块
http://nginx.org/en/docs/http/ngx_http_autoindex_module.html
# 重新编译
cd /usr/local/src/
./configure --help|grep autoindex 
加上选项重新编译
# 配置
autoindex on | off;	#自动文件索引功能,默为off
autoindex_exact_size on | off; # 是否计算确切文件大小,默认off显示 k,m,g
autoindex_localtime on | off ; # 显示本机时间
autoindex_format html | xml | json | jsonp; #索引界面风格
limit_rate 100k; #传输速率限制
# 注意此处的location格式
location /download {
        root   /data/test;
        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
    }

9.11 状态页

需要ngx_http_stub_status_module模块
location = /status {
        stub_status;
    }
# 信息说明
Active connections: #当前处于活动状态的客户端连接数,包括连接等待空闲连接数 =reading+writing+waiting
accepts:#统计总值,Nginx自启动后已经接受的客户端请求的总数。
handled:#统计总值,Nginx自启动后已经处理完成的客户端请求总数,通常等于accepts,除非有因worker_connections限制等被拒绝的连接
requests:#统计总值,Nginx自启动后客户端发来的总的请求数。
Reading:#当前状态,正在读取客户端请求报文首部的连接的连接数,数值越大,说明排队现象严重,性能不足
Writing:#当前状态,正在向客户端发送响应报文过程中的连接数,数值越大,说明访问量很大
Waiting:#当前状态,正在等待客户端发出请求的空闲连接数,开启 keep-alive的情况下,这个值等于 active – (reading+writing)

9.12 第三方模块使用

# git clone
git clone https://github.com/openresty/echo-nginx-module.git
# 编译时加上--add-module=源码路径
--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 --without-http_autoindex_module --add-module=./echo-nginx-module
# 配置
location = /echo {
        index index.html;
        default_type text/html;
        echo "hello world,main-->";
        echo $remote_addr ;
        echo_reset_timer;
        echo "took $echo_timer_elapsed sec for total.";
    }

9.13 nginx变量

9.13.1 内置变量

$remote_addr; #存放了客户端的地址,注意是客户端的公网IP
$proxy_add_x_forwarded_for #将客户端IP追加请求报文中X-Forwarded-For首部字段,多个IP之间用逗号分隔,如果请求中没有X-Forwarded-For,就使用$remote_addr
$args; # URL中的参数
$document_root; # 当前请求系统资源的根目录路径
# limit_rate = 10240
$limit_rate; #如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有设置, 则显示0
$remote_port; # 客户端与nginx发生通信的端口
$remote_user; # 进过账号密码验证的用户名
$request_body_file; #反向代理请求后端资源名称
$request_method; #请求资源的方式,GET,POST等
$request_filename; # 请求资源的磁盘路径绝对路径
$request_uri; #请求参数的原始路径不包括主机
$scheme; # 请求协议
$server_protocol; # 使用的http协议版本
$server_addr; #服务器ip地址
$server_name; # 服务器主机名
$server_port; # 服务器端口号
$http_<name> # name可以是请求报文的首部字段
例子:
	$http_user_agent; # 用户访问的代理
# 配置
location = /echo {
        index index.html;
        default_type  application/json;
        echo_reset_timer;
        echo "hello world,main-->";
        echo "remote_addr" $remote_addr;
        echo "args" $args;
        echo "document_root" $document_root;
        echo "limit_rate" $limit_rate;
        echo "remote_port" $remote_port;
        echo "remote_user" $remote_user;
        echo "request_body_file" $request_body_file;
        echo "request_method" $request_method;
        echo "request_filename" $request_filename;
        echo "request_uri" $request_uri;
        echo "scheme" $scheme;
        echo "server_protocol" $server_protocol;
        echo "server_addr" $server_addr;
        echo "server_name" $server_name;
        echo "server_port" $server_port;
        echo "http_user_agent" $http_user_agent;
        echo "took $echo_timer_elapsed sec for total.";
    }

# 测试
(base) gu@python:~/destop/github$ curl 172.31.3.112:81/echo
hello world,main-->
remote_addr 172.31.3.1
args 
document_root /apps/nginx/html
limit_rate 0
remote_port 48218
remote_user 
request_body_file 
request_method GET
request_filename /apps/nginx/html/echo
request_uri /echo
scheme http
server_protocol HTTP/1.1
server_addr 172.31.3.112
server_name pc
server_port 81
http_user_agent curl/7.87.0
took 0.001 sec for total.

9.13.2 自定义变量

# 格式
set $variable value;
# 定义位置
server, location, if
# 配置
location = /echo {
        set $name guquanheng;
        set $age 18;
        ......
        echo "name" $name;
        echo "age" $age;
        echo "http_user_agent" $http_user_agent;
        echo "took $echo_timer_elapsed sec for total.";
    }
# 测试
hello world,main-->
remote_addr 172.31.3.1
......
name guquanheng
age 18
http_user_agent Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
took 0.000 sec for total.

9.14 自定义日志格式(json)

# 简单来说就是将各种信息通过封装成json格式然后显示
# 配置日志格式
vim nginx.conf
log_format access_json
'{"@timestamp":"$time_iso8601",'
'"host":"$server_addr",'
'"clientip":"$remote_addr",'
'"size":$body_bytes_sent,'
'"responsetime":$request_time,'
'"upstreamtime":"$upstream_response_time",'
'"upstreamhost":"$upstream_addr",'
'"http_host":"$host",'
'"uri":"$uri",'
'"xff":"$http_x_forwarded_for",'
'"referer":"$http_referer",'
'"tcp_xff":"$proxy_protocol_addr",'
'"http_user_agent":"$http_user_agent",'
'"status":"$status"}';
# 定义日志路径和日志格式名称 
access_log /apps/nginx/logs/access_json.log access_json;

9.15 压缩功能

针对指定类型进行压缩传输,增加负载,节省带宽
依赖于模块 ngx_http_gzip_module
https://nginx.org/en/docs/http/ngx_http_gzip_module.html
可以配置在http,server,location
gzip on | off; # 启用或禁用压缩
gzip_comp_level level; # 指定压缩比1-9
gzip_min_length 1k; # 小于多少不会被压缩
gzip_http_version 1.0 | 1.1; # 启用压缩后通信协议的最小版本
gzip_buffers number size; # 指定向服务器进行申请缓存的数量和大小 比如32个 4k页
gzip_types mime-type; # 指定针对那些资源进行压缩,写入mime-type
gzip_vary on ;# 开启压缩后在响应报文头部加入字段“Vary: Accept-Encoding” 

9.16 HTTPS实现

基于ngx_http_ssl_module模块
配置在 http 和 server
https://nginx.org/en/docs/http/ngx_http_ssl_module.html
# 配置
vim nginx.conf
ssl on # 开启ssl协议
listen 443 ssl; # 指定监听端口
ssl_certificate /path # 指定cert证书路径
ssl_certificate_key /path/to/file; # 指定key文件
ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2]; # 指定协议版本
# 配置ssl缓存
ssl_session_cache off | none | [builtin[:size]] [shared:name:size];
	off: #关闭缓存
	none:	#通知客户端支持ssl session cache,但实际不支持
	builtin[:size]:#使用OpenSSL内建缓存,为每worker进程私有[shared:name:size]:#在各worker之间使用一个共享的缓存,需要定义一个缓存名称和缓存空间大小,一兆可以存储4000个会话信息,多个虚拟主机可以使用相同的缓存名称
ssl_session_timeout time; # 缓存有效期,默认5m

9.17 openssl版本升级

# ssl协议由于版本问题存在漏洞,需要升级到对应版本
1、下载openssl源码
wget https://www.openssl.org/source/old/3.1/openssl-1.1.1w.tar.gz
2、重新编译安装,指定openssl源码路径
--with-openssl=
# 编译
./configure --with-http_random_index_module --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=./echo-nginx-module --with-openssl=/usr/local/src/openssl-1.1.1w
# 安装
make -j 2 && make install 
# 验证
nginx -V
nginx version: nginx/1.20
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.1.1w  11 Sep 2023
TLS SNI support enabled
configure arguments: --with-http_random_index_module --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=./echo-nginx-module --with-openssl=/usr/local/src/openssl-1.1.1w

9.18 Rewrite

# 对url进行重写,当改变网站结构后不需要进行对外的改变,让客户可以无感访问
# 依赖与pcre库,ngx_http_rewrite_module模块
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
配置在server和location块

9.18.1 if 指令

# 格式,当条件为真值表达式时,执行指定动作
if (条件匹配) {
	action
}
# 条件匹配
= 	#变量和给定字符串判断是否一致
!=
~ # 使用正则匹配(大小写敏感)
!~
~* # 使用正则匹配(大小写不敏感)
!~*
-f # 判断请求的文件是否存在
!-f 
-d # 判断目录是否存在
-x # 判断文件是否具有执行权限
!-x
-e # 判断文件目录和软连接是否存在
# action
location = /main {
        if ($remote_addr = 172.31.3.111){
            return 456;
        }       
   	}
# 测试
[root@nexus ~]# curl 172.31.3.112:81/main -I
HTTP/1.1 456 
Server: nginx/1.20
Date: Fri, 22 Dec 2023 02:50:57 GMT
Content-Length: 0
Connection: keep-alive

9.18.2 set指令

参考9.13变量使用

9.18.3 break指令

# 编程中用于中断当前循环,nginx配置中,用于中断当前作用域(location中的rewrite配置指令)
# 例子
location = /echo {
        set $name guquanheng;
        echo "name" $name;
        break; # 后面的set命令将不会执行
        set $age 18;
        echo "age" $age;
        index index.html;
        default_type  application/json;
        echo_reset_timer;
        echo "hello world,main-->";
        echo "remote_addr" $remote_addr;
        echo "args" $args;
        echo "document_root" $document_root;
        echo "limit_rate" $limit_rate;
        echo "remote_port" $remote_port;
        echo "remote_user" $remote_user;
        echo "request_body_file" $request_body_file;
        echo "request_method" $request_method;
        echo "request_filename" $request_filename;
        echo "request_uri" $request_uri;
        echo "scheme" $scheme;
        echo "server_protocol" $server_protocol;
        echo "server_addr" $server_addr;
        echo "server_name" $server_name;
        echo "server_port" $server_port;
        echo "http_user_agent" $http_user_agent;
        echo "took $echo_timer_elapsed sec for total.";
    }
# 测试
[root@nexus ~]# curl 172.31.3.112:81/echo
name guquanheng # name有输出
age 			# age没有输出
hello world,main-->
remote_addr 172.31.3.111
args 
document_root /apps/nginx/html
limit_rate 0
remote_port 16427
remote_user 
request_body_file 
request_method GET
request_filename /apps/nginx/html/echo
request_uri /echo
scheme http
server_protocol HTTP/1.1
server_addr 172.31.3.112
server_name pc
server_port 81
http_user_agent curl/7.29.0
took 0.000 sec for total.

9.18.4 return指令

# 编程中直接退出当前函数并返回结果,nginx中将直接返回状态码,后续所有配置将不再执行
# 格式
return code;
return code text;
return code URL;
# 配置
location = /echo {
        set $name guquanheng;
        echo "name" $name;
        return 345 "byebye"; # 退出并返回byebye字符
        set $age 18;
        echo "age" $age;
        index index.html;
        default_type  application/json;
        echo_reset_timer;
        echo "hello world,main-->";
        echo "remote_addr" $remote_addr;
        echo "args" $args;
        echo "document_root" $document_root;
        echo "limit_rate" $limit_rate;
        echo "remote_port" $remote_port;
        echo "remote_user" $remote_user;
        echo "request_body_file" $request_body_file;
        echo "request_method" $request_method;
        echo "request_filename" $request_filename;
        echo "request_uri" $request_uri;
        echo "scheme" $scheme;
        echo "server_protocol" $server_protocol;
        echo "server_addr" $server_addr;
        echo "server_name" $server_name;
        echo "server_port" $server_port;
        echo "http_user_agent" $http_user_agent;
        echo "took $echo_timer_elapsed sec for total.";
    }
# 测试
[root@nexus ~]# curl 172.31.3.112:81/echo -v
* About to connect() to 172.31.3.112 port 81 (#0)
*   Trying 172.31.3.112...
* Connected to 172.31.3.112 (172.31.3.112) port 81 (#0)
> GET /echo HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 172.31.3.112:81
> Accept: */*
> 
< HTTP/1.1 345 
< Server: nginx/1.20
< Date: Fri, 22 Dec 2023 03:05:48 GMT
< Content-Type: application/json
< Content-Length: 6
< Connection: keep-alive
< 
* Connection #0 to host 172.31.3.112 left intact
byebye

9.18.5 rewrite_log指令

# 是否开启rewrite模块的日志
rewrite_log on; # 开启后会记录在error日志中,日志级别需要设置为notice

9.18.6 rewrite指令

# 通过正则匹配来对url进行操作
# 格式
rewrite regex replacement  [flag];
# 重写完成后的操作
[flag]
	redirect; # 临时重定向
	permanent; # 永久重定向
	break; # 跳出当前配置,跳转到重写后的url配置块,仅适用于一次重写
	last; # 结束当前配置的规则,重新对重写url进行重写检查,可以多次重写,注意不要重写太多次

9.19 盗链和防盗链

9.19.1 盗链

# 在页面插入其他网站的链接,当访问时会加载其他网站的信息
# 配置
<html>
<head>
<meta http-equiv=Content-Type content="text/html;charset=utf-8">
<title>盗链</title>
</head>
<body>
<img src="http://172.31.3.112:81/meihualu.jpg" >
<h1 style="color:red">hello</h1>
</body>
</html>

9.19.2 防盗链

通过ngx_http_referer_module模块实现
配置在server和location
# 格式
valid_referers none blocked server_names
               *.example.com example.* www.example.org/galleries/
               ~\.google\.;
# 配置
server_name  pc.quanheng.com;
valid_referers none blocked server_names
        *.quanheng.com ~\.jpg\. ;
if ($invalid_referer){
    return 403 "Forbidden Access";
}

10、负载均衡

10.1 七层负载

10.1.1 参数配置

# 配置在location,需要开启ngx_http_upstream_module模块
1、proxy_pass http://172.31.3.112:81; # 后端主机,支持ip:port,主机名,以及主机群组
# 示例
location  /image {
        proxy_pass http://172.31.3.112:81; # 最后面不带 / 则此url为 http://172.31.3.112:81/image
        # proxy_pass http://172.31.3.112:81/download/; # 表示转发的url本身http://172.31.3.112:81/download/
    }
若location 匹配使用正则 那么proxy_pass后面的url不能带/ 
location  ~|~* /image {
        proxy_pass http://172.31.3.112:81; # 必须使用此方式
    }
2、proxy_hide_header {field}; # 作为反向代理,客户端访问时隐藏后端服务的头部信息
3、proxy_pass_header {field}; # 声明将后端服务器的首部字段传递
4、proxy_pass_request_body on | off; #是否向后端换发http的body部分
5、proxy_pass_request_headers on | off;#是否转发请求头部信息
6、proxy_set_header; # 更改头部信息
# 示例
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for X-Real-IP $remote_addr;
7、proxy_connect_timeout time; # 与后端服务建立连接的超时时间,超时报504
8、proxy_read_timeout time;# 发起read请求后的超时时间
9、proxy_send_timeout time; # write请求发起时间
10、proxy_http_version 1.0; # 代理服务的协议通信版本
11、proxy_ignore_client_abort off; # 客户段中断请求,立即中断与后端的请求

10.1.2 缓存设置

1、proxy_cache zone_name | off; 默认off # 指明缓存配置
zone_name # 使用proxy_cache_path配置
proxy_cache_path
/data/nginx/proxycache # 缓存的保存路径
inactive=120s # 缓存有效时间
levels=1:1:2 # 目录层次结构 1代表2^4 2代表2^8 1:1:2可以生成2^4x2^4x2^8=2^16=65536个目录
keys_zone=proxycache:20m # #指内存中缓存的大小,主要用于存放key和metadata
max_size=1g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值
2、proxy_cache_key string; # 缓存中用于键的设置
proxy_cache_key $scheme$proxy_host$request_uri; # 默认
3、proxy_cache_valid [code ...] time; # 针对状态码响应内容的缓存时间
proxy_cache_valid 404 1m;
proxy_cache_valid any 1m; #除了定义的状态的其余时间
4、proxy_cache_methods GET | HEAD | POST ...; # 针对那些方法进行缓存

10.1.3 添加响应首部字段

# 后端服务器响应给客户端的报文中添加指定的响应首部字段
依赖ngx_http_headers_module模块
示例:
add_header X-Via $server_addr; #当前nginx主机的IP
add_header X-Cache $upstream_cache_status; #是否缓存命中
add_header X-Accel $server_name; #客户访问的FQDN

10.1.4 upstream模块

10.1.4.1 定义后端服务

# 定义一组后端服务器,名称为back_test1,里面是后端服务列表
upstream back_test1 {
	server .....
	......
}
# 示例
upstream back_test1 {
	# 主机名称支持fqdn,ip:port
	server backend1.example.com weight=5 reslove; # 可以指定权重 reslove表示当域名的ip变化时自动使用新ip不用重启服务
	server 127.0.0.1:8080 max_fails=3 fail_timeout=30s; #对后端服务器的检测失败次数和检测超时时间
	server unix:/tmp/backend3; max_conns=1 # 最大活动连接数
	server backup1.example.com backup; # 设为备份服务器,当所有服务器不可用启用此服务器
	server 172.31.3.1 down; # 下线此服务器
	hash KEY [consistent]; # 指定一个key 进行hash	consistent表示使用一致性hash运算
	hash $request_uri consistent; # 以用户的请求url做hash运算
	ip_hash; # 源地址哈希
	least_conn; # 最小连接算法
} 

10.1.4.2 使用

# 配置
location  /image {
        proxy_pass http://back_test1;
    }

10.2 四层负载

用lvs吧

11、参数优化

11.1 内核参数

fs.file-max = 1000000
#表示单个进程较大可以打开的句柄数
net.ipv4.tcp_tw_reuse = 1
#参数设置为 1 ,表示允许将TIME_WAIT状态的socket重新用于新的TCP链接,这对于服务器来说意义重
大,因为总有大量TIME_WAIT状态的链接存在
net.ipv4.tcp_keepalive_time = 600
#当keepalive启动时,TCP发送keepalive消息的频度;默认是2小时,将其设置为10分钟,可更快的清理无
效链接
net.ipv4.tcp_fin_timeout = 30
#当服务器主动关闭链接时,socket保持在FIN_WAIT_2状态的较大时间
net.ipv4.tcp_max_tw_buckets = 5000
#表示操作系统允许TIME_WAIT套接字数量的较大值,如超过此值,TIME_WAIT套接字将立刻被清除并打印警
告信息,默认为8000,过多的TIME_WAIT套接字会使Web服务器变慢
net.ipv4.ip_local_port_range = 1024 65000
#定义UDP和TCP链接的本地端口的取值范围
net.ipv4.tcp_rmem = 10240 87380 12582912
#定义了TCP接受缓存的最小值、默认值、较大值
net.ipv4.tcp_wmem = 10240 87380 12582912
#定义TCP发送缓存的最小值、默认值、较大值
net.core.netdev_max_backlog = 8096
#当网卡接收数据包的速度大于内核处理速度时,会有一个列队保存这些数据包。这个参数表示该列队的较大值
net.core.rmem_default = 6291456
#表示内核套接字接受缓存区默认大小
net.core.wmem_default = 6291456
#表示内核套接字发送缓存区默认大小
net.core.rmem_max = 12582912
#表示内核套接字接受缓存区较大大小
net.core.wmem_max = 12582912
#表示内核套接字发送缓存区较大大小
注意:以上的四个参数,需要根据业务逻辑和实际的硬件成本来综合考虑
net.ipv4.tcp_syncookies = 1
#与性能无关。用于解决TCP的SYN攻击
net.ipv4.tcp_max_syn_backlog = 8192
#这个参数表示TCP三次握手建立阶段接受SYN请求列队的较大长度,默认1024,将其设置的大一些可使出现Nginx繁忙来不及accept新连接时,Linux不至于丢失客户端发起的链接请求
net.ipv4.tcp_tw_recycle = 1
#这个参数用于设置启用timewait快速回收
net.core.somaxconn=262114
#选项默认值是128,这个参数用于调节系统同时发起的TCP连接数,在高并发的请求中,默认的值可能会导致链接超时或者重传,因此需要结合高并发请求数来调节此值。
net.ipv4.tcp_max_orphans=262114
#选项用于设定系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤立链接将立即被复位并输出警告信息。这个限制指示为了防止简单的DOS攻击,不用过分依靠这个限制甚至认为的减小这个值,更多的情况是增加这个值

11.2 pam

/etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
posted on   要快乐不要emo  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示