Nginx 学习
Nginx 介绍
Nginx是一个高性能的HTTP、反向代理服务器;主要功能:①反向代理 ②实现集群和负载均衡③ 静态资源虚拟化。
什么是代理
正向代理
正向代理可以理解为「客户端」的代理

反向代理
反向代理可以理解为「服务器」的代理

Nginx 下载与安装
1.下载源代码手动编译安装(推荐),下载Nginx包,官网下载地址:http://nginx.org/en/download.html

- 使用FTP工具将文件上传到虚拟机中
- 解压Nginx包,并安装
tar -zxvf nginx-1.21.6.tar.gz #解压到当前目录
cd nginx-1.21.6 #进入解压后的文件夹
ls
#文件夹中的文件:auto CHANGES.ru configure html man src CHANGES conf contrib LICENSE README- 安装依赖库
#安装C编译器
yum install -y gcc
#安装pcre库PVEL
yum install -y pcre pcre-devel
#安装zlib
yum install -y zlib zlib-devel- 编译安装
./configure --prefix=/usr/local/nginx # 指定编译选项,--prefix选项指定安装的目录
make # 编译
make install # 安装编译结果- 创建软连接(可以直接使用nginx命令,不会出现-bash: nginx: command not found错误)
ln -s /usr/local/nginx/sbin/nginx /usr/local/bin #实际路径根据自己的情况确定- 放开防火墙80端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --reload # 开放或者关闭端口需要重启防火墙Nginx 目录
Nginx一般安装在/usr/local/nginx目录下(安装时--prefix可指定安装目录)

conf #配置文件
|-nginx.conf # 主配置文件
|-其他配置文件 # 可通过那个include关键字,引入到了nginx.conf生效
html #静态页面
logs(默认不是放在这里,可以在配置文件中修改为这里)
|-access.log #访问日志(每次访问都会记录)
|-error.log #错误日志
|-nginx.pid #进程号
sbin
|-nginx #主进程文件
*_temp #运行时,生成临时文件Nginx进程模型
Master 进程和Work 进程

Master 进程的作用
启动和关闭服务: master 进程负责启动和关闭 Nginx 服务。它读取并解析配置文件,启动 worker 进程。
管理 Worker 进程: master 进程管理所有的 worker 进程,监控它们的运行状态。它会在 worker 进程异常退出或终止时,自动重启新的 worker 进程,以保持服务的正常运行。
信号处理: master 进程处理外部信号,如重载配置、平滑升级和停止服务等信号。根据接收到的信号,master 进程会执行相应的操作,如重新加载配置文件或优雅地关闭服务。
Work 进程的作用
处理请求: worker 进程负责处理客户端的请求。每个 worker 进程是等价的,能够独立处理请求。通过这种方式,Nginx 能够并行处理大量的客户端请求,提高了服务的并发处理能力。
异步非阻塞模式: worker 进程采用异步非阻塞的方式处理请求,通过事件驱动机制,高效地 处理大量的并发连接。
共享内存: worker 进程之间通过共享内存机制共享部分数据,例如缓存、限速等数据,保证各 worker 进程之间的数据一致性。
Work 进程数量设置
要设置 Nginx 的 worker 进程数量,可以在 Nginx 的配置文件中进行配置。通常情况下,worker 进程的数量由服务器的 CPU 核心数来确定,以充分利用服务器的硬件资源,提高性能。
打开 Nginx 的配置文件,通常位于 /etc/nginx/nginx.conf。在配置文件中找到 worker_processes 指令。这是设置 worker 进程数量的地方。
worker_processes auto;
//#auto 表示让 Nginx 自动根据系统的 CPU 核心数来确定 worker 进程数量。Master关系和Work和协作

- 独立处理请求: 每个 worker 进程独立于其他 worker 进程,处理自己的客户端请求。这种设计避免了进程间的锁争用,提高了性能和处理效率。
- Master-Worker 模式: master 进程负责全局管理和控制,worker 进程负责实际的请求处理工作。这种模式有效地分离了控制和工作职责,使得 Nginx 既能高效地处理请求,又能灵活地管理进程。
- 负载均衡: master 进程在启动时创建多个 worker 进程,操作系统负责将客户端请求均匀分配给这些 worker 进程,实现了负载均衡。
Worker的抢占机制
多个worker进程争抢一个锁,获取锁的进程进行响应

