Nginx
- Nginx 基础
- Nginx 环境搭建
- Nginx 基础概念
- Nginx 配置文件结构
- Nginx 配置文件通用语法
- nginx.conf 常用配置
- 虚拟主机配置 - server
- 日志文件 - log_format、access_log
- 日志文件切分
- 资源路径匹配 - location
- 全局变量
- 反向代理配置 - proxy_pass
- 负载均衡配置 - upstream
- 动静分离
- 对于静态资源的压缩处理 - gzip
Java 从 0 到架构师目录:【Java从0到架构师】学习记录
Nginx 基础
Nginx 官网:http://nginx.org/
网络请求分为动态请求和静态请求:
- 动态请求:需要后台程序处理逻辑,比如查询数据库数据
- 静态请求:请求一些觉得资源(html、css、js、png …)
Nginx:网络静态资源服务器,只能处理静态请求
Tomcat:可以处理动态请求 + 静态请求
Tomcat 默认最多支持 150 并发,Nginx 官网给出数据最多支持 5w 并发
Tengine,淘宝网基于 Nginx 开发的服务器
代理:
- 正向代理:例如访问 YouTube,国内正常无法直接访问,需要通过一些代理软件,绕过国内的防火墙才能访问,这些软件就是正向代理(代理客户端)
- 反向代理:YouTube 的后台有很多服务器,当用户访问的时候,YouTube 将用户的请求交给后台 N 台服务器中的一台来做,这就是反向代理(代理服务器)
更多网络相关的知识参考:网络协议从入门到底层原理 - 代理
常见的负载均衡策略:
- 使用硬件进行负载均衡,例如:F5、Array 等负载均衡器
- 使用软件进行负载均衡,例如:Nginx,Tengine
- 使用阿里云负载均衡 SLB
- 使用 Nginx + Keepalived
- 其他软件负载均衡,如:LVS (Linux Virtual Server)、HAProxy 等技术
Nginx 的优点:
- Nginx 可以在大多数 Unix Linux OS 上编译运行,并有 Windows 移植版
- Nginx 是开源免费的
- Nginx 能够支持高达 50000 个并发连接数的响应
Tomcat 默认在 300 个左右
- …
Nginx 环境搭建
Nginx 官网:http://nginx.org/,下载安装包
# 下载需要的依赖库文件
yum install pcre -y
yum install pcre-devel -y
yum install zlib -y
yum install zlib-devel -y
# 解压安装包
tar -zxvf nginx-1.18.0.tar.gz -C /usr/local/src
# 进行configure配置,查看是否报错
cd /usr/local/src/nginx-1.18.0
./configure --prefix=/usr/local/nginx
# 编译安装
make && make install
注意:如果出现这个错误
./configure: error: C compiler cc is not found
执行这个命令:yum -y install gcc gcc-c++ autoconf automake make
Nginx 相关操作:
# 启动命令
/usr/local/nginx/sbin/nginx
# 关闭命令
/usr/local/nginx/sbin/nginx -s stop
# 重启命令
/usr/local/nginx/sbin/nginx -s reload
# 重新生成日志文件
/usr/local/nginx/sbin/nginx -s reopen
# 查看端口
netstat -ano | grep 80
访问浏览器:http://192.168.52.128
在 /usr/local/nginx 目录下,可以看到如下 4 个目录:
- conf 配置文件
- html 网页文件
- logs 日志文件
- sbin 主要二进制程序
Nginx 基础概念
在 Nginx 中会启动 Master 和 Worker 两种进程
Master 进程的主要工作:
- 接收客户端的请求
- 向 Worker 进程发送信号
- 监控 Worker 进程的状态
- 当 Worker 进程退出以后,会自动启动新的 Worker 进程
Worker 进程的主要工作:处理客户端的连接
在配置文件中可以配置:
# 配置 Worker 进程的数量与 CPU 内核有关系
worker_process 2;
Nginx 配置文件结构
main:全局设置,设置的指令将影响其他所有设置
- events
- http
- upstream:上游服务器设置,用于负载均衡,设置一系列的后端服务器
- server:虚拟主机设置,主要用于指定特定的主机和端口
- location:URL 匹配特定位置的设置,用于匹配网页的位置
server 继承 main,location 继承 server,upstream 既不会继承其他设置也不会被继承
Nginx 配置文件通用语法
Nginx 通用语法:
- 配置文件由“指令”(
;结尾的语句
)和“指令块”({}
)构成 - 每条指令以分号
;
结尾,指令和参数之间用空格符号进行分割 - 每条指令块以大括号
{}
将多条指令组织在一起 -
include
语句允许组合多个配置文件以提升可维护性 - 使用
#
符号添加注释,提高可读性 - 使用
$
符号引用变量 - 部分指令的参数支持正则表达式
nginx.conf 常用配置
虚拟主机配置 - server
# nginx虚拟主机配置
server {
listen 80; # 监听端口
server_name localhost; # 一般写域名(1个IP对应多个域名)
# 寻找资源的路径
location / {
root html; # 相对路径,nginx目录下的html目录
index index.html index.htm; # 默认访问的页面
}
}
日志文件 - log_format、access_log
nginx 访问日志放在 logs/access.log 下,并且使用 main 格式(支持自定义格式)
# 对于main格式配置如下
# 日志文件输出格式这个位置相当于全局设置
# log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
# access_log logs/host.access.log main;
tail -n 100 -f access.log # 查看日志内容命令
日志文件切分
系统运行起来之后,我们需要对 nginx 日志进行分析,得到响应耗时的 url,请求时间,以及这段时间的请求量和并发量,通过分析找到优化系统的方案;所以需要运维人员对 nginx 的日志进行切割和分析处理,我们会通过定时器定时将日志按 天/小时 进行备份。
实现定时备份日志思路:
- 第一步:分析如何去实现日志切分,编写 shell 脚本
- 第二步:定时任务对脚本进行调度
1、日志备份脚本 backuplog.sh,放在 sbin 目录下
#!/bin/sh
BASE_DIR=/usr/local/nginx
BASE_FILE_NAME=access.log
CURRENT_PATH=$BASE_DIR/logs
BAK_PATH=$BASE_DIR/datalogs
CURRENT_FILE=$CURRENT_PATH/$BASE_FILE_NAME
BAK_TIME=`/bin/date -d yesterday +%Y%m%d%H%M`
BAK_FILE=$BAK_PATH/$BAK_TIME-$BASE_FILE_NAME
mv $CURRENT_FILE $BAK_FILE
$BASE_DIR/sbin/nginx -s reopen
2、执行定时任务调度:crontab -e */1 * * * * sh /usr/local/nginx/sbin/backuplog.sh
注意:将脚本从 Windows 拷贝到 Linux,执行脚本的时候可能会出现
$'\r': command not found
,需要转换一下格式:yum install dos2unix -y
、dos2unix 脚本文件
资源路径匹配 - location
语法规则: location [=|~|~*|^~] /uri/ { … }
= 开头表示精确匹配
^~ 开头表示uri以某个常规字符串开头,理解为匹配url路径即可
nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)
~ 开头表示区分大小写的正则匹配
~* 开头表示不区分大小写的正则匹配
/ 通用匹配,任何请求都会匹配到
多个location配置的情况下匹配顺序为:
= ---> ^~ ---> ~/~* ---> /
匹配案例:
- 例如有以下匹配规则:
location = / {
# 规则A
}
location = /login {
# 规则B
}
location ^~ /static/ {
# 规则C
}
location ~ \.(gif|jpg|png|js|css)$ {
# 规则D
}
location ~* \.png$ {
# 规则E
}
location / {
# 规则H
}
- 匹配效果:
http://localhost/ # 规则A
http://localhost/login # 规则B
http://localhost/register # 规则 H
http://localhost/static/a.html # 规则 C
http://localhost/a.gif # 规则 D
http://localhost/b.jpg # 规则 D
http://localhost/static/c.png # 规则 C
http://localhost/a.PNG # 规则 E
http://localhost/a.xhtml # 规则 H
实际应用配置:
# 直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理
# 这里是直接转发给后端应用服务器了,也可以是一个静态首页
# 第一个必选规则
location = / {
proxy_pass http://192.168.52.128:9999/index;
}
# 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
# 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}
# 第三个规则就是通用规则,用来转发动态请求到后端应用服务器
# 非静态文件请求就默认是动态请求,自己根据实际把握
# 毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了
location / {
proxy_pass http://tomcat:8080/
}
全局变量
$args #请求中的参数值
$query_string #同 $args
$arg_NAME #GET请求中NAME的值
$is_args #如果请求中有参数,值为"?",否则为空字符串
$uri #请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如"/foo/bar.html"。
$document_uri #同 $uri
$document_root #当前请求的文档根目录或别名
$host #优先级:HTTP请求行的主机名>"HOST"请求头字段>符合请求的服务器名
$hostname #主机名
$https #如果开启了SSL安全模式,值为"on",否则为空字符串。
$binary_remote_addr #客户端地址的二进制形式,固定长度为4个字节
$body_bytes_sent #传输给客户端的字节数,响应头不计算在内;这个变量和Apache的mod_log_config模块中的"%B"参数保持兼容
$bytes_sent #传输给客户端的字节数
$connection #TCP连接的序列号
$connection_requests #TCP连接当前的请求数量
$content_length #"Content-Length" 请求头字段
$content_type #"Content-Type" 请求头字段
$cookie_name #cookie名称
$limit_rate #用于设置响应的速度限制
$msec #当前的Unix时间戳
$nginx_version #nginx版本
$pid #工作进程的PID
$pipe #如果请求来自管道通信,值为"p",否则为"."
$proxy_protocol_addr#获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串
$realpath_root #当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径
$remote_addr #客户端地址
$remote_port #客户端端口
$remote_user #用于HTTP基础认证服务的用户名
$request #代表客户端的请求地址
$request_body #客户端的请求主体:此变量可在location中使用,将请求主体通过proxy_pass,fastcgi_pass,uwsgi_pass和scgi_pass传递给下一级的代理服务器
$request_body_file #将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off,uwsgi_pass_request_body off,or scgi_pass_request_body off
$request_completion #如果请求成功,值为"OK",如果请求未完成或者请求不是一个范围请求的最后一部分,则为空
$request_filename #当前连接请求的文件路径,由root或alias指令与URI请求生成
$request_length #请求的长度 (包括请求的地址,http请求头和请求主体)
$request_method #HTTP请求方法,通常为"GET"或"POST"
$request_time #处理客户端请求使用的时间; 从读取客户端的第一个字节开始计时
$request_uri #这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI,不包含主机名,例如:"/cnphp/test.php?arg=freemouse"
$scheme #请求使用的Web协议,"http" 或 "https"
$server_addr #服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中
$server_name #服务器名
$server_port #服务器端口
$server_protocol #服务器的HTTP版本,通常为 "HTTP/1.0" 或 "HTTP/1.1"
$status #HTTP响应代码
$time_iso8601 #服务器时间的ISO 8610格式
$time_local #服务器时间(LOG Format 格式)
$cookie_NAME #客户端请求Header头中的cookie变量,前缀"$cookie_"加上cookie名称的变量,该变量的值即为cookie名称的值
$http_NAME #匹配任意请求头字段;变量名中的后半部分NAME可以替换成任意请求头字段,如在配置文件中需要获取http请求头:"Accept-Language",$http_accept_language即可
$http_cookie #cookie 信息
$http_post
$http_referer #引用地址
$http_user_agent #客户端代理信息
$http_x_forwarded_for#相当于网络访问路径。
$sent_http_NAME #可以设置任意http响应头字段;变量名中的后半部分NAME可以替换成任意响应头字段,如需要设置响应头Content-length,$sent_http_content_length即可
$sent_http_cache_control
$sent_http_connection
$sent_http_content_type
$sent_http_keep_alive
$sent_http_last_modified
$sent_http_location
$sent_http_transfer_encoding
反向代理配置 - proxy_pass
# 配置反向代理
# proxy_pass url;
proxy_pass http://192.168.52.128:8080;
# 注意: 反向代理之后,获取客户端ip地址为nginx服务器地址
# 这里需要nginx进行forward,设置真实的ip地址:
# 设置客户端真实ip地址
proxy_set_header x-real-ip $remote_addr;
负载均衡配置 - upstream
# 设定负载均衡的服务器列表在Server模块配置
# upstream myproject {
# weigth 参数表示权值,权值越高被分配到的几率越大
# max_fails 当有max_fails个请求失败,就表示后端的服务器不可用,默认为1,将其设置为0可以关闭检查
# fail_timeout 在以后的fail_timeout时间内nginx不会再把请求发往已检查出标记为不可用的服务器
# }
upstream p2p {
ip_hash;
server 192.168.11.130:8888 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.11.194:8888 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.11.225:8888 weight=1 max_fails=2 fail_timeout=30s;
}
location / {
proxy_pass http://p2p;
}
负载均衡的配置:
- Round Robin 轮询,默认值
- Least Connections 最少连接数
- IP Hash 将客户端请求的 IP 进行 Hash 运算
- Generic Hash 自定义 Hash 的一个取值
- Random 随机发送
负载均衡可能会引起 session 丢失的问题:nginx 在处理转发到不同的后台服务器的时候,session 可能存储在 A 服务器,但是用户发送的请求却发到 B 服务器,从而没有权限进行操作
以上问题的解决方案是:
- 方案一:对于同一个客户端的请求,直接由指定的服务器处理
例如使用 IP_Hash 规则,对客户端的 ip 进行处理,保证同一个 ip 由同一个服务器处理 - 方案二:使用 Redis + Token 作为分布式 Session 解决方案
动静分离
第一步:把静态资源存放到 nginx 可以访问的目录
第二部:配置静态资源的目录
# 静态资源访问地址, \.是转义
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
root /datas/crm/static/;
}
# 动态请求访问地址
location / {
proxy_pass http://localhost:8080;
}
对于静态资源的压缩处理 - gzip
满足的条件:
- 客户端发送的 HTTP 报头必须含有
Accept-Encoding
字段,且其值包含gzip
这个压缩类型
一般浏览器都会发Accept-Encoding:gzip, deflate, sdch
这样的报头 - 服务器启用了 gzip 压缩,那么响应头会包含
Content-Encoding:gzip
,客户端根据这个来判断服务器返回的内容是否为 gzip 压缩过的内容
# 开启gzip压缩
gzip on;
# 文件达到多大开始压缩
gzip_min_length 1k;
# 压缩级别(1-9),级别越高,越消耗cpu,默认值为1
gzip_comp_level 2;
# 压缩文件的类型, 对于jpg,png图片压缩效率不高
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript;
# 根据客户端的HTTP头来判断,是否需要解压缩
gzip_vary on;
效果:开启压缩后,原本 70k 的 js 资源被压缩为 18k
gzip 对文本压缩效果很好,对图片压缩效果差一点