SpringBoot 分布式 Session 共享解决方案

分布式Session一致性?

说白了就是服务器集群Session共享的问题,集群情况下,session保存在各自的服务器的tomcat中,当分发地址至不同服务时,导致sesson取不到,就会产生session共享问题。

Session的作用?

Session 是客户端与服务器通讯会话跟踪技术,服务器与客户端保持整个通讯的会话基本信息。

客户端在第一次访问服务端的时候,服务端会响应一个sessionId并且将它存入到本地cookie中,在之后的访问会将cookie中的sessionId放入到请求头中去访问服务器,如果通过这个sessionid没有找到对应的数据那么服务器会创建一个新的sessionid并且响应给客户端。

分布式 Session 存在的问题?

假设第一次访问服务A生成一个sessionid并且存入cookie中,第二次却访问服务B客户端会在cookie中读取sessionid加入到请求头中,如果在服务B通过sessionid没有找到对应的数据那么它创建一个新的并且将sessionid返回给客户端,这样并不能共享我们的Session无法达到我们想要的目的。

解决方案:

  • 使用cookie来完成(很明显这种不安全的操作并不可靠)

  • 使用Nginx中的ip绑定策略,同一个ip只能在指定的同一个机器访问(不支持负载均衡)

  • 利用数据库同步session(效率不高,访问压力大)

  • 使用tomcat内置的session同步(同步可能会产生延迟,集群过多tomcat,session全局复制导致性能下架)

  • 使用token代替session

  • 使用spring-session以及集成好的解决方案,存放在redis中(读写效率高,并可在集群环境下做高可用)

spring-session 实战

启动两个SpringBoot项目端口号分别为 8080、8090 进行测试。

1、项目依赖(pom.xml)
  



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.1.RELEASE
         
    
    com.mscloudmesh
    springboot-redis
    0.0.1-SNAPSHOT
    springboot-redis
    springboot-redis

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.projectlombok
            lombok
        



        
            org.springframework.boot
            spring-boot-starter-data-redis
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        


        
        
            org.springframework.session
            spring-session-data-redis
        
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

2. application.yml配置文件:

server:
  port: 8080
spring:
  application:
    name: springboot-redis
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    password:
    jedis:
      pool:
        max-active: 200
        max-wait: -1
        max-idle: 10
        min-idle: 0
    timeout: 1000

  session:
    store-type: redis

 

package com.mscloudmesh.session;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RestController
@RequestMapping("/test")
public class TestController {
    @Value("${server.port}")
    private Integer port;
    
    @GetMapping("/createSession")
    public String createSession(HttpSession session, String name) {
        session.setAttribute("name", name);
        return "当前项目端口:" + port + " 当前sessionId:" + session.getId() + " 在Session中存入成功!";
    }
    
    @GetMapping("/getSession")
    public String getSession(HttpSession session) {
        return "当前项目端口:" + port + " 当前sessionId:" + session.getId() + "  获取的姓名:" + session.getAttribute("name");
    }
}

3. 启动类
  在 Spring boot 的文档中,添加 @EnableRedisHttpSession 来开启 `spring session`支持,配置如下:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;//开启session共享

@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 30 * 60 * 1000)
@SpringBootApplication
public class RedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class, args);
    }

}

下面进行下测试
  为了方便测试,我们修改server.port为8080,8081,运行两个应用程序
  1. 启动之后进行访问测试,首先访问 8080 端口的 程序
    http://localhost:8080/createSession?name=kevin
     
  2.修改端口为8081,启动程序并访问测试
        http://localhost:8080/getSession

这样两个服务器就实现session共享

3.可以通过redis客户端查看
   SpringBoot 分布式 Session 共享解决方案_第1张图片

你可能感兴趣的:(springboot系列)