nginx负载均衡ip_hase策略下用户会不会永远锁定到一个节点了?

夏天198801 发布于 2013/11/19 15:33
阅读 2K+
收藏 6

MySQL连接为什么挂死了?别踩坑!>>>

最近apache做了一个企业集群项目的反向代理,发现当高峰期的时候会出现503的报错,但是系统页面刷新一下几十秒之后就正常了,没有找到好的办法解决

于是想到用更好的nginx,并且想配置负载均衡,但是由于我们的系统是SSO单点登陆的集成项目,存在session的问题,找开发弄session序列化弄不好,人也不好协调,就想采用nginx的ip_hase策略;

在网上找了半天都没有具体看懂这种策略的逻辑原理,只不过大概知道是根据客户端IP锁定到其中一个节点;

现在就是想找位大师了解下,ip_hase负载分发策略的时候 具体怎么实现的;会不会出现当用户第一次登陆系统的时候分发到某一个节点,然后从此这个用户就永远锁定到这个节点了,什么情况下用户能够在登陆访问的时候重新根据逻辑选择节点?

加载中
0
eechen
eechen

拿PHP提供的session来说,默认使用的是文件存储的方式,会话文件就保存在当前的服务器,一般是/tmp下:
session.save_handler=files
session.save_path=/tmp
PHP的会话机制会给客户端设置一个cookie用来保存sesseion_id,对应服务器上的会话文件/tmp/sess_sesseion_id

把这些session绑定在本机的Web应用放到Nginx的upstream应用集群应该是不合适的,就算
设置ip_hash让固定IP只访问一个后端,但如果客户端IP在会话中改变,那就有可能连上后端其他的服务器,这样会导致找不到会话.还有如果这台后端服务器宕机,那用户的会话也会丢失.

所以最好还是自己用cookie实现一套适合自己的session机制,比如用mysql内存表或者memcached来保存cookie对应的会话数据,非关键和不敏感的数据直接设置cookie保存到客户端,这样会话数据就不会存储在具体的应用服务器上,方便了使用Nginx的upstream进行php-fpm应用服务器集群扩展.

0
夏天198801
夏天198801

引用来自“eechen”的答案

拿PHP提供的session来说,默认使用的是文件存储的方式,会话文件就保存在当前的服务器,一般是/tmp下:
session.save_handler=files
session.save_path=/tmp
PHP的会话机制会给客户端设置一个cookie用来保存sesseion_id,对应服务器上的会话文件/tmp/sess_sesseion_id

把这些session绑定在本机的Web应用放到Nginx的upstream应用集群应该是不合适的,就算
设置ip_hash让固定IP只访问一个后端,但如果客户端IP在会话中改变,那就有可能连上后端其他的服务器,这样会导致找不到会话.还有如果这台后端服务器宕机,那用户的会话也会丢失.

所以最好还是自己用cookie实现一套适合自己的session机制,比如用mysql内存表或者memcached来保存cookie对应的会话数据,非关键和不敏感的数据直接设置cookie保存到客户端,这样会话数据就不会存储在具体的应用服务器上,方便了使用Nginx的upstream进行php-fpm应用服务器集群扩展.

大师,我们的应用客户端是自己的OA网络环境,用户使用过程中终端的IP是不会变的,也就是说,采用这个策略的话,除非用户的PC重新开机获取IP,然后用户登录系统的时候nginx才有机会重新分发节点是吧 ;不然用户只要不关机就锁定在一个节点了,不是完全的“均衡”负载是吧,我在想有没有让nginx在用户每次重新登录的时候都会来重新根据IP来判断分配节点,然后只要不退出系统就一直锁定在一个节点的办法(因为系统内部很多单点登录的子模块)
PS,我们的服务是通过tomcat发布出去的
夏天198801
夏天198801
回复 @eechen : 同样多谢大神,我刚开始学习nginx,太复杂的话反而我怕造成其他问题,ip_hase这样的方式 也算是适合我们想在的系统环境了,不是完全“均衡”的负载,但是也能分担单个节点压力,存在节点的宕机风险导致部分用户无法使用,也好过现在单个节点承受的风险,是不是这个道理哈~~
eechen
eechen
这个你最好问下Tengine作者 @shudu ,看看有没有可行的方法。
0
eechen
eechen
把内网特定的IP段用Nginx分流到后端Tomcat上,可以试着这样干:

server {
	if ($remote_addr = 192.168.0.20) {
		location ~ \.(jsp|do)$ {
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header X-Forwarded-For $remote_addr;
			proxy_set_header Host $host;
			proxy_pass http://192.168.0.1:8080;
		}
	}
}

把来自192.168.0.20的jsp和do请求proxy给后面192.168.0.1的服务器。
条件$remote_addr那里可以用正则匹配一个IP段,这样应该就可以把该IP段的动态请求导到指定的Tomcat服务器上。
0
光石头
光石头
后台系统是java吗?
光石头
光石头
回复 @夏天198801 : 不一定非要序列化,可以后台转换成json,存入memcached,取出json再映射成session
夏天198801
夏天198801
回复 @屁屁果 :额,这个之前试过,但是后来发现tomcat里面有一个工程的session没有序列化,做不了session共享,上面描述问题里面我也提到过了,我们的开发不好协调,找他们做session序列化没做好
光石头
光石头
回复 @夏天198801 : 可以扩展tomcat,实现容器级别的session共享,就和应用没有关系了 http://www.9iu.org/2011/11/25/tomcat-memcached-session-sso.html
夏天198801
夏天198801
是啊,后台是java,容器是tomcat
0
leo108
leo108

可以把session托管到memcache或者redis嘛

0
shudu
shudu

推荐你使用Tengine:

1、使用Tengine的consistent_hash功能,以你的登录的cookie为key,这样的话一个固定的用户(登录cookie值)可以hash到一台固定的机器上。

2、如果没有登录(即没有登录cookie),则使用round-robin方式(默认的负载均衡方式)。

3、你可以使用if来判断cookie值是否为空。

shudu
shudu
兼容
Aceslup
Aceslup
从nginx转tengine有无什么限制?都兼容么?
0
番茄炒鸡蛋
番茄炒鸡蛋
客户端服务器session是靠浏览器cookie维持的,每次去请求都会带一个参数SESSIONID。so...只要把nginx的分发策略设置为根据cookie中的SESSIONID来分发。可以满足你的需求。只要第一次登陆(不管ip是否登陆过)都会走负载,重新分配节点;如果已经访问过(带cookie)则可以保证分配到同一节点。
番茄炒鸡蛋
番茄炒鸡蛋
QQ:875881559 欢迎交流
返回顶部
顶部