nginx 的 upstream目前支持 4 种方式的分配
- 轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
- weight 指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
- ip_hash 每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
- fair(第三方) 按后端服务器的响应时间来分配请求,响应时间短的优先分配。
- url_hash(第三方)
配置
#设定负载均衡的服务器列表
upstream backend_web{
ip_hash;
#weigth 参数表示权值,权值越高被分配到的几率越大
#max_fails 允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream 模块定义的错误
#fail_timeout max_fails 次失败后,暂停的时间。
#down 表示单前的server暂时不参与负载
#backup 其它所有的非backup机器down或者忙的时候,请求backup机器,这台机器压力会最轻。
server 10.10.192.72:8080 max_fails=3 fail_timeout=3s weigth=10;
server 10.10.157.102:8081 max_fails=3 fail_timeout=3s weigth=5;
server 10.10.192.72:8082 down;
server 10.10.157.102:8083 backup;
}
server
{
listen 80;
server_name www.imdst.com;
access_log /data/logs/test.access_log;
index index.html index.htm index.php;
location /{
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $remote_addr;
#请求转向backend_web定义的服务器列表
proxy_pass http://backend_web;
}
}
##################以下是https配置###################
server
{
listen 443;
server_name www.imdst.com;
access_log /data/logs/www.imdst.com.log;
index index.html index.htm index.php;
ssl on;
ssl_certificate sslkey/www.imdst.com.crt;
ssl_certificate_key sslkey/www.imdst.com.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
location /{
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://backend_sdk;
proxy_next_upstream error timeout http_500;
}
}
proxy_next_upstream
- 在Nginx配置文件中,proxynextupstream用于指定在什么情况下Nginx会将请求转移到其他服务器上。其默认值是proxynextupstream error timeout,即发生网络错误以及超时,才会重试其他服务器。默认情况下服务返回500状态码是不会重试的,如果想在响应500状态码时也进行重试,可以配置:
proxy_next_upstream error timeout http_500;
当然还有http502、http503、http_404等可以指定在出现哪些状态码的情况下需要重试。
当请求类型是POST时,Nginx默认不会失败重试,(但是
proxy_next_upstream
有一个选项non_idempotent
,生产环境不建议加上这个选项)通常情况下,如果请求使用非等幂方法(POST、LOCK、PATCH),请求失败后不会再到其他服务器进行重试。加上
non_idempotent
选项后,即使是非幂等请求类型(例如POST请求),发生错误后也会重试。如果使用该方法的多个相同请求对服务器的预期效果与单个请求的效果相同,则认为请求方法是幂等的。常见的HTTP请求方法中,GET是幂等的,而POST是非幂等的。
在做业务开发是如何理解幂等性,举个最简单的例子:GET方法一般用于获取数据,如果获取的是数据库数据,对应的是SELECT语句。同样的SELECT语句执行一次还是多次,都不会影响数据。而POST一般对应INSERT,如果执行多次后,可能会造成数据重复插入的问题。所以不要使用GET方法做一些INSERT操作,在业务开发时要遵循HTTP协议规范。
生产环境中为什么不建议加上non_idempotent选项?因为无论是发生500错误还是timeout,服务器上的业务可能都已经执行过了,而重试会导致非幂等方法重复执行,从而导致业务问题,例如一个请求会创建了多个订单,或者收到多条短信的问题。
实现多台服务器之间session的共享
- nginx中的
ip_hash
技术能够将某个ip的请求定向到同一台后端,这样一来这个ip下的某个客户端和某个后端就能建立起稳固的session,ip_hash
是在upstream配置中定义的:
upstream backend {
server 127.0.0.1:8080 ;
server 127.0.0.1:8081 ;
ip_hash;
}
ip_hash
是容易理解的,但是因为仅仅能用ip这个因子来分配后端,因此ip_hash
是有缺陷的,不能在一些情况下使用:- nginx不是最前端的服务器。
ip_hash
要求nginx一定是最前端的服务器,否则nginx得不到正确ip,就不能根据ip作hash。譬如使用的是squid为最前端,那么nginx取ip时只能得到squid的服务器ip地址,用这个地址来作分流是肯定错乱的。 - nginx的后端还有其它方式的负载均衡。假如nginx后端又有其它负载均衡,将请求又通过另外的方式分流了,那么某个客户端的请求肯定不能定位到同一台session应用服务器上。这么算起来,nginx后端只能直接指向应用服务器,或者再搭一个squid,然后指向应用服务器。最好的办法是用location作一次分流,将需要session的部分请求通过ip_hash分流,剩下的走其它后端去。
- nginx不是最前端的服务器。
Linux 核心参数优化
net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.tcp_max_syn_backlog = 4096
net.core.netdev_max_backlog = 32768
net.core.somaxconn = 32768
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_wmem = 8192 436600 873200
net.ipv4.tcp_rmem = 32768 436600 873200
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_reserved_ports = 10001-11000