文档章节

单点优化系列--session共享踩坑记

j
 java_龙
发布于 2017/08/17 16:15
字数 1463
阅读 1103
收藏 81

本文将继续单机架构升级集群系列博文, 记录tomcat的Session共享工作的记录,希望能帮助到需要的朋友们,也欢迎大牛们批评指正!!       

背景

        在博文( https://my.oschina.net/u/2342969/blog/995598 )中描述了本次架构升级的背景

        在博文( https://my.oschina.net/u/2342969/blog/1036702 )中记录了redis主从集群搭建

        在博文(https://my.oschina.net/u/2342969/blog/1162829 )中记录了 nginx+keepalived主从集群高可用搭建工作

        以上博文有需要的朋友们可以观阅

本文将记录 tomcat的Session共享工作, 在此参考了 spring官网文档(

http://docs.spring.io/spring-session/docs/1.3.1.RELEASE/reference/html5/#httpsession-redis-xml

)

概述

    基于以前博文可以了解到,现阶段,我们是一台nginx、2台tomcat       

    在我们未做session共享的情况下,使用的nginx的iphash策略,以致停掉一个tomcat_A,所有请求都会集中到另外一台tomcat_B 并需要重新登陆, tomcat_A启动后,已经请求道tomcat_B的请求量还是不会减少,

    做了session共享的应用,是基于 tomcat sessionmanager 做的,依赖tomcat版本,需要修改服务器配置,以致如需换应用服务器还需要重新搭建

    现优化方案,基于spring session,将session共享做到应用层,净化服务器配置,便于应用迁移。

环境准备

  •     centOs:6.5
  •    nginx : 1.5.8

  •    redis:版本任意(本文使用的2.8)

注意事项

  1.     spring session依赖spring mvc
  2.     本文基于redis实现session共享

基于lettuce完成

    pom依赖

    在maven项目pom.xml 增加以下依赖



<dependencies>
        <!-- ... -->

        <dependency>
                <groupId>org.springframework.session</groupId>
                <artifactId>spring-session-data-redis</artifactId>
                <version>1.3.1.RELEASE</version>
                <type>pom</type>
        </dependency>
        <dependency>
                <groupId>biz.paluch.redis</groupId>
                <artifactId>lettuce</artifactId>
                <version>3.5.0.Final</version>
        </dependency>
        <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>4.3.4.RELEASE</version>
        </dependency>
</dependencies>

    session共享spring配置

    在项目增加spring-session.xml

    目录如下: src/main/webapp/WEB-INF/spring/spring-session.xml

<context:annotation-config/> <!--开启注解配置-->

<!--springSession 配置-->
<bean id="sessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <!--修改session的有效时间 以秒为单位,默认值是1800,便于测试修改为60秒-->
        <property name="maxInactiveIntervalInSeconds" value="60"></property>
    </bean>

<!-- 如不使用P命名空间或者属性注入 默认redis ip为localhost,port为6379 -->
    <bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory" 
          p:hostName="127.0.0.1" 
          p:port="6379" p:password="your-password" 
          p:timeout="3000" p:database="3" />

  修改web.xml

    加载spring-session.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/spring/*.xml
    </param-value>
</context-param>
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

 在web.xml增加拦截器, 此拦截器一定要加载所有拦截器前面,DispatcherServlet启动之后

<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

基于jedis完成

    pom依赖

    在maven项目pom.xml 增加以下依赖



<dependencies>
        <!-- ... -->

        <dependency>
                <groupId>org.springframework.session</groupId>
                <artifactId>spring-session-data-redis</artifactId>
                <version>1.3.1.RELEASE</version>
                <type>pom</type>
        </dependency>
        <dependency>  
               <groupId>redis.clients</groupId>
               <artifactId>jedis</artifactId>
               <version>2.5.2</version>
        </dependency> 
        <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>4.3.4.RELEASE</version>
        </dependency>
</dependencies>

    session共享spring配置

    在项目增加spring-session.xml

    目录如下: src/main/webapp/WEB-INF/spring/spring-session.xml   

<context:annotation-config/> <!--开启注解配置-->

<!--springSession 配置-->
<bean id="sessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <!--修改session的有效时间 以秒为单位,默认值是1800,便于测试修改为60秒-->
        <property name="maxInactiveIntervalInSeconds" value="60"></property>
    </bean>

<!-- 如不使用P命名空间或者属性注入 默认redis ip为localhost,port为6379 -->
    <bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="10.34.59.12"></property>
        <property name="port" value="6379"></property>
        <property name="database" value="3"></property>
    </bean>

    此处深坑,如果一个项目配置了多个JedisConnectionFactory,下图bean无法找到唯一的JedisConnectionFactory

查看RedisHttpSessionConfiguration源码可以使用RedisTemplate关于session的redis,根据下图可以更改JedisConnectionFactory配置如下:

	<bean id="sessionRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
		<property name="connectionFactory">
			<bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
				  p:database="3" p:host-name="${redis.host}" p:port="${redis.port}"
				  p:usePool="true" p:password="${redis.pass}" p:pool-config-ref="jedisPoolConfig1" p:timeout="${redis.timeout}">
			</bean>
		</property>
	</bean>

 

修改web.xml

    加载spring-session.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/spring/*.xml
    </param-value>
</context-param>
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

 在web.xml增加拦截器, 此拦截器一定要加载所有拦截器前面,DispatcherServlet启动之后

<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

到此应用就具备了session共享的功能, 有不当或者错误的地方,欢迎拍砖!!!

关于配置了多个JedisConnectionFactory, RedisHttpSessionConfiguration 报错的解决方案,烦请大神不吝赐教,报错如下:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisMessageListenerContainer' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.data.redis.connection.RedisConnectionFactory]: : No qualifying bean of type [org.springframework.data.redis.connection.RedisConnectionFactory] is defined: expected single matching bean but found 2: jedisFactory,jedisFactory1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.data.redis.connection.RedisConnectionFactory] is defined: expected single matching bean but found 2: jedisFactory,jedisFactory1
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
	at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
	at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
	at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5118)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5634)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:899)
	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:875)
	at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
	at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1863)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
	at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
	at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
	at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:618)
	at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:565)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
	at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
	at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
	at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1487)
	at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:97)
	at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1328)
	at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1420)
	at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:848)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
	at sun.rmi.transport.Transport$2.run(Transport.java:202)
	at sun.rmi.transport.Transport$2.run(Transport.java:199)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:198)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:567)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.access$400(TCPTransport.java:619)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(TCPTransport.java:684)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(TCPTransport.java:681)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:681)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.data.redis.connection.RedisConnectionFactory] is defined: expected single matching bean but found 2: jedisFactory,jedisFactory1
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:970)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)

 

© 著作权归作者所有

共有 人打赏支持
j
粉丝 58
博文 85
码字总数 123309
作品 0
成都
程序员
加载中

评论(2)

j
java_龙

引用来自“ixiaohei”的评论

我记得我当时做是指定一个名字就好了,当时还看过spring session源代码,现在忘记了,不过可以搞个内部bean配置redis可以解决。后面我们用户量太多,集群太大已经废弃使用session这种方案。都是sso单点拿token。然后filter过滤拿到token去sso服务端解析到用户数据。
:+1: 3Q
ixiaohei
ixiaohei
我记得我当时做是指定一个名字就好了,当时还看过spring session源代码,现在忘记了,不过可以搞个内部bean配置redis可以解决。后面我们用户量太多,集群太大已经废弃使用session这种方案。都是sso单点拿token。然后filter过滤拿到token去sso服务端解析到用户数据。
memcached pk redis

由于项目的需要,我需要决策使用memcached还是redis。 分享一下我的经验,我需要把原本单点的一个系统改照成非单点,我引入了NGINX很容易实现了,但是原有系统大量使用了SESSION,改造成集群...

SunnyWu
2016/03/24
63
0
Android 进阶之路(我的博客文章目录)

原文地址:http://blog.csdn.net/u011240877 为了方便读者阅读以及自己回顾,总结写过的文章和一些想要写的文章目录如下: 1.Java Java 解惑:Comparable 和 Comparator 的区别 Java 解惑:R...

u011240877
2017/04/01
0
0
react-native下遇到的坑,在这里都可以解决

React-Native android在windows下的踩坑记 坑很多,跳之前做好准备。没有VPN的同学请浏览完本文后慎行。 你需要先安装最新版本的node.js(我最后使用的是v4.1.2),前往官网下载>> 注:我win...

hqxluoyang
2015/10/27
0
0
一起学微软Power BI系列-使用技巧(1)连接Oracle与Mysql数据库

阅读目录 1.关于Power BI的版本信息 2.Power BI连接Oracle踩坑记 3.连接Mysql数据库 4.参考文献与资料   说起Oracle数据库,以前没用过Oracle不知道,但是这1年用Oracle后,发现真的是想狂...

老朱第八
01/09
0
0
centos 7( linux )下搭建elasticsearch踩坑记

目录 概述 环境准备 elasticsearch配置 启动踩坑记 彩蛋 概述 公司最近在做全文检索的项目,发现elasticsearch踩了不少坑,百度点进去又是坑,在此记录一下自己的踩坑历程。 本文旨在单机版的e...

java_龙
10/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

初级开发-编程题

` public static void main(String[] args) { System.out.println(changeStrToUpperCase("user_name_abc")); System.out.println(changeStrToLowerCase(changeStrToUpperCase("user_name_abc......

小池仔
今天
6
0
现场看路演了!

HiBlock
昨天
16
0
Rabbit MQ基本概念介绍

RabbitMQ介绍 • RabbitMQ是一个消息中间件,是一个很好用的消息队列框架。 • ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的s...

寰宇01
昨天
9
0
官方精简版Windows10:微软自己都看不过去了

微软宣布,该公司正在寻求解决方案,以减轻企业客户的Windows 10规模。该公司声称,企业客户下载整个Windows 10文件以更新设备既费钱又费时。 微软宣布,该公司正在寻求解决方案,以减轻企业...

linux-tao
昨天
19
0
TypeScript基础入门之JSX(二)

转发 TypeScript基础入门之JSX(二) 属性类型检查 键入检查属性的第一步是确定元素属性类型。 内在元素和基于价值的元素之间略有不同。 对于内部元素,它是JSX.IntrinsicElements上的属性类型...

durban
昨天
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部