nginx经常挂在嘴边的就是反向代理,不过他还可以干很多事,我所了解的只是反向代理、静态文件缓存、静态资源服务器,对于负载均衡只是略有涉及。
Nginx (“engine x”) 是一个高性能的 HTTP 和 反向代理 服务器 ,也是一个 IMAP/POP3/SMTP 代理 服务器 。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名
引用一下菜鸟教程的简介:Nginx功能丰富,可作为HTTP服务器,也可作为反向代理服务器,邮件服务器。支持FastCGI、SSL、Virtual Host、URL Rewrite、Gzip等功能。并且支持很多第三方的模块扩展。Nginx的稳定性、功能集、示例配置文件和低系统资源的消耗让他后来居上,在全球活跃的网站中有12.18%的使用比率,大约为2220万个网站。
特点
(1):代理服务器,快速高效反向代理,提升网站性能。
(2):负载均衡器,内部支持Rails和PHP,也可支持HTTP代理服务器,对外进行服务。同时支持简单容错和利用算法进行负载均衡。
(3):性能方面,Nginx专门为性能设计,实现注重效率。采用Poll模型,可以支持更多的并发连接,并在大并发时占用很低内存。
(4):稳定性方面,采用分阶段资源分配技术,使CPU资源占用率低。
(5):高可用性方面,支持热备,启动迅速。
nginx安装
mac 下安装
brew install nginx
安装目录为 /usr/local/Cellar/nginx/1.17.2/
配置文件目录为 /usr/local/etc/nginx/nginx.conf
服务器默认路径 /usr/local/var/www
常用命令
mac 下的启动命令
-
启动
nginx
-
快速停止关闭
nignx -s stop
-
优雅的关闭
nginx -s quit
-
承载配置文件
nginx -s reload
-
查看nginx进程
ps -ef | grep nginx
-
查看配置文件是否正确
nginx -t
-
优雅的杀死nginx进程
kill -quit 进程号
-
快速的杀死nginx进程
kill -term 进程号
nginx配置
nginx 文件的默认配置文件位置 /usr/local/etc/nginx/nginx.conf
打开 /usr/local/etc/nginx/
目录可以看到,里面有很多的配置文件,启动有一个nginx.conf
和 nginx.conf.default
两个配置文件,刚开始安装的时候,两个文件的内容是一样的,所以我们可以肆意的修改nginx.conf
搞崩的话就直接把nginx.conf.default
中的内容复制过来就行了又是一个新的nginx。
配置文件架构
// nginx全局块 ... // events块 events { ... } // http 块 http { // http全局块 ... // server块 server { ... } // http全局块 ... }
配置文件加注释说明
# 配置nginx的用户组 默认为nobody #user nobody; # 配置nginx的主线程数量 nginx是一个主线程下面多个子线程 worker_processes 1; # 配置nginx的错误日志 格式为 log路径 log级别 # error_log 的日志级别为: debug info notice warn error crit alert emerg 紧急由低到高 # error_log的默认日志级别为error,那么就只有紧急程度大于等于error的才会记录在日志 # error_log 的作用域为 main http mail stream server location #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; # 指定nginx进程运行文件存放地址 #pid logs/nginx.pid; events { # poll是多路复用IO中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能 # use poll # 设置网络的连接序列化 防止惊群现象发生 默认为 on # accept_mutex on; # 设置一个进程是否同时接受多个网络连接 默认为 off # multi_accept off # 最大连接数 默认为 512 worker_connections 1024; } 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"'; // 允许通过日志配置 #access_log logs/access.log main; # sendfile 指定使用 sendfile 系统调用来传输文件。优点在于在两个文件描述符之间传递数据(完全在内核中操作),从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,效率高,称之为零拷贝,这个东西有点讲究,自行百度 # sendfile 作用域 location server http sendfile on; #tcp_nopush on; # 链接超时时间 默认 75s 作用域 http server location #keepalive_timeout 0; keepalive_timeout 65; # 开始gzip压缩 #gzip on; server { # 端口号 listen 8080; # 域名或ip server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; # 对请求的路由进行过滤 正则匹配 location / { root html; index index.html index.htm; } ... } include servers/*; }
nginx 日志
nginx的日志大致分为 access_log
和 error_log
。error_log 记录的是nginx的错误日志。(以下对日志的理解不是很全面,还只是基础的)
error_log
- 记录nginx错误日志
- 作用域为
main http mail stream server location
- 日志级别
debug info notice warn error crit alert emerg
- 日志级别默认为 error 当级别高于或等于指定级别时才会记录
access_log
- 记录请求通过的日志
- 作用域为
http server location limit_except
- 日志格式默认为
combined
- 日志格式是可以自定义的
# 定义一个为 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/access.log main;
上方的 log_format
后面类似 $remote_addr
是nginx的内置变量,取值如下
$remote_addr, $http_x_forwarded_for(反向) 记录客户端IP地址 $remote_user 记录客户端用户名称 $request 记录请求的URL和HTTP协议 $status 记录请求状态 $body_bytes_sent 发送给客户端的字节数,不包括响应头的大小; 该变量与Apache模块mod_log_config里的“%B”参数兼容。 $bytes_sent 发送给客户端的总字节数。 $connection 连接的序列号。 $connection_requests 当前通过一个连接获得的请求数量。 $msec 日志写入时间。单位为秒,精度是毫秒。 $pipe 如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。 $http_referer 记录从哪个页面链接访问过来的 $http_user_agent 记录客户端浏览器相关信息 $request_length 请求的长度(包括请求行,请求头和请求正文)。 $request_time 请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。 $time_iso8601 ISO8601标准格式下的本地时间。 $time_local 通用日志格式下的本地时间。
反向代理
正向代理 反向代理
- 正向代理大概的意思就是,客户端发送一个请求,这个请求包含服务器地址,那么代理服务器收到了请求后会将请求发送到客户端指定的服务器,并将响应内容传递给客户端,在这个过程中,客户端是知道请求的服务器地址的,但是服务器是不知道哪个客户端请求的。VPN做的就是这个事。
- 反向代理大概的意思就是,客户端发送一个请求给代理服务器,由代理服务器来决定这个请求该交给哪个服务器,这就是实现了服务器负载均衡,可以将请求转发到比较空闲的服务器来响应,这个时候,代理服务器就是相对于客户端的服务器,因为此时客户端也不知道请求交给了哪个服务器。
我所理解的正向代理和反向代理就是这个意思,如有错误欢迎下方评论。
proxy_pass
那么nginx使用的就是proxy_pass
属性来进行反向代理的处理,使用也是很简单。下面以nodejs开启一个建立在 localhost:4000 的服务
const http = require('http'); http.createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('server 4000'); }).listen(4000);
请求 localhost:4000
可以打开我们的页面
那么我们需要做的是将 localhost:5000
的所有请求都代理到4000这个server里,这样就会出现我们访问5000和访问4000一样的效果。具体配置如下
server { # 监听 localhost:5000 listen 5000; server_name localhost; # / 表示匹配所有的请求,所有的请求都会经过这个过滤器 location / { # 设定请求转发的地址 proxy_pass http://localhost:4000; } }
这边需要注意的是 proxy_pass
的写法,必须是http://
或者https://
开头的,http头是不能省的。
请求5000端口效果如下:
本地代理至百度
上方的例子过于简单,那么这一个和上面的有点类似,这次是将4000的端口号代理到www.baidu.com
。修改一下proxy_pass
server { # 监听 localhost:5000 listen 5000; server_name localhost; # / 表示匹配所有的请求,所有的请求都会经过这个过滤器 location / { # 设定请求转发的地址 proxy_pass https://www.baidu.com; } }
这样就可以了,至于这边写的是http
还是 https
,这个倒是不影响,因为百度内部会自动将http
转成https
毕竟安全嘛。
百度代理至本地
那么按照刚刚的思路就是监听 www.baidu.com
然后设置一下 proxy_pass
为 localhost:4000
配置如下
server { listen 80; server_name www.baidu.com; location / { proxy_pass http://localhost:4000; } }
试一下,是不是没有用,没有用就对了。要是这么轻松的搞定nginx
还玩个蛋。那么这个里面又有点操作了,先看正确的配置,修改本地的hosts文件,mac下的文件位置为 /etc/hosts
但是需要 sudo 来进行修改,毕竟这个文件比较重要嘛
sudo vim /etc/hosts
添加一句
server { listen 80; server_name baidu.com; location / { proxy_pass http://127.0.0.1:4000; } }
一般在本地开发的时候我们都会修改本地的hosts
文件,但是会遇到一个问题就是有的时候是有用的有的时候又没用了,我这边的解决办法是,每次修改完hosts
文件就清楚浏览器的浏览数据,尤其是缓存这一块的东西。
如果遇到nginx配置完全正确hosts
文件也配置了,但是还是没有用,不妨清一下缓存,至少在我这是每次都是清完缓存才有用的。
nginx跨域
跨域的解决办法就是在header
里面加上允许跨域的源等信息
location / { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; if ($request_method = 'OPTIONS') { return 204; } }
但是在实际项目里。origin
还是不要设置为*
比较好,因为前端使用axios的话在获取session这一块会出现问题。
nginx缓存
这边有一个需要注意的地方,nginx作为静态资源服务器的时候是不做缓存的,只有当nginx进行反向代理的时候才具备缓存这个功能。我一开始写了半天发现鸟用都没有,最后才发现只有做代理的时候才具备缓存。
各大浏览器本身已经具有缓存了,比如说谷歌,我们可以写一个html,然后在html引入一张图片,我们可以看看浏览器是怎么对图片这些静态资源进行缓存的。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <img src="./static/test.jpg" alt=""> </body> </html>
这个html代码我使用http-server
部署在了http-server -a 127.0.0.1 -p 4000
可以看出是在127.0.0.1 4000
端口。
这是首次加载的时候的状况
刷新一下
那么区别还是很大的
html
文件的状态码从200到304,304状态码表明该文件是从缓存中读取jpg
文件可以发现在size
这一列,多了一个memory cache
,这表明这个图片是从浏览器缓存中读取的- 各个文件的加载事件明显减少,尤其是图片
可能有的人会发现第一次加载的时候,显示的是from desk cache
,那么chrome浏览器的缓存分为两种,一种是磁盘缓存一种是内存缓存,
官方文档:
Chrome employs two caches — an on-disk cache and a very fast in-memory cache. The lifetime of an in-memory cache is attached to the lifetime of a render process, which roughly corresponds to a tab. Requests that are answered from the in-memory cache are invisible to the web request API. If a request handler changes its behavior (for example, the behavior according to which requests are blocked), a simple page refresh might not respect this changed behavior. To make sure the behavior change goes through, call handlerBehaviorChanged() to flush the in-memory cache. But don’t do it often; flushing the cache is a very expensive operation. You don’t need to call handlerBehaviorChanged() after registering or unregistering an event listener.
大概意思就是:chrome有两种缓存,一种是desk cache
一种是memory cache
,然后memory cache
的效率高于前者。
那么打开chrome devtools点开图片可以发现
在cache-control
后面有一个max-age
,那么具体的有关缓存的技术这边就不说了我回头整理一下
那么针对不同类型的文件进行缓存还是很简单的,需要注意的在于location
的正则匹配
那么第一种最简单的缓存,就是直接设置expires 缓存时间
设置expires
location ~ .*\.(jpg|png)$ { proxy_pass http://127.0.0.1:4000; expires 3m; }
expires
是以秒为单位的,那么我们设置为3m
也就是180秒,发现确实是可以的。
proxy_cache_path 的使用
那么我们也可以指定我们的nginx缓存目录,通过proxy_cache_path 属性
proxy_cache_path /tmp/cache/test levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off; location ~ .*\.(jpg|png)$ { proxy_pass http://127.0.0.1:4000; proxy_cache my_cache; proxy_cache_valid 200 304 1y; proxy_cache_valid any 1m; expires 1y; }
- proxy_cache_path 执行缓存文件的目录,如果没有的话需要提前创建,不然nginx会报错
- levels 采用2级目录来存储
- key_zone 在共享内存中设置一块存储区域来存放缓存的key和metadata(类似使用次数),这样nginx可以快速判断一个request是否命中或者未命中缓存,1m可以存储8000个key,10m可以存储80000个key
- max_size 最大cache空间,如果不指定,会使用掉所有disk space,当达到配额后,会删除最少使用的cache文件
- inactive 未被访问文件在缓存中保留时间,在指定时间内未被访问的文件会被删除
- use_temp_path 如果为off,则nginx会将缓存文件直接写入指定的cache文件中,而不是使用temp_path存储,official建议为off,避免文件在不同文件系统中不必要的拷贝;
- proxy_cache 启用proxy cache,对应着配置的key_zone;
- proxy_cache_valid 根据不同的状态码设置不同的缓存时间
可以查看一下nginx
进程,会发现这个时候是有缓存的进程在开着的。
这边可以看到,我们的图片的缓存时间已经被设置为1年
location匹配优先级
在缓存中需要注意的一点就是location的匹配规则和优先级
- = 开头表示精确匹配
- ^~ 开头表示uri以某个常规字符串开头,不是正则匹配;
- ~ 开头表示区分大小写的正则匹配;
- ~* 开头表示不区分大小写的正则匹配;
- / 通用匹配, 如果没有其它匹配,任何请求都会匹配到;
upstream负载均衡
负载均衡是nginx的另一大特点,可以配置多个服务器,将请求分发到最合适的那台服务器,避免某一台服务器请求太多而崩溃。使用upstream
属性来配置
upstream favtomcat { server 192.168.1.100:4000; server 192.168.1.111:5000; } location / { root html; index index.html index.htm; # 对应上方的 favtomcat proxy_pass http://favtomcat; }
这是最基础的负载均衡配置,采用的是轮询
的策略进行负载,每个请求按时间顺序逐一分配到不同的后端服务器,适用于图片服务器集群和纯静态页面服务器集群。
优点: 方式简便、成本低廉
缺点: 可靠性低和负载分配不均衡
那么upstream
还有其他的负载策略
weight权重
可以给每一台服务器设置一个权重,这样权重高的干的活也就会多一点
upstream favtomcat { server 192.168.1.100:4000 weight=5; server 192.168.1.111:5000 weight=10; }
ip_hash
这种方式是基于客户端的ip地址,采用hash算法计算下一个请求要选择哪一个服务器,这样固定的ip会访问同一个服务器,可以解决session问题
upstream favtomcat { ip_hash; server 192.168.1.100:4000; server 192.168.1.111:5000; }
least_conn最少链接
会将下一个请求分发到当前链接数最少的一台服务器
upstream favtomcat { least_conn; server 192.168.1.100:4000; server 192.168.1.111:5000; }
fair
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream favtomcat { fair; server 192.168.1.100:4000; server 192.168.1.111:5000; }
url_hash
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器
upstream backserver { server squid1:3128; server squid2:3128; hash $request_uri; hash_method crc32; }
参考
https://juejin.im/post/59f94f626fb9a045023af34c;
Nginx Proxy Cache原理和最佳实践
来源:https://blog.csdn.net/qq_38606793/article/details/100046413