Worker事件处理机制
传统HTTP服务器是同步处理,当多个客户端请求时,如果Client1的请求被阻塞,Master会fork新的worker进程处理
但是Nginx采用的是异步非阻塞方式,如果Client1的请求被阻塞,worker会取处理下一个请求,不会阻塞当前worker进程。所以Nginx的一个worker进程可以并发处理大量请求

Nginx 配置
Nginx 配置文件详情
//# master进程会启动worker进程,该选项设置在系统中显示启动该进程的用户名(一般不改动,默认nobody)
//# user nobody
//# 启动的worker进程数
worker_processes 1;
//# 错误日志放置的路径 notice、info是错误日志的级别,比如:info就是日志级别大于info才生成日志
//# 默认地址为/var/log/nginx/error.log ,可通过nginx -V返回的--eror-log-path字段获取实际值
//#error_log logs/error.log;
//#error_log logs/error.log notice;
//#error_log logs/error.log info;
//# pid文件存放路径,默认:/var/run/nginx/nginx.pid,可通过nginx -V返回的--pid-path字段获取实际值
//#pid logs/nginx.pid;
//# 配置事件处理方式、worker最大连接数
events {
use epoll; //# 使用epoll事件处理机制(默认值)
worker_connections 1024; //# 每个worker进程处理的最大连接数
}
//# http模块配置
http {
include mime.types; //#include是引入关键字,这里引入了mime.types这个配置文件的内容(同在conf目录下,mime.types是用来定义,请求返回的content-type)
default_type application/octet-stream; //#mime.types未定义的,使用默认格式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"';
//# 访问日志地址,默认:/var/log/nginx/access.log,可通过nginx -V返回的--http-log-path字段获取实际值
//#access_log logs/access.log main;
//# 详见下文
sendfile on;
// #tcp_nopush on;
keepalive_timeout 65; //# TCP链接超时时间,单位秒
//# 压缩相关,详见下文
gzip on; //# 开启压缩,压缩后发送给客户端
//# 详见下文
server {
//xxx
}
}sendfile配置
打开sendfile,用户请求的数据不用再加载到nginx的内存中,而是直接发送
高负载的场景下,使用 sendfile 功能可以降低 CPU 和内存的占用,提升服务器性能
http{
sendfile:on # off
}
//# 或者指定某个server开启
server {
location / {
sendfile off;
...
}
}gzip配置
http{
gzip on; //# 开启压缩,压缩后发送给客户端
gzip_min_length 1;//# 设置最小压缩下限。1就是小于1字节的文件不压缩
gzip_comp_level 3 //# 压缩级别0-9,值越大文件就压缩的越小,相应的会损耗更多性能
gzip_type text/plain application/javascript image/* # 指定哪些 MIME 类型,开启压缩(不写默认全部),可以使用通配符 image/* 就是所有图片。具体哪些类型可以看conf/mime.types文件
}nginx 中的 gzip 压缩分为动态压缩、静态压缩
动态压缩:
- 服务器给客户端返回响应时,消耗自身的资源进行实时压缩,保证客户端拿到 gzip 格式的文件
- gzip on开启的就是动态压缩,gzip_comp_level设置的级别高,可能会造成CPU占用过高
静态压缩:
- 直接将预先压缩过的 .gz 文件返回给客户端,不再实时压缩文件,如果找不到 .gz 文件,会使用对应的原始文件
- 该功能需要模块: ngx_http_gzip_static_module(默认不会被构建);通过下面命令查看,当前安装的是否包含该模块
javanginx -V
如果不包含,需要重新编译Nginx
java./configure --with-http_gzip_static_module //# 指定编译配置,这个参数安装模块 ngx_http_gzip_static_module make # 编译 make install # 安装包含该模块,则可以启用下面配置
javahttp{ gzip_static on; gzip_proxied expired no-cache no-store private auth; }
server配置
虚拟主机配置(可以启用多个),多个server字段,会根据请求的域名+端口从前向后匹配
用户访问bk.zuoyou.space(注意:需要解析到当前Nginx的这台机器),请求会匹配到下面的配置中
http {
//#....其他属性
server {//# server 规则可以有多个,每个对应 一个域名+端口的组合
access_log logs/bk.zuoyou.space-access.log //# 访问日志字段也可以设置在Server中,命中该Server的请求日志都在这里
listen 80; //# 端口
server_name bk.zuoyou.space; //# 域名,可以有多个值,用空格分隔。支持通配符,例如:*.example.org 。
//# server_name bk.zuoyou.space default_server; #default_server表示当Nginx接收的请求没有能匹配上的server,就命中设置了default_server
//# 域名+端口 匹配上了,就会走这里的映射(映射规则可以有多个)
//# 【类型1】
//# / 路径的映射配置,这个映射比较特殊,无论用户请求的是什么路径,只要没有被更具体的 location 块匹配到,就都会命中 location /。即 bk.zuoyou.space:80 会命中这里
location / {
//# root指定当前这个server的根路径为 html/pro(注意root字段如果是相对路径很特殊:是相对于nginx的安装目录,即这里html与conf目录同级)
root html/pro;
//# 当命中/路径时的首页,nginx会在root目录下找index.html、index.htm并返回
index index.html index.htm;
}
//# 【类型2】
//# 一般请求用root
//# bk.zuoyou.space:80/abc、bk.zuoyou.space:80/abc/1 都会命中这条规则
//# 例如: bk.zuoyou.space:80/abc/ 会返回首页,即index字段(root目录下查找index指定的文件)
//# 例如: bk.zuoyou.space:80/abc/1/index.html 返回的是机器上的home/abc/1/index.html (实际机器路径为:root+【请求命中路径-全部路径结尾,例如:/abc/1/index.html】)
location /abc {
root /home;
index index.html index.htm;
}
//# 【类型3】
//# 一般静态文件会用alias
//# /images/ 路径的映射配置,即 bk.zuoyou.space:80/images/xx会命中这里,实际请求路径为:/var/www/images/xxx。对比root字段,如果下面的alias替换为root字段,则实际请求路径为/var/www/images/images/xxx,这显然是错误的
//# 注意尾斜杠,bk.zuoyou.space:80/images不能命中
location /images/ {
//# alias设置请求的别名,用于替换文件系统路径。
alias /var/www/images/;
}
//# 反向代理,proxy_pass将请求代理到指定的后端服务器。
location /api/ {
proxy_pass http://backend_server;
}
//# 服务器错误码为500 502 503 504,转到"域名/50x.html"
error_page 500 502 503 504 /50x.html;
//# 【类型4】使用=代表精确匹配
//# 只有访问 bk.zuoyou.space.ltd:80/50x.html才能命中这条规则
location = /50x.html {
root html;
}
//# 【类型5】使用正则匹配
//# '~',例子:location ~ { xxx },表示匹配所有路径
//# '~(空格)正则' ,例子:~ \.(png|gif) 匹配png、gif的路径
//# '~*(空格)正则',不区分大小写,例子:~ *\.(png|gif) 匹配png、PNG、gif、GIF等路径
//# '^~(空格)字符串' ,表示匹配以字符串开头的请求,例子:^~ /test,即 bk.zuoyou.space:80/test/xxx可以命中
location ~*\.(png|gif) { //#因为忽略大小写,所以 bk.zuoyou.space:80/a.PNG 可以命中规则
root /home;
}
}
server {
//# xxxx
}
}server配置在单独文件维护
新建配置文件zuoyou.conf,在server配置放在一个独立文件维护
server {
//# xxxx
}
server {
//# xxxx
}在http中引入server配置
http{
include zuoyou.conf
}通过server_name,实现不同域名,映射到同一静态页面
- 可以写多个,用空格分开
- 使用通配符(*)
- 使用正则表达式
http{
server {
listen 80;
server_name *.zuoyou.space.ltd ~^[0-9]+\.zuoyou\.ltd$; # "\."是转译"."
location / {
root html/test;
index index.html index.htm;
}
}
}日志切割
Nginx长期运行会产生大量日志,如果不开启日志切割,出现问题很难通过日志排查,需要借助crontabs设置定时任务
默认的日志路径
# 错误日志地址:--eror-log-path=/var/log/nginx/error.log
# 请求日志地址:--http-log-path=/var/log/nginx/access.log(每一个请求就记录一个日志)- 安装crontabs
yum install crontabs- crontabs 常用命令
service crond start //启动服务
service crond stop //关闭服务
service crond restart //重启服务
service crond reload //重新载入配置
crontab -e // 编辑任务
crontab -l // 查看任务列表
service crond status //查看服务状态- 常见的表达式
*/1 * * * * #每分钟执行一次
59 23 * * * #每天23:59分执行一次
0 1 * * * #每天凌晨一点执行一次
* 23,00-07/1 * * * #当天23点,第二天0点到凌晨7点 每隔1分钟执行一次- 设置定时任务以及添加任务
crontabs -l # 查看全部定时任务
crontabs -e # 添加定时任务(打开一个文件)
* */1 * * * * /usr/local/nginx/sbin/cut_log.sh # 每隔1分钟执行一次,其中,cut_log.sh自己写的切割脚本
#!/bin/bash
LOG_FILE="/var/log/nginx/access.log"
DATE=$(date +"%Y-%m")
BACKUP_FILE="/var/log/nginx/access.${DATE}.log"
# 检查当前月份是否已更改,如果已更改,则备份日志文件并创建一个新的日志文件
if [[ ! -e "$BACKUP_FILE" ]]; then
mv "$LOG_FILE" "$BACKUP_FILE"
touch "$LOG_FILE"
chown nginx:nginx "$LOG_FILE" # 确保 Nginx 用户有权写入新的日志文件
chmod 640 "$LOG_FILE" # 设置适当的文件权限
/etc/init.d/nginx reload # 重新加载 Nginx 配置,确保日志文件句柄更新
fi重启crontabs配置才会生效
service cornd restart反向代理与负载均衡概念
反向代理:这种代理方式叫做,隧道代理。有性能瓶颈,因为所有的数据都经过Nginx,所以Nginx服务器的性能至关重要

负载均衡:把请求,按照一定算法规则,分配给多台业务服务器(即使其中一个坏了/维护升级,还有其他服务器可以继续提供服务)

Nginx实现反向代理
负载均衡配置
单台主机代理
使用proxy pass关键字实现负载均衡代理,使用该关键字之后root和index字段就会失效
- 当请求命中了这条规则,会被转发到目标服务器地址
http{
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://xxx; # 参数是 http://server_name
}
}
}- 路径 + 参数会被一起转发
假设Nginx机器的地址为:http://www.xxx.com
请求 http://www.xxx.com/test?a=1
会被 proxy_pass地址/test?a=1- 重写需求: 例如只有api前缀的才转发到后台服务器,但是接口并不包含api路径
location / {
rewrite ^/api/(.*) $1
proxy_pass http://xxx; # 参数是 http://server_name
}反向代理集群
Nginx实现负载均衡集群,例如将请求代理到192.168.174.133:80和192.168.174.134:80这两个服务
http{
upstream test_server{ # 参数是server_name
server 192.168.174.133:80; #如果是80端口,可以省略不写
server 192.168.174.134:80;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://test_server;
}
}
}- 设置权重,多个请求,Nginx会根据权重分配
upstream test_server{
server 192.168.174.133:80 weight=10;
server 192.168.174.134:80 weight=80;
}- 关闭down,server设置成down,如果server只剩下这一台,必须使用down的server
upstream test_server{
server 192.168.174.133:80 down;
server 192.168.174.134:80;
}- 慢启动(商业版本才用这个配置)
upstream test_server{
server 192.168.174.133:80 slow_start=60s; # Nginx会在60的时间内,慢慢分配流量从0到正常值
server 192.168.174.134:80;
}- 备用机,backup的这个机器正常是不会被访问到,如果192.168.174.133:80出现故障,无法提供服务,才会自动启用
upstream test_server{
server 192.168.174.133:80 ;
server 192.168.174.134:80 backup;
}- 失败重试
upstream test_server{
# 失败次数超过max_fail后,Nginx在fail_timeout时间内将不会转发任何请求给这个服务,超过fail_timeout后会在尝试一次。成功则恢复转发,否则仍然fail_timeout时间,再次尝试
server 192.168.174.133:80 max_fail=2 fail_timeout=10s;
server 192.168.174.134:80 ;
}负载均衡算法
IP_hash
对用户的ip进行计算:Hash(IP)%upstream_node_count,返回要使用机器的索引;每一个用户会固定分配到一台机器,防止在A机器上创建Session的用户,后续被分配到其他机器,导致Session失效。
开启ip_hash后,如果想要移除一台server,必须使用down配置。如果直接删除,会导致upstream_node_count变化,使得所有用户访问的访问的机器发生变化
缺点
- 增加服务节点会导致upstream_node_count变化,进而导致所有用户访问的机器变化
- 某个用户短时间发起大量请求,会打到一台固定的机器,导致这台机器性能大幅下降,而其他机器可能还是空闲
upstream test_server{
# 开启ip_hash,
ip_hash;
server 192.168.174.133:80;
server 192.168.174.134:80;
}一致性哈希算法(Consistent Hashing)
一致性哈希算法解决了使用ip_hash,在新增、删除服务节点时,所有用户访问节点发生变化的问题;hash函数返回值的范围是[0,2^32-1] 节点IP计算哈希,用户IP计算哈希,用户分配的节点是其右侧的第一个节点,增加、减少服务节点,只会影响一小部分用户,而不是全部. 
# consistent不加使用的就是普通hash算法
upstream test_server{
hash $request_uri consistent; # 基于请求的uri做一致性哈希
hash $remote_addr consistent; # 基于请求的全部32为IPv4地址做一致性哈希(ip_hash只对IPv4的前24位做哈希)
hash $cookie_xxx consistent; # 基于请求cookie中的xxx字段做一致性哈希
server 192.168.174.133:80;
server 192.168.174.134:80;
}最少连接数(least_conn)
尽可能将请求转发到当前连接数最少的后端服务器
upstream test_server{
least_conn;
server 192.168.174.133:80;
server 192.168.174.134:80;
}下面例子,开启least_conn,Nginx会优先转发到Tomcat3 
动静分离
动静分离是将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,之所以要进行动静分离,其一为了提高前端的响应速度,其二就是为了将动态请求和静态请求进行分别部署,后端各个服务各司其职,提高处理性能。适用于中小型项目(将静态资源放在nginx服务器上)
静 :前端项目(静态资源) 动:接口服务
location ~ .*\.(gif|jpg|pdf|jpeg|png)$ {
expires 8h;
root /nginx/data/image;
}
location~ .*\.(html)$ {
root /nginx/data/html;
}
#拦截后台请求,正则匹配 api 路径
location ~* ^/(lb){
# 配置代理地址
proxy_pass http://myserver;
}URL重写
rewrite需要写正则比较复杂,所以目前使用return的比较多
return
把Http重定向为Https
server {
listen 80;
server_name bk.zuoyou.space;
location / {
return 302 https://bk.zuoyou.space$request_uri
# 302是状态码
# $request_uri是路径和参数 ,例如:/xxx/xx?xx=xx
}
}rewrite
rewrite是URL重写的关键指令,根据regex(正则表达式)部分内容,重定向到replacement,结尾是flag标记。
rewrite <regex> <replacement> [flag];
关键字 正则 替代内容 flagt标记
正则:per1森容正则表达式语句进行规则匹配
替代内容:将正则匹配的内容替换成replacement
flag标记说明:
last #本条规则匹配完成后,继续向下匹配新的1ocation URI规则
break #本条规则匹配完成即终止,不再匹配后面的任何规则
redirect #返回302临重定向,游览器地址会显示跳转后的URL地址
permanent #返回301永久重定向,测览器地址栏会显示跳转后的URL地址把Http重定向为Https
server {
listen 80;
server_name bk.zuoyou.space;
location / {
rewrite ^/(.*) https://bk.zuoyou.space/$1 redirect;
# 匹配到uri的/后的内容,并放到$1中,执行重定向
proxy_pass http://xxx;
}
}配置Https证书
- 申请域名证书

