`
408516584
  • 浏览: 18001 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Nginx+Tomcat负载平衡,Redis管理session存储

阅读更多

本文的环境:

              1.CentOs6.4 minimal

              2.jdk1.7.0_71

              3.Tomcat7.0.65

              4.Nginx1.8

              5.Redis3.0.5

              6.vm11

环境配置不多说了,假设环境都已经装好。我虚拟机的ip地址是192.168.233.129 后面就不再解释了,直接用。

 

修改nginx配置信息    cd /usr/local/nginx/conf

vim nginx.conf

配置负载均衡 ,增加下面的配置 

upstream localhost {

         server      localhost:8080;

         server      localhost:8081;          

 }

 

server的location 中增加

proxy_pass   http://localhost;

 

ok 重启下nginx  cd /usr/local/nginx/sbin

./nginx -s reload

接下来访问http://192.168.233.129

ok 能够正常访问,显示了tomcat默认页,表示配置成功。

nginx 负载均衡默认是用轮询的方式,为了能够看到每次请求都被转发到了不同的tomcat上的效果,我们分别在webapps下ROOT下增加test.jsp  简单的一句话来表示这是tomcat1还是tomcat2。

 

ok 增加好之后再访问http://192.168.233.129/test.jsp 就显示tomcat1或者tomcat2,刷新页面,就会交替显示tomcat1  tomcat2.

 




 
 ok 如果能够交替显示表示负载均衡配置成功了。

 

ok 接下来就要解决session的问题了,打开F12看cookie,发现每次刷新都是新的sessionid,这样肯定是不行的,解决集群环境下的session共享有很多实现的方式,可以通过在upstream下配置 ip_hash;来根据ip指定到固定一台tomcat服务器来解决session的问题。配置完后之后再重启nginx    再刷新页面发现sessionid不变了,无论怎么刷新sessionid都不会变了,而且页面只显示tomcat1,说明现在是固定的访问tomcat1服务器了,而不是轮询的方式。

 

ok 到这里为止,我都非常的顺利,几乎没什么问题,但在配置redis来管理session的时候,问题就来了,而且还是相当的蛋疼,花了一天的时间终于解决了,也是我写这篇的主要原因。

 

ok 接下来我们要实现的是用轮询的方式实现session共享,本文用的方式是用redis来集中管理session,当一个请求过来,tomcat是去redis里找这个sessionid是否存在。

 

首先先把tomcat的依赖包分别拷到tomcat/lib目录下,我一开始用的包是

1.tomcat-redis-session-manager-1.2-tomcat-7.jar
2.jedis-2.1.0.jar
3.commons-pool-1.6.jar
 

 

然后分别修改tomcat下的context.xml配置文件,增加如下配置

 

 

<Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" />
<Manager className="com.radiadesign.catalina.session.RedisSessionManager"
                host="localhost"
                port="6379"
                database="0"
                maxInactiveInterval="60" />
    ok,配置好了,但是在启动tomcat的时候报错了,错误信息如下:
caused by: org.apache.catalina.LifecycleException: Unable to attach to session handling valve; sessions cannot be saved after the request without the valve starting properly.
 借助有道词典看的懂错误的大概意思,但是不知道怎么解决,不用怕,把错误信息复制一下到网上查一下,肯定能解决,因为毕竟我又不是第一个人配置这玩意,别人肯定也会碰到这问题。一点都不用慌,嗯,抱着这样的心态上网查了半天,结果居然没有一个人碰到这问题,我简直日了狗了。
于是看看别人的博客看别人是怎么做的,几乎所有的博客都说要去tomcat-redis-session-manager库的主页
https://github.com/jcoleman/tomcat-redis-session-manager
下载源码,修改build.gradle的依赖包版本,改成你自己的版本,然后重新构建项目,用构建生成的jar包。
不就是要编译打包嘛,为什么要弄的这么麻烦,而且也没用过gradle来构建项目,所以我是直接把源码拷到eclipse,注意这个项目有很多分支和tags,有些比较早的版本是依赖common-pool的jar包,我是下的master的分支,所以加的是common-pool2的jar包,要不然会报找不到类的错误,把依赖包加进来,通过export jar文件,来生成jar包。到这里,我的jar包变成了下面的样子
1.common-pool2-2.4.2.jar
2.jedis-2.5.1.jar
3.tomcat-redis-session-manager-1.2-mine.jar(自己通过源码编译生成的)
 
ok,把这3个jar包去替换原来的3个jar,然后还要修改一下context.xml配置文件,否则会提示找不到类,因为master分支的包名变了,修改后的context.xml文件如下
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />  
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"  
         host="localhost"  
         port="6379"  
         database="0"  
         maxInactiveInterval="60" /> 
 
重启tomcat,嗯,感觉这次肯定没问题了。
结果,还是报同样的错,我简直日了狗了,难道真的要用gradle来构建项目才行?这不科学啊,不就是编译几个java类打成jar包吗,改不改build.gradle依赖包版本应该没有半毛钱关系,又不会影响源代码。但是呢,实在没有办法了,还是决定试一下吧。我想gradle应该类似maven应该很简单吧,于是下了个gradle-2.8。通过修改build.gradle的依赖版本,通过 gradle bulid的命令来构建项目,这里也有一些坑,只改依赖版本,根本构建不成功,不过构建过程碰到的问题,网上都找到了
一个是需要把maven私服给注释了,因为没帐号密码,直接让它去maven中央仓库找,或者你可以配开源中国的,速度快点,不过也就才几个包,无所谓拉,懒的搞,另外一个是需要把 signing那一段注释掉。修改后build.gradle文件如下
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'signing'

group = 'com.orangefunction'
version = '2.0.0'

repositories {
  mavenCentral()
}

compileJava {
  sourceCompatibility = 1.7
  targetCompatibility = 1.7
}

dependencies {
  compile group: 'org.apache.tomcat', name: 'tomcat-catalina', version: '7.0.65'
  compile group: 'redis.clients', name: 'jedis', version: '2.5.1'
  compile group: 'org.apache.commons', name: 'commons-pool2', version: '2.4.2'
  //compile group: 'commons-codec', name: 'commons-codec', version: '1.9'

  testCompile group: 'junit', name: 'junit', version: '4.+'
  testCompile 'org.hamcrest:hamcrest-core:1.3'
  testCompile 'org.hamcrest:hamcrest-library:1.3'
  testCompile 'org.mockito:mockito-all:1.9.5'
  testCompile group: 'org.apache.tomcat', name: 'tomcat-coyote', version: '7.0.65'
}

task javadocJar(type: Jar, dependsOn: javadoc) {
  classifier = 'javadoc'
  from 'build/docs/javadoc'
}

task sourcesJar(type: Jar) {
  from sourceSets.main.allSource
  classifier = 'sources'
}

artifacts {
  archives jar

  archives javadocJar
  archives sourcesJar
}

//signing {
//  sign configurations.archives
//}

task copyJars(type: Copy) {
  from configurations.runtime
  into 'dist'  
}

uploadArchives {
  repositories {
    mavenDeployer {
      beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

      //repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
      //  authentication(userName: sonatypeUsername, password: sonatypePassword)
      //}
      //repository(url: "https://oss.sonatype.org/content/repositories/snapshots") {
      //  authentication(userName: sonatypeUsername, password: sonatypePassword)
      //}

      pom.project {
        name 'tomcat-redis-session-manager'
        packaging 'jar'
        description 'Tomcat Redis Session Manager is a Tomcat extension to store sessions in Redis'
        url 'https://github.com/jcoleman/tomcat-redis-session-manager'

        issueManagement {
          url 'https://github.com:jcoleman/tomcat-redis-session-manager/issues'
          system 'GitHub Issues'
        }

        scm {
          url 'https://github.com:jcoleman/tomcat-redis-session-manager'
          connection 'scm:git:git://github.com/jcoleman/tomcat-redis-session-manager.git'
          developerConnection 'scm:git:git@github.com:jcoleman/tomcat-redis-session-manager.git'
        }

        licenses {
          license {
            name 'MIT'
            url 'http://opensource.org/licenses/MIT'
            distribution 'repo'
          }
        }

        developers {
          developer {
            id 'jcoleman'
            name 'James Coleman'
            email 'jtc331@gmail.com'
            url 'https://github.com/jcoleman'
          }
        }
      }
    }
  }
}

 

 

 其实根本不需要改依赖版本,直接用默认的就可以了,原因我上面说过了。

ok,我们再用gradle build 来构建项目,这次终于成功了,看构建日志会发现,他会去下载依赖包,所以如果用gradle来构建的话,就不需要再另外去下载jar包了,,gradle已经帮你下载了,跟maven类似,也有个本地仓库,在用户目录下\.gradle\caches\modules-2\files-2.1,只要把这jar包拷过去就可以了。

 

ok 这下总可以了吧,把构建生成的jar包再替换tomcat中的。然后再重启

 

结果你猜怎么着,没错,还是报同样的错误,我简直又日了狗了,简直奔溃,因为网上根本搜不到这个问题的解决方案

Stack Overflow上也去查了。

 

试了各种的方法,还去专门深入了解了一下tomcat的原理,都没有什么卵用,好吧,只能根据错误提示,去源码里查原因了,找到出错的那一行,

 

/**
   * Start this component and implement the requirements
   * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
   *
   * @exception LifecycleException if this component detects a fatal error
   *  that prevents this component from being used
   */
  @Override
  protected synchronized void startInternal() throws LifecycleException {
    super.startInternal();

    setState(LifecycleState.STARTING);

    Boolean attachedToValve = false;
    for (Valve valve : getContainer().getPipeline().getValves()) {
      if (valve instanceof RedisSessionHandlerValve) {
        this.handlerValve = (RedisSessionHandlerValve) valve;
        this.handlerValve.setRedisSessionManager(this);
        log.info("Attached to RedisSessionHandlerValve");
        attachedToValve = true;
        break;
      }
    }

    if (!attachedToValve) {
      String error = "Unable to attach to session handling valve; sessions cannot be saved after the request without the valve starting properly.";
      log.fatal(error);
      throw new LifecycleException(error);
    }

    try {
      initializeSerializer();
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
      log.fatal("Unable to load serializer", e);
      throw new LifecycleException(e);
    }

    log.info("Will expire sessions after " + getMaxInactiveInterval() + " seconds");

    initializeDatabaseConnection();

    setDistributable(true);
  }
 

 

 看抛出的异常说明attachedToValve是false,说明if (valve instanceof RedisSessionHandlerValve) 这句是false。

ok,为了能够看清这个valve到底是什么东西,于是在这句之前加个日志打印一下看是什么,这里写日志的时候一开始把valve写成value了,我靠,我一直以为是value,长的太他妈像了。

 

for (Valve valve : getContainer().getPipeline().getValves()) {
    	log.info("valve======================>" + valve.getClass().getName());
      if (valve instanceof RedisSessionHandlerValve) {
        this.handlerValve = (RedisSessionHandlerValve) valve;
        this.handlerValve.setRedisSessionManager(this);
        log.info("Attached to RedisSessionHandlerValve");
        attachedToValve = true;
        break;
      }
    }
 

 

 ok,改完之后,直接用eclipse的export 重新打成jar包来替换tomcat中的,这时候可以看到刚刚添加的日志

 

INFO: valve======================>org.apache.catalina.core.StandardContextValve
 

 

 ok,valve 果然不是RedisSessionHandlerValve,看来valve没取到值,是不是在context.xml中配置有问题?

于是又去检查了一遍,发现RedisSessionHandlerValve类名没有写错,于是又去看了一下打印的日志。

这一次看,有惊天大突破,平时waring的日志啊什么的肯定都是不看的,但是这次发现这个waring有点特别

 

WARNING:   No rules found matching 'Context/Value'.
 

 

总感觉报错跟这个有关,警告说没有匹配的规则,那应该还是配置文件的问题了,到这里的时候突然想到写日志的时候把valve写成value了,于是去官网确认了一下,到底是value还是valve。



 

 好吧,果然是写错了,简直崩溃,看来下次配置文件应该用复制的,而不是自己手打。把value改成valve之后,再重启tomcat,ok,终于不报错了。把2台tomcat跑起来,测试下redis管理session的效果。

        可以看到刷新页面,tomcat1和tomcat2交替显示,并且sessionid不变。

        然后去redis 用命令看一下,keys * ,发现存了一个session,ok,到此Nginx负载均衡+Tomcat集群+Redis管理session终于配置成功。

          既然是配置文件写错了,那我用之前的3个jar可以吗,于是又把最开始的3个jar包来替换tomcat中的,记得还要改下context.xml配置,因为包名改了,之前说过的。测试了之后发现一点问题也没有,完全可以用最开始的那3个jar包。

          最后来个非常非常重要的总结,你前面可以都不看,但是总结你应该看看,因为很重要,所以字体要大点。

 

 

总结:用Tomcat通过redis来管理session所需要用到的依赖包tomcat-redis-session-manager.jar,完全没有必要自己去下载源码,然后修改build.gradle的依赖包的版本,再重新构建。真的,我不知道为什么博客几乎所有有关redis管理session的文章都说要自己重新构建,真的没必要。还有的人说如果用jedis-2.1.jar则要用commons-pool jar包,如果要jedis-2.5以上则要用commons-pool2的jar包,真的完全错误。我不知道他们自己有没有测试过。这里说下什么时候用commons-pool,什么时候用commons-pool2,因为commos-pool2的包名发生了变化,所以版本导不对会报找不到类异常。

 

你可以直接去github里下载已经编译好的jar包,比如tomcat-redis-session-manager-1.2-tomcat-7.jar,他里面依赖的是commons-pool版本的jar包,如果你想用commons-pool2,你可以把master分支源码拉下来自己打jar包,master里依赖的commons-pool2,看RedisSessionManager这个类也知道,

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
 

 

他导的是commons-pool2。

 

所以,最终你可以用我一开始用的3个jar包,也可以用我后来的3个jar包,我都测试过,都没问题。

 

ok,现在我把这两组jar包都上传,你们可以直接下载我的。

 

commons-pool2-2.4.2版本之所以比上面那个大那么多是因为,tomcat-redis-session-manager-1.2-mine.jar这个包把依赖包也打进来了,所以,应该只要拷这个到tomcat下就可以了,我没试过,有兴趣的可以试一下。

 

 

  • 大小: 18.7 KB
  • 大小: 19.1 KB
  • 大小: 31.5 KB
分享到:
评论

相关推荐

    nginx+tomcat+redis完成session共享

    2. **添加session存储库**:在Tomcat服务器中,需要添加一个session存储库,通常是一个Java的HttpSessionListener,以便在session创建或销毁时与Redis进行交互。你可以使用第三方库如`spring-session-data-redis`来...

    Nginx+tomcat+redis

    - **session共享**:在分布式环境中,Redis可以作为session存储,解决跨服务器的session共享问题,确保用户会话的一致性。 - **消息队列**:Redis支持发布/订阅模型,可以作为简单消息队列,用于异步处理任务或...

    nginx+tomcat6+redis实现session共享Jar文件

    同时,需要配置session存储路径为redis的地址。 3. **添加共享session的jar文件**:压缩包中的"tomcat6+redis做session共享亲测可用"文件可能包含了一个实现了session共享功能的jar文件,需要将其添加到Tomcat的lib...

    nginx+tomcat8.5+redis完成session共享

    我们将配置`Tomcat`使用`Redis`作为session存储,这样每当session数据发生变化时,都会自动同步到`Redis`中。 实现session共享的关键步骤如下: 1. **安装与配置**:首先,我们需要在服务器上安装`Nginx`、`Tomcat...

    nginx+redis负载均衡、session共享

    为了解决这个问题,我们可以使用Redis作为session存储。 Redis是一个高性能的键值存储系统,它可以快速读写大量数据,特别适合存储session这类小数据量但频繁读写的场景。通过配置Nginx和后端应用(如Tomcat),...

    Nginx+Tomcat+Redis实现负载均衡过程中session所需架包

    将session存储在Redis中,各个Tomcat实例可以共享这些数据。为了实现这一目标,可以使用一个名为`Jedis`的Java客户端库与Redis进行交互。在Tomcat中,可以通过实现`HttpSession`接口的自定义session管理器,或者使用...

    redis缓存服务器Nginx+Tomcat+redis+MySQL实现session会话共享

    "redis缓存服务器Nginx+Tomcat+redis+MySQL实现session会话共享"的主题旨在探讨如何利用这些技术组件来实现这一目标。以下是相关知识点的详细说明: **Redis**:Redis是一个高性能的键值数据存储系统,常用于做缓存...

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

    使用Redis作为session存储,可以避免单个服务器上session数据丢失,同时使得session数据在多台服务器间共享,这对于负载均衡环境至关重要。通过将session ID作为键,session数据作为值存储在Redis中,Nginx可以在...

    Keepalived+nginx+tomcat+redis_session_share

    本案例通过搭建一个基于`Keepalived`、`nginx`、`Tomcat`及`Redis`的服务集群来实现应用服务的高可用性和负载均衡,并通过`Redis`实现了`Tomcat`间的`Session`共享功能。 ### 一、环境简介 - **服务器配置**:两台...

    Nginx+Tomcat+Redis搭建高性能负载均衡集群Session共享

    超详细Nginx+Tomcat+Redis搭建高性能负载均衡集群Session共享搭建说明,按文档步骤可轻松搭建并实现session共享

    Tomcat7+Redis+Session 负载之后session 共享 tomcat jar包

    标题 "Tomcat7+Redis+Session 负载之后session 共享 tomcat jar包" 涉及的是在使用Nginx做负载均衡时,如何通过集成Redis来实现Tomcat7服务器之间的Session共享,从而确保用户在不同服务器之间切换时仍然能够保持...

    nginx+tomcat实现负载均衡,共享session的两种方式

    nginx+tomcat实现负载均衡,共享session的两种方式: 1.使用Redis共享session 2.使用tomcat的组播功能。

    Nginx+Tomcat+Redis集群和session共享所有jar包

    Nginx+Tomcat+Redis实现应用服务器集群负载均衡和Session共享所需要的所有jar包,包括如下jar包:commons-logging-1.2.jar,commons-pool2-2.6.0.jar,jedis-2.9.0.jar,tomcat-juli-7.0.90.jar,tomcat-redis-...

    nginx+tomcat7+jdk1.7+redis--jar.rar

    标题 "nginx+tomcat7+jdk1.7+redis--jar.rar" 提示我们这是一个关于在Web服务器架构中集成Nginx、Tomcat7、Java 1.7和Redis的解决方案,特别是涉及到使用Redis作为Session缓存的配置。描述中强调了在下载和使用这些...

    nginx+tomcat+redis存储session

    在Tomcat的`context.xml`或`server.xml`中配置`Manager`元素,使用`org.apache.catalina.session.JDBCStore`或`org.apache.catalina.session.redis.RedisStore`(如果使用的是Redis作为session存储)。 3. **引入...

    NGINX + TOMCAT 6 + REDIS 实现负载均衡 session会话同步

    这里我们选择使用REDIS,一个开源、高性能的键值数据存储系统,可以作为共享session存储。通过在TOMCAT中配置session复制或者将session持久化到REDIS,可以确保用户的session会话在所有服务器间保持一致。具体步骤...

    nginx2.8.1+tomcat7+redis1.8 session共享

    nginx2.8.1+tomcat7+redis1.8 session共享,windows环境下,jar包都包含,直接运行即可,把redis服务,tomcat两个,niginx负载平衡,session共享,参考别人的例子,自己总结的。

    nginx+tomcat8.+redis__session__单点登录、会话共享.zip

    标题中的"nginx+tomcat8.+redis__session__单点登录、会话共享"涉及到的是在分布式系统中如何实现用户会话(Session)的共享和单点登录(Single Sign-On, SSO)的问题。这里主要涉及到三个核心组件:Nginx、Tomcat和...

Global site tag (gtag.js) - Google Analytics