负载均衡调度器最大程度地让用户不必关心后端服务器,我们知道,当采用RR调度策略时,即便是同一用户对同一内容的多次请求,也可能被转发到了不同的后端服务器,这听起来似乎没什么大碍,但有时候,或许会带来一些问题。
当某台后端服务器启用了Session来本地化保存用户的一些数据后,下次用户的请求如果转发给了其他后端服务器,将导致之前的Session数据无法访问;
后端服务器实现了一定的动态内容缓存,而毫无规律的转发使得这些缓存的利用率下降。
如何解决这些问题呢?从表面上看,我们需要做的就是调整调度策略,让用户在一次会话周期内的所有请求始终转发到一台特定的后端服务器上,这种机制也称为黏滞会话(Sticky Sessions),要实现它的关键在于如何设计持续性调度算法。
既然要让调度器可以识别用户,那么将用户的IP地址作为识别标志最为合适,一些反向代理服务器对此都有支持,比如Nginx和HAProxy,它们可以将用户的IP地址进行Hash计算并散列到不同的后端服务器上。
对于Nginx,只需要在upstream中声明ip_hash即可,如下所示:
upstream backend {
ip_hash;
server 10.0.1.200:80;
server 10.0.1.201:80;
}
除此之外,你还可以利用Cookies机制来设计持久性算法,比如调度器将某个后端服务器的编号追加到写给用户的Cookies中,这样调度器便可以在该用户随后的请求中知道应该转发给哪台后端服务器。这样做可以更加细粒度地追踪到每一个用户,试想一下,当有很多用户隐藏在一个公开IP地址后面时,利用Cookies的持久性算法将显得更加有效。
我们已经实现了黏滞会话,但是如此一来,黏滞会话可能或多或少地破坏了均衡策略,至少像权重分配这样的动态策略已经无法工作,我们对此不能视而不见,否则前面的努力即将付诸东流。
当然,问题的关键在于,我们究竟是否要通过实现黏滞会话来迁就系统的特殊需要呢?在权衡代价之后你认为是否值得呢?最为关键的问题是前面提到的两个问题是否能从根本上避免呢?如果可以,这很值得去考虑。
事实上,在后端服务器上保存Session数据和本地化缓存,的确是一件不明智的事情,它使得后端服务器显得过于个性化,以至于和整个系统格格不入,如果允许的话,我们应该尽量避免这样的设计,比如采用分布式Session或者分布式缓存等,让后端服务器的应用尽量与本地无关,也可更好地适应环境。