`
neverback
  • 浏览: 1549 次
  • 性别: Icon_minigender_1
  • 来自: 济南
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

关于nginx+tomcat负载均衡下tomcat故障后的的会话转移

阅读更多
最近自己尝试着在linux下面进行开发和学习,想想即使对于一般的企业应用,做一个小的集群也是有必要的,能防止单服务器down掉之后的尴尬,所以就在学习nginx+tomcat配置一个小型的集群,google之下也算搞定,然后自然涉及到session共享之类的问题,依旧想google之,前人经验后人乘凉,搜索后发现最多的文章的解决方式就是开启tomcat的session复制,还有比较多的情况是使用memcached session manager 这个开源框架,这样就能在某个tomcat故障时候防止用户会话失效,这两者都要对tomcat配置文件什么的进行一些不大不小的改动,而且在我尝试之后发现,开启tomcat session复制尤其不可取,尤其在session中内容比较多的情况下(当然,session中放太多东西本身就不应该..),效率很是问题,也有人说在nginx下用iphash,将同一ip会话粘在同一个tomcat服务器上,但是如果在这台tomcat服务器down掉的情况下,却没有给出一个比较好的会话转移解决方法。(或者我没搜到?)
额。前面罗嗦一通是前提,我的一个程序中的解决方法,不必像开启tomcat的session复制或者像memcached session mamager这样对tomcat的配置文件进行修改,只需要代码实现即可。 想法如下:

用memcached 存储用户信息,将会话的sessionId作为key,放了一个map用来存储信息,
这样在会话中如果所粘合的tomcat down掉,nginx将此次会话转发给其他服务器时候,将存储在memcached中的信息复制回来即可。像下面这样:
request--sessionFilter(会话转移filter)--powerFilter(权限验证filter)--action--
首先我在登录的时候做了如下操作:初始化信息
SessionCacheService.initSessionCache(sessionId,map);

因为采取iphash策略,用户会话是粘合在同一服务器上的,那么当这台服务器down掉后的处理:
用request.getRequestedSessionId();获取上一会话的sessionId去memcached中找,找到后将信息复制到此会话中.
/**
 * Created by IntelliJ IDEA.
 * User: bjslogin[at]gmail.com
 * Date: 11-8-2
 * Time: 上午10:28
 * 设置nginx为iphash,如果发生故障转移,即会将session信息转移至新的服务器
 */
public class SessionFilter implements Filter {
    private Logger logger = Logger.getLogger(getClass());

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        String url = request.getRequestURI();
        for(String c : PowerFilter.noFilterPages){
            if(url.indexOf(c) > 0){
                filterChain.doFilter(servletRequest,servletResponse);
                return;
            }
        }

        String requestedSessionId = request.getRequestedSessionId();
        HttpSession session = request.getSession();
        if(requestedSessionId.equals(session.getId())){
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }
        Map<String,Object> _map = SessionCacheService.getSessionCache(session.getId());
        if(_map == null){
            Map<String,Object> map = SessionCacheService.getSessionCache(requestedSessionId);
            if(map == null){
                filterChain.doFilter(servletRequest,servletResponse);
                return;
            }
            logger.info("开始转移...");
            SessionCacheService.initSessionCache(session.getId(),map);
        }

        filterChain.doFilter(servletRequest,servletResponse);
    }

    public void destroy() {

    }
}


然后我的powerFilter 权限验证filter如下:
/**
 * Created by IntelliJ IDEA.
 * User: bjslogin[at]gmail.com
 * Date: 11-8-1
 * Time: 下午2:23
 * 权限验证filter
 */
public class PowerFilter implements Filter {
    private Logger logger = Logger.getLogger(getClass());
    private FilterConfig filterConfig;
    private ApplicationContext ctx = null;
	protected static final String sessionErrorPage = "/sessionError.jsp";
	protected static final String noPermissionPage = "/noPermission.jsp";
	protected static final String[] noFilterPages = {"login.action","logout.action"};

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        String url = request.getRequestURI();
        logger.info("【"+request.getRemoteHost()+"[at]"+new Date()+"】"+url);

        for(String c : noFilterPages){
            if(url.indexOf(c) > 0){
                filterChain.doFilter(servletRequest,servletResponse);
                return;
            }
        }

        HttpSession session = request.getSession();
        Map<String,Object> map = SessionCacheService.getAndRefreshSessionCache(session.getId());
        if(map == null){
            HttpServletResponse response = (HttpServletResponse)servletResponse;
            response.sendRedirect(request.getContextPath() + sessionErrorPage);
            return;
        }

        LoginService loginService = (LoginService)getBean(LoginService.class);
        boolean flag = loginService.checkPrivate(request.getSession().getId(),StringUtils.substringAfter(url,request.getContextPath() + "/"));
        if(!flag){
            HttpServletResponse response = (HttpServletResponse)servletResponse;
            response.sendRedirect(request.getContextPath() + noPermissionPage);
            return;
        }

        filterChain.doFilter(servletRequest,servletResponse);
    }

    public void destroy() {

    }

    public Object getBean(Class clazz) {
        if (ctx == null) {
            ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
        }
        return ctx.getBean(clazz);
    }

}


看的出来我是用cache里面的信息来判断会话失效的,放弃使用HttpSession了,只用了它的ID,当然,这只是我的个人做法,要使用session存储信息的话,就是类似于将将memcached作为一个session信息的备份了,添加两个listener保证session和memcached同步即可,我的做法:
/**
 * Created by IntelliJ IDEA.
 * User: bjslogin[at]gmail.com
 * Date: 11-8-1
 * Time: 上午11:07
 * session失效时同时干掉缓存
 */
public class SessionCacheListener implements HttpSessionListener{

    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        // do nothing
        // 登陆时才初始化sessionCache内容
    }

    //session失效时同时移除缓存内容
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        HttpSession session = httpSessionEvent.getSession();
        SessionCacheService.removeSessionCache(session.getId());
    }
}


这个是监听session属性变化的listener,保证当session内容变化时候能同步到cache中
/**
 * Created by IntelliJ IDEA.
 * User: bjslogin[at]gmail.com
 * Date: 11-8-1
 * Time: 上午11:28
 * 监听session属性变化,同步cache
 */
public class SessionCacheAttributeListener implements HttpSessionAttributeListener {

    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        HttpSession session = httpSessionBindingEvent.getSession();
        String key = httpSessionBindingEvent.getName();
        Object value = httpSessionBindingEvent.getValue();
        SessionCacheService.putSessionCacheAttribute(session.getId(), key, value);
    }

    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        HttpSession session = httpSessionBindingEvent.getSession();
        String key = httpSessionBindingEvent.getName();
        SessionCacheService.removeSessionCacheAttribute(session.getId(), key);
    }

    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
        attributeAdded(httpSessionBindingEvent);
    }
}


这样就能保证session与cache内容同步了,只需要在SessionFilter的SessionCacheService.initSessionCache(session.getId(),map);方法之前将cache中的内copy到session中即可,下一步的powerFIlter判断用户信息就不会出现问题。
在我本机nginx+3个tomcat测试中,将正在被访问的tomcat人为down掉,确实是能保证会话平滑转移的,我的nginx的集群配置方式:
upstream localhost {  
      ip_hash;
      server localhost:8060;  
      server localhost:8070;  
      server localhost:8080;  
     }

server {  
            listen       8090;  
            server_name  localhost;     
            location / {  
              proxy_connect_timeout   3;  
              proxy_send_timeout      30;  
              proxy_read_timeout      30;  
              proxy_pass http://localhost;  
            } 
}   
}

不过据我所知,如果客户端禁用cookie的话,request.getRequestedSessionId()可能就有问题了,,不过。。不管啦!
这是我的一个解决方法,贴出来与大家分享。
毕业一年,还只是新手,如果这样做有什么错误的话,请指正,我会虚心学习,请言论不要过激。。谢谢。
还有,看了精华贴 【晒晒大家年龄和近期愿望吧】  心中真是感慨万千,感觉天朝上学的时间真是太长了,刚毕业没多久,就觉得时间已经不够用。同时祝帖子里面的朋友愿望都能实现(话说最多的愿望是找个女朋友?)!
分享到:
评论

相关推荐

    Nginx + Tomcat 负载均衡配置详解

    **Nginx + Tomcat 负载均衡配置详解** 在现代互联网应用中,服务器的高可用性和性能优化是至关重要的。Nginx 和 Tomcat 的组合常常被用来实现这样的目标,其中Nginx作为反向代理和负载均衡器,而Tomcat作为Java应用...

    nginx+tomcat7+memcached session会话保持

    本文将详细介绍如何在Nginx、Tomcat7和Memcached的环境下实现会话保持,确保用户在多台服务器之间切换时仍能保持其会话状态。 首先,我们要理解会话保持的重要性。在分布式系统中,用户可能与集群中的任何一台...

    Nginx+Tomcat负载均衡配置教程

    ### Nginx+Tomcat负载均衡配置教程 #### 一、Nginx 安装与配置 **1. 下载并安装Nginx** - **下载Nginx**:前往Nginx官方网站下载适合您操作系统的最新版本。推荐下载稳定版以确保运行稳定。 - **解压文件**:将...

    Nginx+tomcat+redis

    - **负载均衡**:Nginx可以基于多种策略(如轮询、最少连接、IP哈希等)分配请求到不同的Tomcat实例,从而实现负载均衡,提高系统的可用性和响应速度。 - **静态资源处理**:Nginx对静态文件(如CSS、JavaScript、...

    nginx+tomcat负载均衡实现

    `nginx`作为一款高性能的反向代理服务器和负载均衡器,常用于处理静态资源和分配请求,而`tomcat`则是Java应用服务器,专门处理动态内容。本文将深入探讨如何利用`nginx`和`tomcat`实现负载均衡,以提升系统性能和...

    linux下nginx+memecached+tomcat负载均衡故障转移

    总结起来,构建Linux下的Nginx+Memcached+Tomcat负载均衡和故障转移架构,需要综合考虑服务器配置、网络通信、缓存策略、健康检查以及应用层的设计。通过合理的架构设计和优化,可以构建出一个强大而稳定的Web服务...

    Nginx+tomcat负载均衡集群session复制 windos

    本文将详细介绍如何在Windows环境下,利用Nginx作为反向代理服务器,与Tomcat集群配合实现负载均衡,并进行session复制,确保用户会话在不同服务器之间的一致性。 首先,Nginx是一款轻量级、高性能的HTTP和反向代理...

    nginx+tomcat负载均衡集群思路步骤过程.docx

    【Nginx+Tomcat负载均衡集群部署】 在IT领域,构建高可用和高并发的Web服务是至关重要的。Nginx与Tomcat的组合是一个常见的解决方案,因为Nginx作为反向代理和负载均衡器,能有效分发流量到多个后端Tomcat服务器,...

    Nginx+KeepAlived+Tomcat负载架构

    本文将详细介绍如何通过`Nginx+KeepAlived+Tomcat`构建一个稳定、高效的负载均衡架构。 #### 二、关键技术介绍 ##### 1. Nginx - **简介**:Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)...

    nginx+tomcat7负载均衡+redis缓存session

    这种模式结合了Nginx的反向代理和负载均衡能力,Tomcat作为Java应用服务器处理业务逻辑,而Redis则用于高效地存储和共享用户会话(session)数据。下面我们将详细探讨这些技术组件及其相互作用。 **Nginx** Nginx...

    nginx+redis负载均衡、session共享

    这个方案结合了Nginx的反向代理和负载均衡能力,以及Redis的内存数据存储和分布式特性,用于处理高并发场景下的HTTP请求,并确保用户会话(session)在多台服务器之间的一致性。 首先,我们来详细了解一下Nginx。...

    Windows+Nginx+Tomcat做负载均衡同时实现session共享Demo

    在IT行业中,构建高效、可扩展的Web服务是至关重要的,而Windows+Nginx+Tomcat的组合在处理高并发请求时,常被用来搭建负载均衡系统,同时通过session共享来保证用户会话的一致性。这个“Windows+Nginx+Tomcat做负载...

    Nginx+Tomcat+Redis搭建均衡负载集群

    这个架构利用Nginx作为反向代理和负载均衡器,Tomcat作为Java应用服务器处理业务逻辑,而Redis则用作缓存系统以提升数据访问速度。下面我们将详细探讨这些组件的作用及其在集群环境中的配置与协同工作。 **Nginx** ...

    nginx+tomcat+redis完成session共享

    3. **配置Nginx**:在Nginx配置文件中,设置负载均衡策略,例如轮询、最少连接数或根据session ID进行粘滞会话。使用`proxy_pass`指令将请求转发到正确的Tomcat服务器,并配置`proxy_set_header`以传递session ID。 ...

    nginx+tomcat负载、集群简单搭建

    本文将详细介绍如何在Windows环境下进行Nginx+Tomcat负载均衡及集群的搭建过程,适合初学者参考。 #### 二、准备工作 1. **下载Nginx** - 访问官方下载页面:[http://nginx.org/en/download.html]...

    nginx+tomcat负载均衡集群(二)

    在本篇博文中,我们将深入探讨如何构建一个基于Nginx和Tomcat的负载均衡集群。这个集群配置有助于提升Web应用程序的性能、可用性和可扩展性。Nginx以其高效能的反向代理和负载均衡能力,常被用作前端服务器,而...

    实现基于nginx的tomcat负载均衡和集群配置

    本篇文章将详细讲解如何使用Nginx作为反向代理服务器来实现对Tomcat应用服务器的负载均衡和集群配置。 首先,我们需要理解Nginx和Tomcat的角色。Nginx是一款高性能的HTTP和反向代理服务器,常用于处理静态内容和...

    负载均衡nginx+tomcat+terracatta+nfs+mysql

    在构建高性能、高可用性的Web服务环境中,"负载均衡nginx+tomcat+terracotta+nfs+mysql"是一个常见的架构组合。这个组合充分利用了各组件的优势,以实现数据的高效处理、分布式存储以及会话共享,确保系统的稳定性和...

    Windows+Nginx+Tomcat搭建负载均衡和集群的tomcat压缩包

    本教程将探讨如何在Windows环境中利用Nginx作为反向代理服务器,与多个Tomcat实例配合,搭建一个负载均衡和集群的系统。这个压缩包包含多个版本的Tomcat,即qdky-tomcat-6.0.44.6、qdky-tomcat-6.0.44.5、qdks-...

Global site tag (gtag.js) - Google Analytics