纸上得来终觉浅,绝知此事要躬行。
0. 性能分析
用于反向代理,
HAProxy
是支持最全面,成本最低的方案。
0.1 缺点分析
Nginx 社区版的缺点(反向代理和负载均衡功能上)
- Session 会话持久保持
Nginx
官方给出的解决方案是使用ip_hash
调度算法,根据访问客户端的源IP
地址进行请求分发调度到后端服务器的。表面上看起来没有什么问题,但是实际应用起来就会发现几乎不可行。- 比如为学校做一个选课系统,服务器放在服务网段,学生在普通网段,两个网段互通全靠
NAT
,Nginx
收到的IP
全都是同一个源IP
,那么这个负载均衡没有就没有生效。
- 后端服务器的健康监测
Nginx
官方给出的解决方案是被动监测的方式。- 如下例所示,意思就是如果
9191
这个端口某次连接超时或者失败次数超过了max_fails
次,就会被判定为服务不可用,然后等待fail_timeout
这么长时间之后自动认为其可用,不管到底真的修复了没有。然后再次重试max_fails
次。 - 这还不算最坑爹的,更麻烦的是在
Nginx
上你无法查看各个后端节点的状态,不知道哪台宕机了或者卡了不好用了。如果你后端有一百台被负载均衡的服务器,光检查可用性这一点Nginx
社区版就完败。
# 被动监测
server localhost:9191 max_fails=1 fail_timeout=40s;
连接和流量的统计功能
- 连接和流量的统计功能,也适用于检查后端健康情况和当前的并发连接数的。这个功能社区版默认还是没有的,需要在编译时添加一个官方支持的模块(
--with-http_stub_status_module
模块)
- 同样是反向代理负载均衡的
HAProxy
和NGINX+
就做的非常好,下面和上面可以对比一下看看。
0.2 替代方案
如何选择负载均衡器呢(一般来说)
- 1、基于
Cookie
的会话保持 - 2、监控后台服务器的负载状态和健康状况,主动进行健康检查
- 3、支持以最小连接数为基准的负载均衡分发策略
对于 HAProxy 来说
- 上述功能全部都可以实现,而且全部是官方支持;
- 不需打补丁,直接在
yum
源上安装就可以全部实现; - 据网上的资料,
HAProxy
的并发数还要高于NGINX
; HAProxy
还可以支持TCP
连接的负载均衡,这一点是NGINX
社区版和plus
在1.9
版本之后才实现的功能,而Tengine
由于基础版本才1.8.1
所以并不支持;
对于 Tengine 来说
- 1、2、3 也可以支持,但是 1、3 不能同时支持;
- 后台监控页面比较简陋,看不到具体每台节点的负载情况;
- 也就是说如果使用
Cookie
作为会话保持策略,那就不能再以最少连接数作为分发策略了,只能使用轮训(round_robin
),这样的话很容易出现某些服务器占用超级高,然后其他服务器几乎没有负载的糟糕情况;
补充说明
- 对于
Nginx puls
来说,1、2、3 都可以支持,但是由于价格太过昂贵,所以我也没试过其真实的效果; - 对于硬件负载均衡器
F5
或A10
来说,1、2、3 都可以支持,而且基本没什么大问题;
1. 反向代理
由
ngx_http_proxy_module
模块提供
1.1 使用格式
- 格式分类
# 【基本使用方式】
# /uri --> /newuri
# 使用newuri替换原有的uri请求地址
location /uri {
proxy_pass http://back_server[:port]/newuri;
}
# 【模式匹配特例】
# /uri --> /uri
# 但使用模式匹配的话(~或~*),请求的uri会添加在newuri后面
# proxy_pass设置的代理服务地址不能添加任何路径,否则会报错
location ~* /uri {
proxy_pass http://back_server[:port];
}
# 【URL重定向特例】
# /uri --> /reurl
# 但使用URL重定向将uri替换成reuri,则proxy_pass的newuri就无效了
location /uri {
rewrite reuri;
proxy_pass http://back_server[:port]/newuri;
}
- 模式示例
# 【基本使用方式】
location /bbs {
proxy_pass http://192.168.100.2:80/newbbs;
}
# 【模式匹配特例】
location ~* \.(jpg|png|gif)$ {
proxy_pass http://192.168.100.2;
}
# 【URL重定向特例】
location /bbs {
rewrite /rebbs/;
proxy_pass http://192.168.100.2:80/newbbs/;
}
- 实例说明
# 通过proxy_set_header设置自定义变量给后端服务器使用
# $host表示客户端请求的主机名,用于虚拟主机中使用
# $remote_addr表示客户端IP地址,X-Real-IP用于后端服务器记录日志
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://localhost:8000;
}
# 设置真实scheme协议
map $http_x_scheme $real_http_x_scheme {
default $http_x_scheme;
"" $scheme;
}
1.2 常用指令
【1】proxy_pass
- 语法格式
proxy_pass URL;
- 含义解释
- 该指令可以设置代理服务器的协议、地址和端口
- 该指令可以定义本地路径和后端服务器的映射关系
- 作用范围
location
、if in location
、limit_except
# 使用http或https定义
proxy_pass http://localhost:8000/uri/;
# 使用UNIX域套接字路径
proxy_pass http://unix:/tmp/backend.socket:/uri/;
【2】proxy_set_header
- 语法格式
proxy_set_header field value;
- 含义解释
- 允许重新定义或者添加发往后端服务器的请求头
value
可以包含文本、变量或者它们的组合- 当且仅当当前配置级别中没有定义
proxy_set_header
指令时,会从上面的级别继承配置
- 作用范围
http
、server
、location
- 默认值
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
# 定义传递给后端服务器的Host变量
proxy_set_header Host $host;
# 此外,服务器名可以和后端服务器的端口一起传送
proxy_set_header Host $host:$proxy_port;
# 如果某个请求头的值为空,那么这个请求头将不会传送给后端服务器
proxy_set_header Accept-Encoding "";
【3】proxy_http_version
代理服务器本身存在缓存,用户请求之后立即返回,所有让第二阶段(代理服务器和后端服务器之间的连接方式)一直保持长连接其实没有必要,可以根据业务情况让其使用短连接方式通信,提高效率。
- 语法格式
proxy_http_version 1.0|1.1;
- 含义解释
- 设置代理使用的
HTTP
协议版本
- 设置代理使用的
- 作用范围
http
、server
、location
- 默认值
proxy_http_version 1.0
# HTTP的1.1版本推荐在使用keepalive连接时一起使用
proxy_http_version 1.1;
【4】proxy_limit_rate
- 语法格式
proxy_limit_rate rate;
- 含义解释
- 设置代理服务器的响应速率,
0
表示不限速,单位为字节/秒 - 限制的是一个请求的响应速率,如果同时启动两个,则限制速率翻倍
- 只工作在响应缓存(
buffering
)开启的情况下
- 设置代理服务器的响应速率,
- 作用范围
http
、server
、location
- 默认值
proxy_limit_rate 0;
proxy_limit_rate 100k;
【5】proxy_method
- 语法格式
proxy_method method;
- 含义解释
- 指定要使用的
HTTP
方法请求转发到代理服务器,而不是从客户端请求的方法,参数值可以包含变量
- 指定要使用的
- 作用范围
http
、server
、location
proxy_method get;
【6】proxy_hide_header
- 语法格式
proxy_hide_header field;
- 含义解释
nginx
默认不会将“Date”
、“Server”
和“X-Accel-...”
响应头发送给客户端。proxy_hide_header
指令则可以设置额外的响应头,这些响应头也不会发送给客户端。相反的,如果希望允许传递某些响应头给客户端,可以使用proxy_pass_header
指令。
- 作用范围
http
、server
、location
proxy_hide_header Date;
proxy_hide_header Server;
【7】proxy_connect_timeout
- 语法格式
proxy_connect_timeout time;
- 含义解释
- 设置与后端服务器建立连接的超时时间
- 应该注意这个超时一般不可能大于
75
秒
- 作用范围
http
、server
、location
- 默认值
proxy_connect_timeout 60s;
proxy_connect_timeout 5s;
【8】proxy_buffers
- 语法格式
proxy_buffers number size;
- 含义解释
- 为每个连接设置缓冲区的数量
number
和每块缓冲区的大小size
- 这些缓冲区用于保存从被代理的服务器读取的响应,成块一起发送
- 每块缓冲区默认等于一个内存页的大小,值是 4K 还是 8K 取决于平台
- 为每个连接设置缓冲区的数量
- 作用范围
http
、server
、location
- 默认值
proxy_buffers 8 4k|8k;
proxy_buffers 8 4k
1.3 缓存功能
【1】proxy_cache_path
- 语法格式
proxy_cache_path path [levels=levels] keys_zone=name:size [inactive=time] [max_size=size] [loader_files=number] [loader_sleep=time] [loader_threshold=time];
- 含义解释
- 用于设置缓存的路径和配置,需要先设置才能使用
- 参数十分多,很多的参数都可以使用默认值就好了
- 该指令只能使用在
http
中,可以设置多个不同名的缓存样式
- 作用范围
http
- 缓存格式
- 缓存数据是保存在文件中的,缓存的键和文件名都是在代理
URL
上执行MD5
的结果。
- 缓存数据是保存在文件中的,缓存的键和文件名都是在代理
- 工作方式
- 被缓存的响应首先写入一个临时文件,然后进行重命名。从
0.8.9
版本开始,临时文件和缓存可以放在不同的文件系统。但请注意,这将导致文件在这两个文件系统中进行拷贝,而不是廉价的重命名操作。因此,针对任何路径,都建议将缓存和proxy_temp_path
指令设置的临时文件目录放在同一文件系统。
- 被缓存的响应首先写入一个临时文件,然后进行重命名。从
- 参数理解
- 所有有效的键和缓存数据相关的信息都被存放在共享内存中。共享内存通过
keys_zone
参数的name
和size
来定义。被缓存的数据如果在inactive
参数指定的时间内未被访问,就会被从缓存中移除,不论它是否是刚产生的。inactive
的默认值是10
分钟。 - 特殊进程
cache manager
监控缓存的条目数量,如果超过max_size
参数设置的最大值,使用LRU
算法移除缓存数据。 nginx
启动之后,特殊进程cache loader
就被启动。该进程将文件系统上保存的过去缓存的数据的相关信息重新加载到共享内存。加载过程分多次迭代完成,每次迭代,进程只加载不多于loader_files
参数指定的文件数量(默认值为100
)。此外,每次迭代过程的持续时间不能超过loader_threshold
参数的值(默认200
毫秒)。每次迭代之间,nginx
的暂停时间由loader_sleep
参数指定(默认50
毫秒)。
- 所有有效的键和缓存数据相关的信息都被存放在共享内存中。共享内存通过
# path设置缓存存储的物理路径位置
# levels设置缓存的路径级别和命名大小
# keys_zone设置缓存的名称和大小
# levels=1:2表示有两层,第一层目录使用一位数,第二层目录使用两位数
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;
# 缓存中文件名看起来是这样的
/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c
【2】proxy_cache
- 语法格式
proxy_cache zone|off;
- 含义解释
- 指定用于页面缓存的共享内存,同一块共享内存可在多个地方使用
- 先定义后使用,选择
http
段中定义的缓存样式中的一个即可 - 其中
off
参数可以屏蔽从上层配置继承的缓存功能
- 作用范围
http
、server
、location
- 默认值
proxy_cache off;
proxy_cache one;
http {
include /etc/nginx/mine.types;
default_type application/octet-stream;
sendfile on;
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:32m;
...
server {
listen 80;
server_name localhost;
...
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /bbs/ {
proxy_cache mycache;
proxy_cache_valid 200 1d;
proxy_cache_valid 301 302 10m;
proxy_cache_valid any 1m;
proxy_cache_use_stale error timeout invalid_header http_500;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://192.168.100.2/;
}
location ~* \.(jpg|png|gif)$ {
proxy_cache mycache;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://192.168.100.2/;
}
}
}
【3】proxy_cache_methods
- 语法格式
proxy_cache_methods GET|HEAD|POST ...;
- 含义解释
- 如果客户端请求方法是列在这个指令的响应才被缓存
- 作用范围
http
、server
、location
- 默认值
proxy_cache_methods GET HEAD;
proxy_cache_methods GET HEAD;
【4】proxy_cache_min_uses
- 语法格式
proxy_cache_min_uses number;
- 含义解释
- 设置请求对于的响应的数量达到指定的数量之后,响应才被缓存
- 作用范围
http
、server
、location
- 默认值
proxy_cache_min_uses 1;
# 请求对于的响应的数量达到10次之后,对于的响应内容才会被缓存起来
proxy_cache_min_uses 10;
【5】proxy_cache_purge
- 语法格式
proxy_cache_purge string ...;
- 含义解释
- 缓存修剪:将特定请求视为一个缓存清除请求
- 如果缓存没有过期但后端已经变动了,用户请求将返回缓存中的响应信息,所有这个时候就需要缓存修剪操作。只要用户请求就删除对于请求的响应缓存数据,就会返回后端变动的响应信息。
- 作用范围
http
、server
、location
proxy_cache_path /data/nginx/cache keys_zone=cache_zone:10m;
map $request_method $purge_method {
PURGE 1;
default 0;
}
server {
...
location / {
proxy_pass http://backend;
proxy_cache cache_zone;
proxy_cache_key $uri;
proxy_cache_purge $purge_method;
}
}
# 需要ngx_cache_purge模块来在过期时间未到之前,手动清理缓存
# 清除缓存的防范:(1)直接删除缓存目录;(2)GET方式请求URL
http {
... // $upstream_cache_status记录缓存命中率
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'"$upstream_cache_status"';
proxy_temp_path /usr/local/nginx-1.6/proxy_temp;
proxy_cache_path /usr/local/nginx-1.6/proxy_cache levels=1:2 keys_zone=cache_one:100m inactive=2d max_size=2g;
server {
listen 80;
server_name ittest.example.com;
root html;
index index.html index.htm index.jsp;
location ~ .*\.(gif|jpg|png|html|css|js|ico|swf|pdf)(.*) {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache cache_one;
# 定义cache_key格式
proxy_cache_valid 200 304 301 302 8h;
proxy_cache_valid 404 1m;
proxy_cache_valid any 2d;
proxy_cache_key $host$uri$is_args$args;
add_header Nginx-Cache $upstream_cache_status;
expires 30d;
}
location ~ /purge(/.*) {
# 设置只允许指定的IP或IP段才可以清除URL缓存
allow 127.0.0.1;
allow 172.29.73.0/24;
deny all;
proxy_cache_purge cache_one $host$1$is_args$args;
error_page 405 =200 /purge$1;
}
}
}
【6】proxy_cache_revalidate
- 语法格式
proxy_cache_revalidate on|off;
- 含义解释
- 过期后重新校验:当缓存过期后向后端服务器询问,如果没有改变将修改有效期继续使用,如果已经改变了,就使用改变后的响应信息发送给客户端
- 作用范围
http
、server
、location
- 默认值
proxy_cache_revalidate off;
proxy_cache_revalidate on;
【7】proxy_cache_use_stale
- 语法格式
proxy_cache_use_stale error|timeout|invalid_header|updating|http_404|http_502 ...
- 含义解释
- 如果缓存已经过期了且和后端服务器无法连接的情况下,如何响应用户请求
- 使用过期缓存的情况;遇到
error
错误页、响应为http_404
、timeout
为后端服务器连接超时等情况下
- 作用范围
http
、server
、location
- 默认值
proxy_cache_use_stale off;
proxy_cache_use_stale http_404;
【8】proxy_cache_valid
- 语法格式
proxy_cache_valid [code ...] time;
- 含义解释
- 根据响应状态码来设置缓存时长
- 作用范围
http
、server
、location
proxy_cache_valid 200 302 10m;
proxy_cache_valid 301 1h;
proxy_cache_valid any 1m;
【9】proxy_cache_bypass
- 语法格式
proxy_cache_bypass string ...;
- 含义解释
- 设置在何种情况下
nginx
将不从cache
中取数据 - 可以和
proxy_no_cache
指令一起使用
- 设置在何种情况下
- 作用范围
http
、server
、location
proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
proxy_cache_bypass $http_pragma $http_authorization;
1.4 加密通信
由ngx_http_ssl_module
模块提供HTTPS
的支持,该模块默认没有配置,需要在编译的使用--with-http_ssl_module
参数开启(需要OpenSSL
库的支持)。
- 更多内容参考官方文档
# 减少处理器负载建议
# 1. 设置工作进程的数量等于处理器的数量
# 2. 开启keep-alive连接支持
# 3. 启用共享会话缓存,即所有工作进程之间共享一个缓存
# 4. 禁用内置的会话缓存,即禁止缓存只使用一个工作进程
# 5. 提高session会话的重用时长(ssl_session_timeout参数)
worker_processes auto;
http {
...
server {
listen 443 ssl;
keepalive_timeout 70;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/cert.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
...
}
}
2. 负载均衡
# nginx的商用软件支持健康监测功能
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
server backup2.example.com:8080 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
2.1 常用指令
【1】upstream
- 语法格式
upstream name {...}
- 含义解释
- 定义一组后端服务器,这些服务器可以监听不同的端口
- 默认情况下,
nginx
按加权轮转的方式将请求分发到各服务器 - 如果所有服务器都返回失败,客户端将会得到失败响应结果
- 作用范围
http
# 使用默认带权重的RR算法,在上面的例子中,每7个请求将被如下分配
# 5个请求去backend1.example.com
# 1个请求去127.0.0.1:8080
# 1个请求去unix:/tmp/backend3
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
server backup1.example.com backup;
}
【2】server
- 语法格式
server address [parameters];
- 含义解释
- 定义服务器的地址
address
和其他参数parameters
- 定义服务器的地址
- 作用范围
upstream
参数格式 | 含义解释和说明 |
---|---|
weight=number |
设定服务器的权重,默认值为1 |
max_fails=number |
定义最大错误次数;设定Nginx 与服务器通信的尝试失败的次数;失败的尝试次数默认值为1 ,设为0 就会停止统计尝试次数,认为服务器是一直可用的;默认配置时,http_404 状态不被认为是失败的尝试,可以通过修改参数进行修改 |
fail_timeout=time |
定义超时是时长;在这段时间中,服务器失败次数达到指定的尝试次数,服务器就被认为不可用;默认情况下,该超时时间是10 秒 |
backup |
标记为备用服务器;当主服务器不可用以后,请求会被传给这些服务器 |
down |
标记服务器永久不可用;可以跟ip_hash 指令一起使用 |
max_conns=number |
商用版本才有;设置代理服务器的最大的活动连接数;默认值为0 表示不受限制 |
upstream backend {
server unix:/tmp/backend3;
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server backup1.example.com:8080 backup;
}
2.2 会话保持
**
sticky
**是nginx
的一个模块,它是基于cookie
的一种nginx
的负载均衡解决方案,通过分发和识别cookie
,来使同一个客户端的请求落在同一台服务器上。
【1】ip_hash
- 语法格式
ip_hash;
- 含义解释
- 类似于
LVS
的sh
算法,持久连接 - 请求基于客户端的
IP
地址在服务器间进行分发 - 这种方法可以确保从同一个客户端过来的请求,会被传给同一台服务器
- 类似于
- 作用范围
upstream
- 坏处说明
- 现在大量用户都是使用
SNAT
进行上网的,而使用ip_hash
的话,代理服务器会将多个客户端识别为一个用户并转发给同一个后端服务器,可能会损害负载均衡调度。 - 虽然代理服务器将多个用户识别为同一个,但是后端服务器却能够识别为多个不同的用户,虽然使用的是同一个
IP
地址,但不同的cookie
。因为用户使用的浏览器新发请求时,后端服务器都视为新请求,随之后端服务器给其发送一个特定cookie
(登录),之后请求时都带上这个特定cookie
来标识不同用户。 - 如果调度的时候根据
cookie
进行调度,颗粒度就比较好了。如果客户端请求到达Nginx
时,Nginx
不做IP
地址绑定而是做cookie
绑定,即保证了会话绑定和力度更大(sticky
)。
- 现在大量用户都是使用
# 如果其中一个服务器想暂时移除,应该加上down参数,这样可以保留当前客户端IP地址散列分布
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
【2】sticky
- 语法格式
sticky cookie name [expires=time] [domain=domain] [httponly] [secure] [path=path];
sticky route $variable ...;
sticky learn create=$variable lookup=$variable zone=name:size [timeout=time] [header];
- 含义解释
- 使用
cookie
绑定,使来自相同客户机的请求传递给同一台后端服务器 sticky_cookie_insert
为1.5.7
之前版本使用的指令
- 使用
- 作用范围
upstream
# 【可用方法一】
# 当使用cookie的方法时,由nginx传入cookie信息给后端服务器。
# 新请求进来时将被分派到配置的均衡算法选择的服务器,后续带有cookie的请求将被分派给指派的服务器。
# name: 可以为任何的字符,默认是route,这里是srv_id
# expires: 设置浏览器的cookie过期时间,默认浏览器关闭就过期
# domain: 哪些域名下可以使用这个cookie
# httponly: 添加HttpOnly属性到cookie
# secure: 添加Secure属性到cookie
# path: 对哪些路径启用sticky模式,这里的/代表整个网站
upstream backend {
server backend1.example.com;
server backend2.example.com;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
# 【可用方法二】
# 当使用route的方式时,用户的第一次请求根据调度发送给后端服务器
# 用户之后的请求URI中将携带route标记的信息,用于负载均衡调度。
# 将$cookie_jsessionid标记为$route_cookie
map $cookie_jsessionid $route_cookie {
~.+\.(?P<route>\w+)$ $route;
}
# 将$request_uri标记为$route_uri
map $request_uri $route_uri {
~jsessionid=.+\.(?P<route>\w+)$ $route;
}
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky route $route_cookie $route_uri;
}
# 【可用方法三】
# 当使用learn的方式时
# nginx分析upstream服务器的响应并学习通常在cookie中传递的server-initiated会话
# 在这个例子中,upstream服务器通过在应答中设置cookie的"EXAMPLECOOKIE"创建会话。
# 带有这个cookie的后续请求将被分派到同一个服务器。
# 如果服务器不能处理请求,新的服务器将被选择,就如同客户端没有被绑定一样。
# 参数create和lookup分别指定变量来指示如何创建新会话和搜索已经存在的会话。
# 两个参数都可以指定多个,这样第一个非空的变量将被使用。
# 会话存储在zone中,在zone属性中配置名字和大小。
# 在64位平台上一个megabyte zone可以存储大概8000个会话。
# 在timeout参数指定的期间内没有被访问的会话将被从zone上移除。默认,超时时间设置为10分钟。
upstream backend {
server backend1.example.com:8080;
server backend2.example.com:8081;
sticky learn
create=$upstream_cookie_examplecookie
lookup=$cookie_examplecookie
zone=client_sessions:1m;
}
2.3 调度算法
调度算法 | 解释说明 |
---|---|
rr |
默认为轮询算法; 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响;权重越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下 |
ip_hash |
每个请求按访问IP 的hash 结果分配;这样来自同一个IP 的访客固定访问一个后端服务器,有效解决了动态网页存在的session 共享问题;当然如果这个节点不可用了就会发到下个节点,而此时没有session 同步的话就注销掉了 |
least_conn |
分派请求到活动连接数量最少的服务器,兼顾服务器权重 |
least_time |
分派请求到平均响应时间最快和活动连接数量最少的服务器, 兼顾服务器权重 |
hash |
根据客户端/服务器映射基于散列key 值;key 可以包含文本、变量和他们的组合 |
url_hash |
按访问 url 的 hash 结果来分配请求,使每个 url 定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率;nginx 本身是不支持url_hash 的,如果需要使用这种调度算法,必须安装nginx 的hash 软件包 nginx_upstream_hash 模块 |
fair |
更加智能的负载均衡算法;该算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配;nginx 本身是不支持fair 的,如果需要使用这种调度算法,必须下载nginx 的upstream_fair 模块 |
2.4 持久连接
【keepalive
】
- 语法格式
keepalive connections;
- 含义解释
- 激活代理服务器到
upstream
服务器的连接缓存,即长连接 connections
参数设置每个worker
进程在缓冲中保持的空闲keepalive
连接的最大数量,当超过这个数量时,最近使用最少的连接将被关闭- 通常
upstream
服务器为memcached
等缓存服务器,而非http
服务器,是因为http
有可能会损害性能
- 激活代理服务器到
- 作用范围
upstream
# 使用keepalive连接后端memcached服务器配置的例子
upstream memcached_backend {
server 127.0.0.1:11211;
server 10.0.0.2:11211;
keepalive 32;
}
server {
...
location /memcached/ {
set $memcached_key $uri;
memcached_pass memcached_backend;
}
}
# 对于HTTP请求,proxy_http_version应该设置为1.1,而Connection的header应该被清理
# 或者HTTP/1.0持久连接可以通过传递"Connection: Keep-Alive"的header到upstream服务器,但是不推荐使用这种方法。
upstream http_backend {
server 127.0.0.1:8080;
keepalive 16;
}
server {
...
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}
}
# 对于FastCGI服务器,要求设置fastcgi_keep_conn来让长连接工作
# 当使用默认的RR之外的负载均衡算法时,必须在keepalive指令之前激活他们
# 对于scgi和uwsgi协议没有keepalive连接的概念
upstream fastcgi_backend {
server 127.0.0.1:9000;
keepalive 8;
}
server {
...
location /fastcgi/ {
fastcgi_pass fastcgi_backend;
fastcgi_keep_conn on;
...
}
}
2.5 健康监测
社区版本中主动的健康监测功能是不可用,而
HAProxy
和NGINX+
才支持而且做得很好,可以参考这个链接了解更多内容。
【1】health_check
- 语法格式
health_check [parameters];
- 含义解释
- 开启对所在
location
引用的集群中的服务器的定期健康检查 - 建议关闭对于
location
的访问日志功能,无用功 - 如果同一个集群的服务器定义有多个健康检查,任何一个检查失败都会导致对应的服务器被认为是不健康
- 开启对所在
- 作用范围
location
可选参数 | 说明解释 |
---|---|
interval=time |
设置两次连续健康检查之间的间隔时间,默认5 秒钟 |
fails=number |
设置连续失败的健康检查次数,之后这台服务器会被认为是不健康,默认为1 |
passes=number |
设置连续通过的健康检查次数,之后这台服务器会被认为是健康的,默认为1 |
uri=uri |
定义健康检查请求的URL ,默认是/ |
match=name |
指定匹配块来配置测试可以通过健康检查的响应;默认,响应的状态码应该是2xx 或者3xx |
port=number |
定义到执行健康检查的服务器的连接端口;默认和服务器端口相同 |
# 将每5秒钟发送"/"请求给后端集群中的每台服务器。
# 如果发生任何通讯错误、超时、代理服务器返回状态码不是2xx或者3xx,则健康检查失败。
# 这台服务器将被认为是不健康的,后续的客户端请求将不会发送给这台不健康的服务器。
location / {
proxy_pass http://backend;
health_check;
}
# 健康检查可以配置为检验响应的状态码,是否存在特定header和他们的值,还有http的body内容。
# 检验可以使用match指令单独配置并在match参数中引用。
http {
server {
...
location / {
proxy_pass http://backend;
health_check match=welcome;
}
}
match welcome {
status 200;
header Content-Type = text/html;
body ~ "Welcome to nginx!";
}
}
http {
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m;
...
upstream backend {
sticky;
server 172.29.88.226:8080 weight=2;
server 172.29.88.227:8081 weight=1;
}
server {
listen 80;
server_name localhost;
...
# 自定义响应首部,用于后端服务器使用
# $upstream_cache_status需要启用缓存共功能,才能查看
# $server_addr和$upstream_cache_status都是upstream提供的内部变量
add_header X-Via $server_addr;
add_header X-Cache $upstream_cache_status;
location / {
proxy_pass http://backend;
proxy_chache mycache;
health_check;
}
}
}
# status is 200, content type is "text/html",
# and body contains "Welcome to nginx!"
match welcome {
status 200;
header Content-Type = text/html;
body ~ "Welcome to nginx!";
}
# status is not one of 301, 302, 303, or 307, and header does not have "Refresh:"
match not_redirect {
status ! 301-303 307;
header ! Refresh;
}
# status ok and not in maintenance mode
match server_ok {
status 200-399;
body !~ "maintenance mode";
}
【2】nginx_upstream_check_module 模块
- 由淘宝的姚伟斌开发,专门提供负载均衡器内节点的健康检查的外部模块,在淘宝自己的
tengine
上是自带了该模块,项目地址官方文档。
ngx_http_upstream_conf_module
模块允许动态配置后端服务器组,通过一个简单的HTTP
接口而不需要重新启动nginx
服务。
# 下面的是一个带后端监控检查的nginx.conf配置
# 对name为backend这个负载均衡条目中的所有节点,每个5秒检测一次,超时时间为1秒
# 请求2次正常则标记后端服务器的状态为up,如果检测3次都失败,则标记后端服务器的状态为down
upstream backend {
sticky; # or simple round-robin
server 172.29.88.226:8080 weight=2;
server 172.29.88.226:8081 weight=1 max_fails=2 fail_timeout=30s ;
server 172.29.88.227:8080 weight=1 max_fails=2 fail_timeout=30s ;
server 172.29.88.227:8081;
check interval=5000 rise=2 fall=3 timeout=1000 type=http;
check_http_send "HEAD / HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
server {
location / {
proxy_pass http://backend;
}
location /status {
check_status;
access_log off;
allow 172.29.73.23;
deny all;
}
}
3. FastCGI 模块
在现在
LNMP
架构里面,PHP
一般是以php-cgi
的形式在运行,它就是一种FastCGI
,我们在进程中看到的php-fpm
是php-cgi
的管理调度器。
- 我们之前的都是使用的是
http
协议,如果Web
服务器,而对于FastCGI
协议,我们就需要使用ngx_http_fastcgi_module
模块的。 - 如客户端请求以
php
结尾的网页,就需要我们将请求发送给处理php
的应用程序,其中传输的协议为FastCGI
。
3.1 安装 LNMP
动静分离:通过对请求的URI
后缀名进行分类,不管是动态还是静态内容的服务器都可以定义为组进行管理、设置缓存等。动态内容可以使用FastCGI
、UWSGI
等协议进行代理(proxy_pass
),静态内容可以使用HTTP
或HTTPS
协议进行代理(fastcgi_pass
)。
# 安装服务,需要适当配置
yim install -y nginx
yum install -y php-fpm
yum install -y mysql-server
yum install -y php-mysql
# 启动服务
service nginx start
service php-fpm start
service mysqld start
# nginx配置文件
server {
...
location / {
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
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;
}
}
# 因为原有的文件内容有可能无法适配
# 编辑/etc/nginx/fastcgi_params内容更改为如下内容
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# 添加测试页面/usr/share/nginx/html/index.php验证
<?php
phpinfo();
?>
3.2 常用指令
【1】fastcgi_pass
- 语法格式
fastcgi_pass address;
- 含义解释
- 设置
fastcgi
的服务器地址
- 设置
- 作用范围
location
、if in location
# 使用域名、IP地址和unix
fastcgi_pass localhost:9000;
fastcgi_pass unix:/tmp/fastcgi.socket;
【2】fastcgi_limit_rate
- 语法格式
fastcgi_limit_rate rate;
- 含义解释
- 设置
FastCGI
服务器的响应速度,0
表示不做限制
- 设置
- 作用范围
http
、server
、location
- 默认值
fastcgi_limit_rate 0;
fastcgi_limit_rate 0;
【3】fastcgi_index
- 语法格式
fastcgi_index name;
- 含义解释
- 设置首页的名称,值为
$fastcgi_script_name
的值
- 设置首页的名称,值为
- 作用范围
http
、server
、location
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/www/scripts/php$fastcgi_script_name;
【4】fastcgi_param
- 语法格式
fastcgi_param parameter value [if_not_empty];
- 含义解释
- 设置自定义参数传递给
FastCGI
服务器使用
- 设置自定义参数传递给
- 作用范围
http
、server
、location
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param HTTPS $https if_not_empty;
3.3 缓存功能
fastCGI
和proxy
的缓存功能使用基本类似,对动态内容的缓存需要设置fastcgi_cache_valid
指令,否则不会进行缓存的。官方文档地址
【1】fastcgi_cache_path
- 语法格式
fastcgi_cache_path path [levels=levels] keys_zone=name:size [inactive=time]...
- 含义解释
- 设置缓存的路径和参数,先定义后使用
- 作用范围
http
fastcgi_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m;
【2】fastcgi_cache
- 语法格式
fastcgi_cache zone|off;
- 含义解释
- 使用
fastcgi_cache_path
定义缓存样式
- 使用
- 作用范围
http
、server
、location
- 默认值
fastcgi_cache off;
location ~ \.php$ {
fastcgi_cache mycache;
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 301 1h;
fastcgi_cache_valid any 1m;
}
【3】fastcgi_cache_methods
- 语法格式
fastcgi_cache_methods GET|HEAD|POST ...;
- 含义解释
- 对特定的请求方法进行缓存
- 作用范围
http
、server
、location
- 默认值
fastcgi_cache_methods GET HEAD;
fastcgi_cache_methods GET;
【4】fastcgi_cache_valid
- 语法格式
fastcgi_cache_valid [code ...] time;
- 含义解释
- 设置缓存时间不同的响应代码
- 作用范围
http
、server
、location
fastcgi_cache_valid 200 302 10m;
fastcgi_cache_valid 301 1h;
fastcgi_cache_valid any 1m;
【5】fastcgi_cache_use_stale
- 语法格式
fastcgi_cache_use_stale error|timeout|http_404
- 含义解释
- 设置腐败缓存
- 作用范围
http
、server
、location
- 默认值
fastcgi_cache_use_stale off;
fastcgi_cache_use_stale http_404;
3.4 场景说明
LNMP
、LNAMP
的动静分离场景
- (1) root 为同一路径
location / {
root /web/nginx/www;
}
location \.php$ {
root /web/nginx/www;
}
- (2) root 为不同的路径
location / {
root /web/nginx/app;
}
location \.php$ {
root /web/nginx/www;
}
- (3) fpm server 为另一主机
location / {
root /web/nginx/www;
}
location \.php$ {
fastcgi_pass fastcgi://172.16.100.9:9000;
}
4. 练习作业
4.1 场景说明
- 使用
nginx
反向代理(使用rr
调度)用户请求至两个以上的后端LAMP
服务器,服务器同时部署WordPress
和phpMyAdmin
服务。- (1) 手动更新所有节点上的
phpMyAdmin
至新版本 - (2) 用脚本实现手动更新
phpMyAdmin
的整个过程
- (1) 手动更新所有节点上的
- 在线升级的情况下,观察:
- (1) 后端服务器的错误日志,分析出错问题原因
- (2) 这就是生成环境中的软件发布操作,熟悉灰度发布等
4.2 解决方式
手动更新phpMyAdmin
服务
- 在
LAMP
中部署phpMyAdmin
服务的时候,用链接的方式指定安装目录,这样方便配置和更新操作。如配置/webapps/pma
目录链接至/webapps/pma-3.4
,之后升级新版本只需要将链接变更为/webapps/pma-3.6
即可。 - 我们手动更新时,在代理服务器上将其中一台标记为
down
或backup
,之后升级该服务器,完成之后再以同样方式升级另一台服务器。
写脚本更新phpMyAdmin
服务
- 我们才可以采用上述所说的,停止一台更新一台的方式。但是更好的做法就是,在代理服务器上运行脚本,修改配置、传递脚本过去、更新服务器等一系列的操作。
- 如果我们的脚本充分的进行了测试,之后再工作中就可以使用它了,方便我们之后软件升级时使用了。