2019-08-20 tomcat基于redis会话共享的集群配置。

实际上这个需求包含三个部分:

  • 基于tomcat的多个应用节点,但并不希望配置tomcat cluster
  • 基于httpd 实现负载均衡。
  • 为实现上述目的,考虑使用redis作为集中session存储,实现一个节点登录后,在所有节点都处于已登录状态。

tomcat的配置

tomcat的部署和配置过程就不描述了,属于基本操作。
这里只描述部署的结构,后面配置httpd的负载均衡时要用到。
tomcat1:
访问路径:http://ip1:port1/appName
tomcat2:
访问路径:http://ip1:port2/appName
tomcat3:
访问路径:http://ip2:port3/appName

httpd负载均衡

httpd2.4版本的配置文件结构,和我们有关的部分如下:

/etc/httpd/
               conf/
               conf.d/
               conf.module.d/
  1. 添加负载均衡配置
    使用如下命令编辑配置文件:
vi /etc/httpd/conf.d/proxy.conf

添加内容:

<Proxy balancer://myCluster>
    BalancerMember http://ip1:port1/appName loadfactor=3
    BalancerMember http://ip1:port2/appName loadfactor=3
    BalancerMember http://ip2:port3/appName loadfactor=3
    ProxySet lbmethod=byrequests
</Proxy>
ProxyRequests Off
ProxyPass /appName balancer://myCluster stickysession=JSESSIONID nofailover=Off
ProxyPassReverse /appName balancer://myCluster
  1. 添加负载均衡监控配置
    使用个如下命令新增配置文件:
vi /etc/httpd/conf.d/lbmgr.conf

添加内容:

<Location /balancer-manager>
    SetHandler balancer-manager
    Order Allow,Deny
    Allow from all
</Location>

其中,<Location / 后面的名字,不一定是 balancer-manager,你可以取自己喜欢的名字,比如lbmgr。在最后访问httpd的负载均衡器监控时,记得你配置的是什么就行了。
最后访问负载均衡器监控的路径是: http://ip/lbmgr

  1. 重启httpd使配置生效:
service httpd restart

应用配置

要让我们基于spring-mvc的遗留系统支持spring-session和redis的会话共享,需要对应用进行配置。

  1. 添加spring-session的配置
    先看配置代码,再解释:

@EnableRedisHttpSession
@PropertySource({"classpath:/com/aa/bb/config/properties/redis.properties"})
public class SpringSessionRedisConfig {
    
    @Bean 
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
    
    @Value("${maxInactiveIntervalInSeconds}")
    private int maxInactiveIntervalInSeconds;

    @Value("${maxTotal}")
    private int maxTotal;

    @Value("${maxIdle}")
    private int maxIdle;

    @Value("${host}")
    private String hostName;

    @Value("${port}")
    private int port;

    @Value("${timeout}")
    private int timeout;

    @Value("${usePool}")
    private boolean usePool;

    @Value("${maxWaitMillis}")
    private int maxWaitMillis;

    @Value("${testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${password}")
    private String password;
    
    @Bean
    public  redisHttpSessionConfiguration() {
        RedisHttpSessionConfiguration bean = new RedisHttpSessionConfiguration();
        bean.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds);
        
        return bean;
    }
    
    @Bean
    public JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig bean = new JedisPoolConfig();
        bean.setMaxIdle(this.maxIdle);
        bean.setMaxTotal(this.maxTotal);
        
        return bean;
    }
    
    @Bean(destroyMethod = "destroy")
    public RedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
        //单机版jedis
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(this.hostName);
        redisStandaloneConfiguration.setPort(this.port);
        redisStandaloneConfiguration.setDatabase(0);
//        redisStandaloneConfiguration.setPassword(RedisPassword.of(this.password));
        //客户端配置
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpcb =
                (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();
        //指定jedisPoolConifig来修改默认的连接池构造器(真麻烦,滥用设计模式!)
        jpcb.poolConfig(jedisPoolConfig);
        JedisClientConfiguration jedisClientConfiguration = jpcb.build();
        
        //单机配置 + 客户端配置 = jedis连接工厂
        return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
    }
    
    @Bean
    public StringRedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        return new StringRedisTemplate(redisConnectionFactory);
    }
}

1.1. 上述配置中,最关键的是:

    @Bean
    public RedisHttpSessionConfiguration redisHttpSessionConfiguration() {
        RedisHttpSessionConfiguration bean = new RedisHttpSessionConfiguration();
        bean.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds);
        
        return bean;
    }

因为spring-session通过RedisHttpSessionConfiguration,提供了一系列的bean和相关配置,实现了用spring-session的会话管理器替换tomcat自己的session会话管理器,并存储到redis中的效果。
这个bean必须和 @EnableRedisHttpSession 配合使用,否则不会生效。

1.2. 配置redis连接池
上述配置,只是让spring-session将会话存储到redis中,但并不知道如何连接到redis,因此需要添加必要配置,告知如何连接到redis。
实际上有多种连接器可用,我们这里使用了Jedis连接器,其他连接器的使用方式参看spring-session的官方文档即可:

    @Bean
    public JedisPoolConfig jedisPoolConfig() {

这个配置提供redis连接池配置

    @Bean(destroyMethod = "destroy")
    public RedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig) {

这个配置创建redis链接工厂

    @Bean
    public StringRedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {

这个配置提供redisTemplate。

好了,有了上述配置,到redis的链接就完成了。
需要注意的是,这里的方法名,就是最终生成的bean的名字,同时也是spring-session查找对应bean时,使用的名字。如果要自定义名字,那么就必须要提供全套配置,否则spring-session就找不到redis链接工厂等bean了。

1.3. 配置spring读取SpringSessionRedisConfig这个配置bean
需要在spring的xml配置文件中,增加如下配置:

<context:component-scan base-package="com.aa.bb.config" />

这个配置让spring去扫描包 com.aa.bb.config 下的@Configuratioin 注解了的配置类。

1.4. 配置spring-mvc filter,去拦截请求处理session
必须让这个filter在其他filter的前面,否则可能导致其他filter工作时找不到正确的会话。

    <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>
    </filter-mapping>

这个配置会向spring-mvc注入一个名字叫 springSessionRepositoryFilter 的filter bean。
这个filter bean 是在前面配置的 RedisHttpSessionConfiguration 中创建的。

到此为止,配置就完成了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容