开发者社区> 问答> 正文

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

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

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

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

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

展开
收起
爱吃鱼的程序员 2020-06-22 14:22:28 1062 0
1 条回答
写回答
取消 提交回答
  • https://developer.aliyun.com/profile/5yerqm5bn5yqg?spm=a2c6h.12873639.0.0.6eae304abcjaIB

    拿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应用服务器集群扩展.

    引用来自“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应用服务器集群扩展.

    回复 @eechen:同样多谢大神,我刚开始学习nginx,太复杂的话反而我怕造成其他问题,ip_hase这样的方式也算是适合我们想在的系统环境了,不是完全“均衡”的负载,但是也能分担单个节点压力,存在节点的宕机风险导致部分用户无法使用,也好过现在单个节点承受的风险,是不是这个道理哈~~这个你最好问下Tengine作者 @shudu,看看有没有可行的方法。把内网特定的IP段用Nginx分流到后端Tomcat上,可以试着这样干:

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

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

    推荐你使用Tengine:

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

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

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

    兼容从nginx转tengine有无什么限制?都兼容么?赞一个mark客户端服务器session是靠浏览器cookie维持的,每次去请求都会带一个参数SESSIONID。so...只要把nginx的分发策略设置为根据cookie中的SESSIONID来分发。可以满足你的需求。只要第一次登陆(不管ip是否登陆过)都会走负载,重新分配节点;如果已经访问过(带cookie)则可以保证分配到同一节点。QQ:875881559欢迎交流
    2020-06-22 14:22:45
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
大规模场景下KubernetesService 负载均衡性能 立即下载
CentOS Nginx PHP JAVA 多语言镜像使用手 立即下载
CentOS Nginx PHP JAVA多语言镜像使用手册 立即下载