解决方案:
1、使用客户端的cookie作为存放登录信息的媒介
cookie是将用户登录信息存储在用户终端的数据载体,与session的最大区别就是,session是存储在服务器端的;所以这就很容易解决这种session的多台服务器共享问题。当我们客户端进行登录的时候,访问的是服务器a,登录成功之后我们将session抽取出来存放在客户端的cookie里面;然后当我们客户端第二次进行访问的时候,访问的是服务器b,这次我们先在服务器b去查找是否有登录成功的session,如果为空,我们再对客户端的cookie进行查找,如果cookie里面已经存储有session,那么再将cookie里面的session同步到服务器b,那么整个流程就能走通了,用户也不用再次登录;
优点:这种方法实现起来简单,方便,很容易上手操作,不会加大数据库的负担;
缺点:如果客户端把cookie禁掉了的话,那么session就无法同步了,而且cookie的安全性不高,很容易外部被伪造使用;
2、使用mysql数据库存储session
既然每个服务器都需要使用同一个session,那么我们可以将session存放在同一个数据库里面,每次访问的时候,我们去数据库check一下是否有这个session或者这个session是否过期,然后就可以进行多台服务器的session同步了;
优点:使用这种方法简单、方便,很容易上手操作;
缺点:使用数据库来同步session,会加大数据库的IO,增加数据库的负担;同时,每次访问都需要拦截请求、查询数据库,导致多一层访问的业务层以及浪费读取数据库session时间;
3、使用memcache或者redis等缓存机制存放session
使用memcache或者redis等分布式缓存机制存放session数据,是现在很多大型项目负载均衡同步session的热门方案;它的原理是项目都使用的是同一个地方的memcache或者redis的缓存,当用户登录的时候,会把session存放在缓存里面,之后不管访问的是项目的那一台服务器,都会从同一个地方去获取session缓存,这样就很轻松实现了session同步;
优点:用缓存来同步session,不会加大数据库的负担,也不用手动去判断session是否存在或过期,省去部分业务逻辑,同时,由于redis等缓存是存放于服务器端,安全性也大大提高;
缺点:memcache或redis把内存分成很多种规格的存储块,有块就有大小,这种方式也就决定了,memcache或redis不能完全利用内存,会产生内存碎片,如果存储块不足,还会产生内存溢出。
把php.ini里的session save handler设置为memcache 或者 redis. 推荐使用memcache 如果用redis的话,目前没有好用的cluster解决方案,而redis还会
把数据回写到硬盘上,完全没必要。而memcache只需要很少的配置就能做cluster
4、ip_hash
nginx中的ip_hash技术能够将某个ip的请求固定到同一台后端应用服务器,这样一来这个ip下的某个客户端和某个后端就能建立起稳固的session,ip_hash是在upstream配置中定义的:
upstream backend { server 127.0.0.1:8001; server 127.0.0.1:8002; ip_hash; }
优点:ip_hash算法可以把一个ip映射到一台服务器上,这样可以解决session同步的问题。这样每个访客固定访问一个后端服务器,可以解决session的问题;
缺点:使用ip_hash进行session共享,它的原理是为每个访问者提供一个固定的访问ip,让用户只能在当前访问的服务器上进行操作,保持了session同步的,但是也造成了负载不均衡的问题,如果当前用户访问的服务器挂了的话,那就会出现问题了;
说明:因为这种方式只能用IP来分配后端,所以要求nginx一定要是最前端的服务器,否则nginx会取不到真实的客户端ip,那ip_hash就失效了。例如在服务器架构中使用squid做前端高速缓存,那么nginx取到的就是squid服务器的ip,用这个ip来做ip_hash肯定是不对的。再有,如果nginx的后端还有其他的负载均衡,将请求又分流了,那么对于某个客户端的请求,肯定不能定位到同一台应用服务器(例如php的fast-cgi服务器等),这样也不能做到session共享,如果在nginx后面再做负载均衡,我们可以再搭一台squid,然后再直接到应用服务器,或者用 location作一次分流,将需要session的部分请求通过ip_hash分流,剩下的走其它后端
upstream_hash 是nginx 的一个第三方模块,支持采用nginx 内部的各种变量作hash,然后针对生成的hash 值,用求余的方式分布到后端(backend)服务器上,达到负载均衡的目的。该模块一般情况下是用做url_hash的,但是也可以做session共享。
假如前端是squid,他会将ip加入x_forwarded_for这个http_header里,用upstream_hash可以用这个头做因子,将请求定向到指定的后端:
可见这篇文档:
在文档中是使用$request_uri做因子,稍微改一下:
hash $http_x_forwarded_for;
这样就改成了利用x_forwarded_for这个头作因子,在nginx新版本中可支持读取cookie值,所以也可以改成:
hash $cookie_jsessionid;
假如在php中配置的session为无cookie方式,配合nginx自己的一个userid_module模块就可以用nginx自发一个cookie,可参见userid模块的英文文档: