xmtrock
发布于 2022-04-12 / 1,175 阅读
0

分布式session,整合SpringSession+Redis

问题:
第一次访问服务器,登录,登陆成功了用户保存到session中,并会返回jsessionid给浏览器cookie
以后访问都会带上cookie,用于获取服务器中的session数据
浏览器关闭的话,就会清除cookie,你也可以设置过期时间
BUT分布式的情况下,其作用域就只能在本域名之下,不可跨域名共享
BUT分布式的情况下,其作用域就只能在当前服务之下,多服务之间(不同端口的服务),也无法共享


解决方式1:session复制
缺点:session同步需要网络带宽,也会造成延迟


解决方式2:在客户端存储,也就是直接存到cookie中
缺点:每次请求要携带大量cookie浪费带宽,并且cookie最长只有4k,并且cookie可能造成泄露或篡改


解决方式3:hash一致性
只需要改nginx配置,利用nginx负载均衡机制。具体就是根据访问的人的信息(ip)来得到hash值并分配到对应的服务器。因为hash值分布均衡。
缺点:session依然存在服务器中,单一服务器重启后session丢失,需要重新登录。另外服务器扩展的话需要rehash,session也需要重新分布。但是缺点总体问题还不是很大。


解决方式4:统一存储session
主要是用redis来统一存储session数据,而不同的服务根据负载均衡来分配去redis取。
这样服务器比较平均,redis也足够处理。这样服务可以随意扩展,反正都需要到redis里取
缺点:增加了网络调用,主要性能瓶颈在调用redis那一步


SpringSession整合

https://docs.spring.io/spring-session/docs/2.3.x/reference/html5/
依赖:

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

配置:

spring.session.store-type=redis

过期时间配置:

server.servlet.session.timeout=30m

redis连接信息:

spring.redis.host=localhost
spring.redis.port=6379

配置类:

@EnableRedisHttpSession
public class SpringSessionConfig {
    @Bean
    public LettuceConnectionFactory connectionFactory() {
        return new LettuceConnectionFactory();
    }
}

用的时候:

public String weibo(HttpSession session)
session.setAttribute("loginUser", respVo);

记得序列化,否则会有序列化问题(默认JDK序列化):

public class MemberRespVo implements Serializable

成功后,redis可以看到数据
20220413013226097
子域名session应用到二级父域名?

不一定,可以在对应的三级子域名的项目那里,一样配置springsession和redis,还有配置类同上。以此,对方服务就能拿到session数据了
然后,如果双边服务都是如上放同一个vo对象,那么需要做个common包同时引用,才能保证两边都能获取数据并序列化

问题是如何跨域名放cookie?

参考文档:设置cookie的时间域名等等
https://docs.spring.io/spring-session/docs/2.3.x/reference/html5/#api-cookieserializer
参考文档:设置Redis用Json序列化
https://github.com/spring-projects/spring-session/blob/2.3.3.RELEASE/spring-session-samples/spring-session-sample-boot-redis-json/src/main/java/sample/config/SessionConfig.java

具体:(注意多个服务都这样配)

@EnableRedisHttpSession
@Configuration
public class SpringSessionConfig implements BeanClassLoaderAware {
    @Bean
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        // cookieSerializer.setCookieMaxAge();
        cookieSerializer.setDomainName("gulimall.com");//放大域名
        cookieSerializer.setCookieName("GULISESSION");//cookie的key名
        return cookieSerializer;
    }

    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        //因为通用能用泛型的?
        return new GenericJackson2JsonRedisSerializer();
    }

    private ClassLoader loader;
    /*
     * (non-Javadoc)
     *
     * @see
     * org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang
     * .ClassLoader)
     */
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.loader = classLoader;
    }
}

20220413023101497