- ssl证书下载

下载后,解压压缩包,可以看到两个文件,一个是 xxx.key(私钥)和xxx.pem(证书)
注:我自己解压的文件中一共有4个文件,分别是 xxx.key(私钥)和xxx.pem(证书),还有xxx.crt和xxx.csr
- 安装ssl模块 ssl配置依赖于ngx_http_ssl_module模块
#查看是否有 --with-http_ssl_module 表示
./nginx -V
#没有需要重新编译安装
./configure --prefix=/usr/local/nginx --with-http_ssl_module # 指定编译选项
make # 编译
make install # 安装编译结果--with-http_ssl_module- 修改配置文件
将两个文件上传到Nginx目录中,记得放置的位置。建议直接放在nginx.conf配置文件所在的目录(/etc/nginx/conf),所以写的都是相对路径
注意:ssl配置可以放在http模块(所有server都开启ssl)、server模块(当前server开启)
http{
server {
listen 443 ssl;
server_name zuolong.space;
# 这里是证书路径
ssl_certificate xxx.pem;
# 这里是私钥路径
ssl_certificate_key xxx.key
location / {
# xxx
}
}
# 如果通过http访问,重定向到https
server {
listen 80;
server_name zuolong.space;
location / {
return https://www.zuolong.space$request_uri #$request_uri是路径+参数,例如:/xxx/xx?xx=xx
}
}
}