nginx负载均衡
当我们的应用单例不能支撑用户请求时,此时就需要扩容,从一台服务器扩容到两台、几十台、几百台,我们需要一个入口,将客户端请求均衡分布在后台的多个服务器上。
负载均衡在服务端开发中算是一个比较重要的特性, nginx 提供的负载均衡可以实现上游服务器的负载均衡、故障转移、失败重试、容错、健康检查,当某些上游服务器出现问题时,可以将请求转到其它的上游服务器从而保障高可用。
第一步我们需要给 nginx 配置上游服务器,即负载均衡到真实的处理业务的服务器 通过在 http 指令下配置 upstream 即可。
指定一组上游服务器地址,其中,地址可以是域名、IP地址。可以在域名或者IP地址后加端口,如果不加端口,那么默认使用80端口。
语法: upstream name { ... }
默认值: —
上下文: http
例子:
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
}
server {
location / {
proxy_pass http://backend;
}
}
upstream 指令当中包含server指令
语法: server address [parameters];
默认值: —
上下文: upstream
可以定义下面的参数:
weight=number 设定服务器的权重,默认是1,权重越大被访问机会越大,要根据机器的配置情况来配置
max_fails=number 设定Nginx与服务器通信的尝试失败的次数。在fail_timeout参数定义的时间段内,如果失败的次数达到此值,Nginx就认为服务器不可用。在下一个fail_timeout时间段,服务器不会再被尝试。 失败的尝试次数默认是1。
可以通过指令proxy_next_upstream 和memcached_next_upstream来配置什么是失败的尝试。 默认配置时,http_404状态不被认为是失败的尝试。
fail_timeout=time
统计失败尝试次数的时间段。在这段时间中,服务器失败次数达到指定的尝试次数,服务器就被认为不可用。默认情况下,该超时时间是10秒。
backup
标记为备用服务器。当主服务器不可用以后,请求会被传给这些服务器,配置这个指令可以实现故障转移。
down
标记服务器永久不可用,可以跟ip_hash指令一起使用。
当访问Nginx时,会将请求反向代理到backend配置的upstream server。
负载均衡的方法
nginx支持以下负载均衡机制:
1、轮询
默认轮训方式
每一个来自网络中的请求,轮流分配给内部的服务器,从1到N然后重新开始。此种负载均衡算法适合服务器组内部的服务器都具有相同的配置并且平均服务请求
相对均衡的情况。
2、加权轮询
通过 weight
参数控制权重
根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能够接受相应权值数的服务请求。例如:服务器A的权值被设计成1,B的权值是3,C的权值是6,则服务器A、B、C将分别接受到10%、30%、60%的服务请求。此种均衡算法能确保高性能的服务器得到更多的使用率,避免低性能的服务器负载过重。
3、IP Hash
在 upstream
当中配置 ip_hash
;
这种方式通过生成请求源IP的哈希值,并通过这个哈希值来找到正确的真实服务器。这意味着对于同一主机来说他对应的服务器总是相同。使用这种方式,你不
需要保存任何源IP。 将客户端会话"沾住"或者"持久化",以便总是能选择特定服务器,那么可以使用 ip-hash 负载均衡机制。
使用 ip-hash
时,客户端IP地址作为 hash key
使用,用来决策选择服务器集群中的哪个服务器来处理这个客户端的请求。这个方法保证从同一个客户端发起的
请求总是定向到同一台服务器,除非服务器不可用。
4、最少连接数
在 upstream
当中配置 least_conn
实现最少连接数
客户端的每一次请求服务在服务器停留的时间可能会有较大的差异,随着工作时间加长,如果采用简单的轮循或随机均衡算法,每一台服务器上的连接进程可能会产生极大的不同,并没有达到真正的负载均衡。最少连接数均衡算法对内部中需负载的每一台服务器都有一个数据记录,记录当前该服务器正在处理的连接数量,当有新的服务连接请求时,将把当前请求分配给连接数最少的服务器,使均衡更加符合实际情况,负载更加均衡。
失败重试
通过配置上游服务器 max_fails
和 fail_timeout
,指定每个上游服务器,当 fail_timeout
时间内失败了 max_fails
次请求,则认为该上游服务器不可用/不存
活,然后这段时间将不会访问这台上游服务器, fail_timeout
时间后会再次进行重试。
max_fails=2
fail_timeout=30s
这2个一起搭配使用,表示:当失败2次的时候,就停止使30秒
proxy_next_upstream 指令
在nginx的配置文件中, proxy_next_upstream
项定义了什么情况下进行重试
语法: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 http_503 | http_504 |http_404 | off ...;
默认值: proxy_next_upstream error timeout;
上下文: http, server, location
其中:
error 表示和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现错误。
timeout 表示和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现超时。
invalid_header 表示后端服务器返回空响应或者非法响应头
http_500 表示后端服务器返回的响应状态码为500
.............
off 表示停止将请求发送给下一台后端服务器
重试不能无限制进行,因此,需要如下两个指令控制重试次数和重试超时时间。
proxy_next_upstream_tries number
:设置重试次数,默认0表示不限制,注意此重试次数指的是所有请求次数(包括第一次和之后的重试次数之和)。
proxy_next_upstream_timeout time
: 设置重试最大超时时间,默认0表示不限制。
即在 proxy_next_upstream_timeout 时间内允许 proxy_next_upstream_tries 次重试。如果超过了其中一个设置,则 Nginx 也会结束重试并返回客户端响应(可能是错误码)。
proxy_send_timeout 后端服务器数据回传时间(代理发送超时时间)
proxy_read_timeout 连接成功后,后端服务器响应时间(代理接收超时时间)
proxy_connect_timeout nginx连接后端的超时时间,一般不超过75s
backup(故障转移)
标记为备用服务器。当主服务器不可用以后,请求会被传给这些服务器。
down
标记服务器永久不可用,可以跟ip_hash指令一起使用。
动态负载均衡
nginx-upsync-module
提供了动态的负载均衡,动态更新上游的服务器不需要 reload nginx
,它的功能是拉取 consul
的后端 server
的列表,并更新Nginx
的路由信息。此模块不依赖于任何第三方模块。 consul
作为 Nginx
的 db,利用 consul
的 KV 服务,每个 Nginx work
进程独立的去拉取各个upstream
的配置,并更新各自的路由.
挂了第三方模块无法结束进程或者是当前进程尚未结束。
nginx -s reload
是平滑重启,不会强制结束正在工作的连接,需要等所有连接都结束才会重启。想象一个场景上线繁忙,想要多添加几台服务器处理更多的流量.
改配置文件并重新启动 Nginx
可能并不总是很方便。 例如,当遇到大流量和高负载,重启 Nginx 并在此时重新加载配置会进一步增加系统负载,并可能暂时降低性能.
wget https://github.com/weibocom/nginx-upsync-module/archive/v2.1.0.tar.gz
--add-module=/root/nginx-upsync-module-2.1.0
示例:
upstream swoole_test {
upsync 127.0.0.1:8700/v1/kv/upstreams/swoole_test upsync_timeout=6m
upsync_interval=500ms upsync_type=consul
strong_dependency=off;
upsync_dump_path /usr/local/nginx/conf/servers_test.conf;
include /usr/local/nginx/conf/servers_test.conf;
}
upsync模块会去consul拉取最新的upstream信息并存到本地的文件中
upsync_timeout 配置从consul拉取上游服务器的超时时间
upsync_interval 配置从consul拉取上游服务器的间隔时间
upsync_type 指定使用配置服务器的类型,当前是consul
strong_dependency 启动时是否强制依赖配置服务器,如果配置为on,则拉取失败,nginx同样会启用失败
upsync_dump_path 指定从consul拉取的上游服务器后持久化到的位置,这样即使
Consul服务器出问题了,本地同样会有备份
添加的时候要注意名称模块的匹配:
安装consul
对于consul的介绍可以移步到另外的文档,暂时先了解就行,我们可以先通过docker的方式pull一个consul
curl -X PUT -d '{"weight":1, "max_fails":2, "fail_timeout":10}' http://$consul_ip:$port/v1/kv/$dir1/$upstream_name/$backend_ip:$backend_port
curl -X PUT -d '{"weight":1,"max_fails":2,"fail_timeout":10}' http://127.0.0.1:8700/v1/kv/upstreams/swoole_test/127.0.0.1:9501
docker run -itd --name -p consul consul
查看所有已经存储的k/v
curl http://127.0.0.1:8700/v1/kv/?recurse
删除 curl -X DELETE http://127.0.0.1:8700/
半自动平滑升级
所谓半自动,其实就是在最后迁移的时候使用源码自带的升级命令:make upgrade 来自动完成
- 1、需要下载对应的需要加载的第三方的扩展,或者是需要附加设置的参数 (注意:之前的配置参数要保留)
--add_module=PATH 添加第三方扩展 - 2、执行make不要执行make install
- 3、重命名 nginx 旧版本二进制文件,即 sbin 目录下的 nginx(期间 nginx 并不会停止服务)
- 4、然后拷贝一份新编译的二进制文件到安装目录
-
5、在源码目录执行 make upgrade 开始升级:
nginx缓存机制(浏览器缓存及nginx缓存)
什么是缓存?
Web缓存是可以自动保存常见文档副本的HTTP 设备。当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地设备而不是服务器中提取这个文档。
为什么使用缓存?
缓存减少了冗余的数据传输,节约了网络费用
缓存缓解了网络瓶颈的问题,对于带宽的要求
缓存降低了对原始服务器的要求,降低服务器压力
缓存加速了页面的展示
缓存的分类:
缓存分为服务端侧(比如 Nginx,redis,memcached)和客户端侧(比如 web browser)。
服务端缓存又分为 代理服务器缓存 和 反向代理服务器缓存(也叫网关缓存,比如 Nginx反向代理就可以设置缓存)
客户端侧缓存一般指的是浏览器缓存、app缓存等等,目的就是加速各种静态资源的访问,降低服务器压力。
简单看看浏览器的缓存规则,同时使用浏览器缓存跟nginx缓存:
第一次访问某个网站
第二次访问某个网站
我们发现多了一些字段关于这些字段的详细介绍下面会讲
HTTP 缓存控制头介绍
HTTP 中最基本的缓存机制,涉及到的 HTTP 头字段,包括 Cache-Control
, Last-Modified
, If-Modified-Since
, Etag
, If-None-Match
等
Last-Modified/If-Modified-Since
Last-Modified
:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since
:当资源过期时(使用Cache-Control标识的max-age),发现资源具有 Last-Modified 声明,则再次向web服务器请求时带上头
If-Modified-Since
,表示请求时间。web服务器收到请求后发现有头 If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,
说明资源有被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应 HTTP 304 (无需包体,节省
浏览),告知浏览器继续使用所保存的 cache 。
当我们按下f5刷新的时候,我们看看浏览器发送的请求头:
此处发送时有一个 If-Modified-Since
请求头,其值就是上次请求响应的 Last-Modified
响应状态码为304
Ctrl+f5强制刷新
如果你想强制从服务器获取最新的内容,不去对比,那么就可以强制刷新
Pragma行是为了兼容 HTTP1.0
,作用与 Cache-Control: no-cache
是一样的
Etag/If-None-Match
Etag
:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定),如果给定URL中的资源修改,则一定要生成新的Etag值。
If-None-Match
:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头 If-None-Match (Etag的值)。web服务器收到请求后发现有头 If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
Last-Modified
标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
如果某些文件会被定期生成,当有时内容并没有任何变化,但 Last-Modified 却改变了,导致文件没法使用缓存
有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形 Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识
符,能够更加准确的控制缓存。 Last-Modified
与 ETag
是可以一起使用的,服务器会优先验证 ETag
,一致的情况下,才会继续比对 Last-Modified
,最后才
决定是否返回304。
如下所示:
浏览器第一次请求,无缓存状态
浏览器第二次请求
Nginx web缓存设置
nginx 提供了 expires、etag、if-modified-since 指令来进行浏览器缓存控制。
expires指令
语法: expires [modified] time;
默认值: expires off;
上下文: http, server, location, if in location
假设我们使用 nginx
作为静态资源服务器,此时可以使用 expires
进行缓存控制。
location /img { alias /export/img/; expires 10s; }
expires 30s;#30秒
expires 30m;#30分钟
expires 2h;#2个小时
expires 30d;#30天
nginx代理缓存模块(ngx_http_proxy_module)
Proxy
模块,用于把请求后抛给服务器节点或 upstream
服务器池
常用配置,具体看手册
请求头传递
proxy_redirect off ;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 50m;
client_body_buffer_size 256k;
proxy_connect_timeout 30;
proxy_send_timeout 30;
proxy_read_timeout 60;
proxy_buffer_size 256k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
proxy_max_temp_file_size 128m;
proxy_pass http://nginx.23673.com;
proxy_cache_path
指令
语法:proxy_cache_path[levels=number] keys_zone=zone_name:zone_size[inactve=time] [max_size=size];
默认值:None
上下文:http
proxy_cache_path 设置缓存目录,目录里的文件名是cache_key的MD5值。
levels=1:2 默认所有缓存文件都放在同一个/path/to/cache下,但是会影响缓存的性能,因此通常会在/path/to/cache下面建立子目录用来分别存放不
同的文件。假设levels=1:2。
key_zone 在共享内存中设置一块存储区域来存放缓存的key和metadata(类似使用次数),这样nginx可以快速判断一个request是否命中或者未命中缓
存,1m可以存储8000个key,10m可以存储80000个key。
max_size 最大cache空间,如果不指定,会使用掉所有disk space,当达到配额后,会删除最少使用的cache文件。
inactive 未被访问文件在缓存中保留时间,本配置中如果60分钟未被访问则不论状态是否为expired,缓存控制程序会删掉文件。inactive默认是10分
钟。需要注意的是,inactive和expired配置项的含义是不同的,expired只是缓存过期,但不会被删除,inactive是删除指定时间内未被访问的缓存文
件。
use_temp_path 如果为off,则nginx会将缓存文件直接写入指定的cache文件中,而不是使用temp_path存储,official建议为off,避免文件在不同文件
系统中不必要的拷贝。
proxy_cache 启用proxy cache,并指定key_zone。另外,如果proxy_cache off表示关闭掉缓存。
proxy_cache_key 定义cache_key,nginx对缓存的资源会设置一个key,NGINX生成的键的默认格式是类似于下面的NGINX变量的MD5哈希
值:$scheme$proxy_host$request_uri,实际的算法有些复杂。 为了改变变量(或其他项)作为基础键,可以使用proxy_cache_key命令。
proxy_cache_valid 为不同的HTTP返回状态码的资源设置不同的缓存时长。
缓存细节
NGINX仅仅默认缓存GET和HEAD客户端请求,在响应头部中 Cache-Control
被配置为 Private
,No-Cache
,No-Store
或者 Set-Cookie
, NGINX
不会进行缓
存。
如果你不想源服务器控制是否缓存,也可以在 nginx 当中配置忽略利用 proxy_ignore_headers Cache-Control
指令实现
下面的指令允许多种请求类型缓存
proxy_cache_methods GET HEAD POST ;
缓存设置优化
proxy_cache_min_uses
设置响应被缓存的最小请求次数。
当缓存不断被填满时,这项设置便十分有用,因为这确保了只有那些被经常访问的内容才会被添加到缓存中。该项默认值为1。
proxy_cache_lock
开启此功能时,对于相同的请求,同时只允许一个请求发往后端。
只有这些请求中的第一个被允许发送至服务器。其他请求在第一个请求得到满意结果之后在缓存中得到文件。如果不启用 proxy_cache_lock ,则所有在缓存中找不到文件的请求都会直接与源服务器通信。
不缓存的条件
有时候,我们也不想所有的请求都被缓存,我们可以指定某些请求不被缓存,比如带有后台后缀的,可以通过一些条件判断决定是否缓存。
语法: proxy_cache_bypass string ...;
默认值: —
上下文: http, server, location
定义nginx不从缓存取响应的条件。如果至少一个字符串条件非空而且非“0”,nginx就不会从缓存中去取响应,而是请求源服务器
比如后台模块是不允许缓存的,就可以设置不缓存
清除缓存
某些时候我们如果不想等待缓存的过期,想要主动清除缓存,可以采用第三方的缓存清除模块清除缓存 nginx_ngx_cache_purge
第三方地址 https://www.nginx.com/resources/wiki/modules/
Purge 模块下载地址 http://labs.frickle.com/nginx_ngx_cache_purge/
可以利用平滑升级的方式安装
proxy_cache_purge
syntax: proxy_cache_purge zone_name key
default: none
context: location
注意:要在proxy_cache 指令 下方
proxy_cache_purge tmp-test $uri;
tmp-test:指定的key_zone
$uri:指定的生成key的参数
比如:匹配url当中包含了purge关键字的就清除
缓存 xxx.com/cache/shop/?a=1
清除 xxxx.com/purge/shop/?a=1