Zero's Blog

Nginx负载均衡

Nginx负载均衡

nginx不单可以作为强大的 web 服务器,也可以作为一个反向代理服务器,而且nginx还可以按照调度规则实现动态、静态页面的分离,可以按照轮询、 ip 哈希、 URL 哈希、权重等多种方式对后端服务器做负载均衡,同时还支持后端服务器的健康检查。

如果只有一台服务器时,这个服务器挂了,那么对于网站来说是个灾难.因此,这时候的负载均衡就会大显身手了,它会自动剔除挂掉的服务器.

安装Nginx

Nginx 负载均衡一些基础知识

nginx 的 upstream 目前支持 4 种方式的分配

  • 轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
  • weight 指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
  • ip_hash 每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
  • fair(第三方) 按后端服务器的响应时间来分配请求,响应时间短的优先分配。
  • url_hash(第三方)

配置:

在http节点里添加

1
2
3
4
5
6
7
定义负载均衡设备的 IP及设备状态
upstream myServer {
server 127.0.0.19090 down;
server 127.0.0.18080 weight=2;
server 127.0.0.16060;
server 127.0.0.17070 backup;
}

在需要使用负载的 Server节点下添加

1
proxy_pass httpmyServer;

1 upstream 每个设备的状态
2 down 表示单前 的server 暂时不参与负载
3 weight 默认为1. weight 越大,负载的权重就越大。
4 max_fails :允许请求失败的次数默认为 1.当超过最大次数时,返回 proxy_next_upstream 模块定义的错误
5 fail_timeoutmax_fails 次失败后,暂停的时间。
6 backup: 其它所有的非 backup 机器 down 或者忙的时候,请求 backup 机器。所以这台机器压力会最轻。

Nginx 还支持多组的负载均衡,可以配置多个 upstream 来服务于不同的 Server.
配置负载均衡比较简单,但是最关键的一个问题是怎么实现多台服务器之间 session 的共享
下面有几种方法(以下内容来源于网络,第四种方法没有实践.)

  • 不使用 session,换作 cookie
    能把 session改成 cookie,就能避开 session 的一些弊端,在从前看的一本 J2EE 的书上,也指明在集群系统中不能用 session,否则惹出祸端来就不好办。如果系统不复杂,就优先考虑能否将 session 去掉,改动起来非常麻烦的话,再用下面的办法。

  • 应用服务器自行实现共享
    asp.net 可以用数据库或 memcached 来保存 session,从而在 asp.net 本身建立了一个session 集群,用这样的方式可以令 session 保证稳定,即使某个节点有故障,session也不会丢失,适用于较为严格但请求量不高的场合。但是它的效率是不会很高的,不适用于对效率 要求高的场合。

以上两个办法都跟 nginx 没什么关系,下面来说说用 nginx 该如何处理:

  • ip_hash
    nginx 中的 ip_hash 技术能够将某个 ip 的请求定向到同一台后端,这样一来这个 ip 下的某个客户端和某个后端就能建立起稳固的 session,ip_hash 是在 upstream配置中定义的
    1
    2
    3
    4
    5
    upstream backend {
    server 127.0.0.18080 ;
    server 127.0.0.19090 ;
    ip_hash;
    }

ip_hash 是容易理解的,但是因为仅仅能用 ip 这个因子来分配后端,因此 ip_hash是有缺陷的,不能在一些情况下使用

nginx 不是最前端的服务器。ip_hash 要求 nginx 一定是最前端的服务器,否则 nginx 得不到正确 ip,就不能根据 ip 作 hash。譬如使用的是squid为最前端,那么 nginx 取 i p时只能得到 squid 的服务器 ip 地址,用这个地址来作分流是肯定错乱的。

nginx 的后端还有其它方式的负载均衡。假如 nginx 后端又有其它负载均衡,将请求又通过另外的方式分流了,那么某个客户端的请求肯定不能定位到同一台 session应用服务器上。这么算起来,nginx 后端只能直接指向应用服务器,或者再搭一个 squid,然后指向应用服务器。最好的办法是用location 作一次分流,将需要 session 的部分请求通过 ip_hash 分流,剩下的走其它后端去。

  • upstream_hash
    为了解决 ip_hash 的一些问题,可以使用 upstream_hash 这个第三方模块,这个模块多数情况下是用作 url_hash 的,但是并不妨碍将它用来做 session 共享:

假如前端是 squid,他会将 ip 加入 x_forwarded_for 这个 http_header 里,用upstream_hash 可以用这个头做因子,将请求定向到指定的后端:

可见这篇文档:httpwww.sudone.comnginxnginx_url_hash.html
在文档中是使用 $request_uri 做因子,稍微改一下:

1
hash $http_x_forwarded_for;

这样就改成了利用 x_forwarded_for 这个头作因子,在 nginx 新版本中可支持读取 cookie 值,所以也可以改成:

1
hash $cookie_jsessionid;

假如在php中配置的 session 为无 cookie方式,配合nginx自己的一个 userid_module 模块就可以用nginx自发一个 cookie,可参见 userid模块的英文文档:

httpwiki.nginx.orgNginxHttpUserIdModule

另可用姚伟斌编写的模块 upstream_jvm_route:httpcode.google.compnginx-upstream-jvm-route