1. 分布式环境下的session共享问题
  2. 分布式环境下的session共享解决方案
  • 方案一: session同步(复制)
  • 优点
    tomcat原生支持,只需要修改配置文件
  • 缺点
    session同步需要数据传输,占用大量带宽
    任意一台服务器保存的session数据都是所有服务器的session数据总和,占用内存较大
  • 方案二: 将session数据存储在客户端
  • 优点
    将数据存储在客户端,在需要的时候直接从客户端获取,也就没有了分布式session的问题
    节省服务器端资源
  • 缺点
    数据存放在客户端的cookie中,存在泄漏、篡改、窃取等安全隐患
    cookie保存的数据限制4K,不能保存大量信息
    每次http请求都要携带cookie信息,浪费网络带宽
  • 方案三: hash一致性(可用)
  • 优点
    如果服务器数量不变,每次hash都会映射到相同的服务器
    只需要修改nginx配置,不需要修改应用代码
    负载均衡,只要hash属性的值分布是均匀的,多台web-server的负载是均衡的
    可以支持web-server水平扩展
  • 缺点
    当web-server重启时可能会导致部分session丢失,影响业务,部分用户需要重新登录(其实该缺点问题不大,session也是有生存周期的,再获取一次即可)
    如果web-server水平扩展,rehash后session重新分布,也会有一部分用户路由不到正确的session
  • 改进版: 一致性hash算法/带虚拟节点的一致性hash算法
  • 方案四: 统一存储
  • spring redid使用db0 springsessiondataredis利弊_spring

  1. 统一存储之使用SpringSession实现
  • pom.xml导入依赖
<dependency>
	<groupId>org.springframework.session</groupId>
	<artifactId>spring-session-data-redis</artifactId>
</dependency>
  • application.yml配置
spring:
  redis:
    host: 192.168.145.8
    port: 6379
#  使用redis存储session解决分布式共享问题
  session:
    store-type: redis

server:
#  session过期时间为30分钟
  servlet:
    session:
      timeout: 30m
  • 主启动类配置@EnableRedisHttpSession注解
package com.kenai.gulimall.auth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

@EnableRedisHttpSession       // 整合redis作为session存储
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallAuthServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(GulimallAuthServerApplication.class, args);
	}
}
  • session存入redis代码编写
@Controller
public class test {
	// session存入redis
    @ResponseBody
    @GetMapping("/test")
    public String test(HttpSession session){
        session.setAttribute("test_session", "data");
        return "ok";
    }

	// 从redis中获取session
    @ResponseBody
    @GetMapping("/getRedisSession")
    public String testGet(HttpSession session){
        String data = (String) session.getAttribute("test_session");
        return data;
    }
}
  • 修改域名及session的redis缓存序列化
package com.kenai.gulimall.auth.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;

@Configuration
public class GulimallSessionConfig {
    // 改变域名等信息。子域名向redis缓存中存放session信息,为了让整个域名都可用,通过修改域名为根域名实现
    // gulimall.com域名及子域名的cookie中有一个名叫GULIMALLSESSION的cookie
    // GULIMALLSESSION当中存放sessionid信息,当向redis请求的时候会带上cookie信息,所以便能根据cookie中存放的sessionId找到redis中存放的session信息
    // session信息中有我们存入的属性信息,比如用户id:用户信息.
    @Bean
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        cookieSerializer.setDomainName("gulimall.com");
        cookieSerializer.setCookieName("GULIMALLSESSION");
        return cookieSerializer;
    }
    
    // session存入redis缓存的json序列化
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer(){
        return new GenericJackson2JsonRedisSerializer();
    }
}