一、简介
Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,提供了反向代理和负载均衡等功能。
1、正向代理
正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。
2、反向代理
以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器
3、负载均衡
负载均衡服务器(load-balancing server)是进行负载分配的服务器。
通过负载均衡服务器,将服务请求均衡分配到实际执行的服务器中,从而保证整个系统的响应速度。
具体如何分配取决于负载均衡算法。
例如:A\B\C三个服务器是一个集群环境,都能提供 W 服务,如果有一个客户端 X 需要访问 W 服务,会访问 Nginx , 由Nginx决定该客户端实际访问 A\B\C中的哪一个服务。
二、安装
1、Centos
2、Docker
3、测试
打开浏览器,访问 IP
安装成功
Nginx 代理的是80端口,
可以通过配置,让nginx代理其他端口
三、Nginx常用命令
命令 | 作用 |
---|---|
nginx | 启动nginx |
nginx -s stop | 关闭nginx |
nginx -s reload | 重启nginx |
nginx -v | 查看版本号 |
四、配置文件
1、配置文件位置
配置文件位置为/usr/local/nginx/conf/nginx.conf
对于Docker - Nginx : /etc/nginx/nginx.conf
2、配置文件结构
#配置nginx的运行用户,nginx将以配置的用户身份运行nginx、访问目录或文件 #user nobody; #进程数量,在后面nginx配置优化部分详细讲解 worker_processes 1; #日志文件以及对应的等级,等级与等级关系参考 log4j #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #nginx 线程id的文件 #pid logs/nginx.pid; events { # 最大连接数 worker_connections 1024; } # 配置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"'; # 访问日志文件 #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; # 配置反向代理 server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }
清理注释后
3、真正结构
五、反向代理
1、概念
Nginx 反向代理,可以代理其他的服务器或者为静态资源(html,css,js,图片,...)提供http服务。合在一起,就是所谓的动静分离。
将动态的(JavaWeb项目) 和 静态资源 分别进行代理
2、配置监听IP和端口
nginx 可以监听服务器的多个端口,通过 server
配置项来配置对于某个端口的监听。
server { listen 80; server_name localhost; }
listen 可以直接配置端口号,也可以配置 IP + 端口号。
如果为端口号, server_name 为被监听服务器名称,
如果为IP+端口, server_name 失效。
3、配置请求路径
使用 location 配置url的映射。
location [=|^~|~|~*] /uri/ { }
-
=
开头表示精确匹配location = /a {}
只能匹配 /a , 不能匹配 /a/b -
^~
开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。location ^~ /a {}
匹配所有以 /a 开头的请求 -
~
开头表示区分大小写的正则匹配location ~ \.(gif|jpg|png|js|css)$ {}
不能匹配 GIF -
~*
开头表示不区分大小写的正则匹配location ~* \.(gif|jpg|png|js|css)$ {}
能匹配 GIF -
!~
和!~*
分别为区分大小写不匹配及不区分大小写不匹配 的正则 -
/
通用匹配,任何请求都会匹配到。
4、静态资源访问
4-1 上传静态资源到Nginx
将web页面上传至Nginx服务器的某个文件夹下:
-
物理上传(FTP)
-
Docker
-
Dockerfile: add
-
docker-compose: volumn
-
4-2 配置location
4-2-1 alias
别名,用于请求路径的替换操作
location /web { alias /a/b/; }
/web/top.png => /a/b/top.png
注意:
alias值一定以 / 结尾
alias不能用在正则匹配中,如果必须用,必须配合rewrite和root使用
4-2-2 root
根,作为路径前缀使用
location /web { root /a/b/; }
/web/top.png => /a/b/web/top.png
alise 会删除 location 后的uri部分,root 不会删除 location 后的uri部分
root 路径会比 alise 路径多一层
4-2-3 index
location /i/ { alias /spool/w3/images/; index index.html index.htm }
当访问 /i/ 的时候,默认访问 index.html, 如果index.html 不存在,访问 index.htm
4-2-4 其他静态资源
图片、视频等
5、动态服务访问
5-1 配置方式
server{ # 监听80端口 listen 80; # 当请求地址为/serverA , 访问 http://192.168.137.138:8080 # 例如 nginx-server/serverA/a/b/c -> http://192.168.137.138:8080/serverA/a/b/c location /serverA { proxy_pass http://192.168.137.138:8080; } }
5-2 跨域配置
location /serverA { 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'; proxy_pass http://192.168.137.138:8080; }
六、负载均衡
1、负载均衡概念
1-1 集群
集群就是单机的多实例,在多个服务器上部署多个服务,每个服务就是一个节点,部署N个节点,处理业务的能力就提升 N倍(大约),这些节点的集合就叫做集群。单机就是把做的系统部署到一台服务器上,所有的请求业务都由这台服务器处理。
1-2 分布式
分布式结构就是将一个完整的系统,按照业务功能,拆分成一个个独立的子系统,在分布式结构中,每个子系统就被称为“服务”。这些子系统能够独立运行在web容器中,它们之间通过RPC方式通信。
1-3 负载均衡
SLB Server Load Balance
/ LB Load Balance
(服务器)负载均衡。负载均衡(Load Balancer)是指把用户访问的流量,通过负载均衡器(Nginx),根据某种转发的策略,均匀的分发到后端多台服务器上,后端的服务器可以独立的响应和处理请求,从而实现分散负载的效果。负载均衡技术提高了系统的服务能力,增强了应用的可用性。
2、定义集群
#定义集群 upstream demo{ server 192.168.137.137:9998; server 192.168.137.137:9997; } server{ listen 8080; server_name localhost; location / { proxy_pass http://demo; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
3、负载均衡策略
3-1 轮询
最基本的配置方法,它是upstream的默认策略,每个请求会按时间顺序逐一分配到不同的后端服务器。
配置参数
-
在轮询中,如果服务器down掉了,会自动剔除该服务器。请求不再发送给该服务器,但是间隔一段时间周期后(fail_time),会再次尝试该服务器。
-
缺省配置就是轮询策略。
-
此策略适合服务器配置相当,无状态且短平快的服务使用。
upstream foo { server localhost:80019; server localhost:8002; server localhost:8003 backup; server localhost:8004 max_fails=3 fail_timeout=20s; }
3-2 权重
在轮询策略的基础上制定沦陷的几率。例如
upstream foo { server localhost:8001 weight=2; server localhost:8002; server localhost:8003 backup; server localhost:8004 max_fails=3 fail_timeout=20s; }
这里例子中,weight参数用于制定轮询的几率,weight默认值为1;
weight的数值和被访问的几率成正比。
此策略比较适合服务器的硬件配置差别比较大的情况。
3-3 ip_hash
负载均衡器按照客户端IP地址的分配方式,可以确保相同客户端的请求一直发送到相同的服务器。这样每个访客都固定访问一个后端服务器。
upstream foo { ip_hash; server localhost:8001 weight=2; server localhost:8002; server localhost:8003; server localhost:8004 max_fails=3 fail_timeout=20s; }
在nginx版本1.3.1之前,不能在ip_hash中使用权重(weight)。
ip_hash不能与backup同时使用。
此策略适合有状态服务,比如session。
当有服务器需要剔除,必须手动down掉。
3-4 least_conn 最小连接
把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果
upstream foo { least_conn; server localhost:8001 weight=2; server localhost:8002; server localhost:8003 backup; server localhost:8004 max_fails=3 fail_timeout=20s; }
此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况。
七、限流
1、概念
限流(rate limiting) 用于限制某个用户在一个给定时间段内能够产生的HTTP请求数。请求可以简单到就是一个对于主页的GET请求或者一个登陆表格的POST请求。
限流可以:
-
用于安全目的上,通过限制请求速度来防止外部暴力扫描,或者减慢暴力密码破解攻击,可以结合日志标记出目标URL来帮助防范DDoS攻击,
-
可以解决流量突发的问题(如整点活动)
一般地说,限流是用在保护下游应用服务器不被在同一时刻的大量用户请求湮没。
2、限流实现方式
-
直接拒绝
# 拒绝 IP 为 1.2.3.4 的服务器请求 location / { deny 1.2.3.4; }
-
控制速率:让请求匀速通过Nginx,访问目标服务
-
控制并发连接数:削减连接的数量(10W -> 2W)
3、限流算法
Nginx为我们提供了请求限制模块(ngx_http_limit_req_module
)、基于漏桶算法的流量限制模块(ngx_stream_limit_conn_module
),可以方便的控制令牌速率,自定义调节限流,实现基本的限流控制
3-1 漏桶算法
Leaky Bucket: 主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算法提供了一种机制,通过它,突发流量可以被整形,以便为网络提供一个稳定的流量。
-
水(请求)从上方倒入水桶,从水桶下方流出(被处理);
-
来不及流出的水存在水桶中(缓冲),以固定速率流出;
-
水桶满后水溢出(丢弃)。
-
这个算法的核心是:缓存请求、匀速处理、多余的请求直接丢弃。
3-2 令牌桶算法
Token Bucket:是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。
-
令牌以固定速率产生,并缓存到令牌桶中;
-
令牌桶放满时,多余的令牌被丢弃;
-
请求要消耗等比例的令牌才能被处理;
-
令牌不够时,请求被缓存。
3-3 两者区别
从作用上来说,漏桶和令牌桶算法最明显的区别就是是否允许突发流量(burst)的处理,漏桶算法能够强行限制数据的实时传输(处理)速率,对突发流量不做额外处理;而令牌桶算法能够在限制数据的平均传输速率的同时允许某种程度的突发传输。
Nginx按 请求速率限速模块 使用的是漏桶算法,即:能够强行保证请求的实时处理速度不会超过设置的阈值。Nginx官方版本限制IP的连接和并发分别有两个模块:
-
limit_req_zone
用来限制单时间内的请求数,即速率限制,采用的漏桶算法 "leaky bucket"。 -
limit_req_conn
用来限制同一时间连接数,即并发限制。
4、限流配置
4-1 IP限流
限制单时间内的请求数
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=2r/s; server { location /login/ { limit_req zone=ip_limit; proxy_pass http://login_upstream; } }
limit_req_zone: 定义限流规则:
-
$binary_remote_addr : 针对客户端ip限流
-
zone=ip_limit:10m :名称为ip_limit,允许使用10MB的内存空间来记录ip对应的限流状态;
-
rate=2r/s: 限流速度为每秒2次请求
limit_req: 使用限流规则:
-
zone=ip_limit 使用ip_limit这个规则
注意: Nginx的限流统计是基于毫秒的,我们设置的速度是2r/s,转换一下就是500ms内单个IP只允许通过1个请求,从501ms开始才允许通过第二个请求
4-2 burst缓存处理
如果短时间内发送了大量请求,Nginx按照毫秒级精度统计,超出限制的请求直接拒绝。这在实际场景中未免过于苛刻,真实网络环境中请求到来不是匀速的,很可能有请求“突发”的情况。Nginx考虑到了这种情况,可以通过burst关键字开启对突发请求的缓存处理,而不是直接拒绝。
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=2r/s; server { location /login/ { limit_req zone=ip_limit burst=3; proxy_pass http://login_upstream; } }
每个IP最多允许3个突发请求的到来
4-3 nodelay降低排队时间
通过设置burst参数,我们可以允许Nginx缓存处理一定程度的突发,多余的请求可以先放到队列里,慢慢处理,这起到了平滑流量的作用。但是如果队列设置的比较大,请求排队的时间就会比较长,用户角度看来就是RT变长了,这对用户很不友好。
RT(Response Time) 响应时间,就是从客户端请求发起到服务器响应结果的时间。RT这个参数是系统最重要的指标之一,它的大小直接反应了当前系统的响应状态 一般在100ms内,最大300ms
nodelay参数允许请求在排队的时候就立即被处理,也就是说只要请求能够进入burst队列,就会立即被后台worker处理,请注意,这意味着burst设置了nodelay时,系统瞬间的QPS可能会超过rate设置的阈值。nodelay参数要跟burst一起使用才有作用。
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=2r/s; server { location /login/ { limit_req zone=ip_limit burst=4 nodelay; proxy_pass http://login_upstream; } }
4-4 自定义返回值
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=2r/s; server { location /login/ { limit_req zone=ip_limit burst=4 nodelay; proxy_pass http://login_upstream; limit_req_status 598; } }
八、Nginx架构和配置
1、master-worker机制
master负责将请求分配给手下的worker, worker接到分配的请求来做具体的事情. 所有的worker并不是轮询来处理master的请求, 而是采用"争抢"机制:
优势:
-
对于每个 worker 进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。
-
采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master 进程则很快启动新的worker 进程。当然,worker 进程的异常退出,肯定是程序有 bug 了,异常退出,会导致当前 worker 上的所有请求失败,不过不会影响到所有请求,所以降低了风险。
2、worker_process
Nginx 同 redis 类似都采用了 io 多路复用机制,每个 worker 都是一个独立的进程,但每个进程里只有一个主线程,通过异步非阻塞的方式来处理请求, 即使是千上万个请求也不在话下。每个 worker 的线程可以把一个 cpu 的性能发挥到极致。所以 worker 数和服务器的 cpu数相等是最为适宜的。设少了会浪费 cpu,设多了会造成 cpu 频繁切换上下文带来的损耗。
windows系统并没有上面所说的io多路复用机制, 所以windows下的nginx并不能将性能最大化.
worker_processes 4 #work 绑定 cpu(4 work 绑定 4cpu)。 worker_cpu_affinity 0001 0010 0100 1000 #work 绑定 cpu (4 work 绑定 8cpu 中的 4 个) 。 worker_cpu_affinity 0000001 00000010 00000100 00001000
3、worker_connection
这个值是表示每个 worker 进程所能建立连接的最大值,所以,一个 nginx 能建立的最大连接数,应该是 worker_connections * worker_processes。当然,这里说的是最大连接数。
如果是支持 http1.1 的浏览器每次访问要占两个连接,所以普通的静态访问最大并发数是: worker_connections * worker_processes /2,而如果是 HTTP 作 为反向代理来说,最大并发数量应该是 worker_connections * worker_processes/4。因为作为反向代理服务器,每个并发会建立与客户端的连接和与后端服务的连接,会占用两个连接。