Sesssion共享问题是因为在服务器集群下,用户访问服务器将值存放到Session中,再次访问的话代理服务器又会分配一个新的服务器(无法保证这个服务还是之前访问且Session中有数据的服务器),

这种情况有很多种解决的方案,例如使用nginx的ip绑定,使用cookie,数据库,缓存等等

最好使用资源最少的情况就是使用SpringSession和Redis来解决

实现原理大致如下:

在A服务器中往Session中放入的值,会被SpringSession监听到并写入到redis中,在其他服务器从session取值的时候就会从session找到值并且返回,

往session中存值和取值都无需手动的吊用redis的API,SpringSession底层会帮助我们实现

依赖pom.xml

   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.1.0</version>
        </dependency>

核心配置文件application.properties

主要是配置redis服务器的参数,和服务端口

spring.redis.host=192.168.118.3
spring.redis.port=6379
spring.redis.password=admin
#服务器端口
server.port=6060

创建一个controller

用于模拟用户存取数据

package com.ty.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@RestController
public class SessionController {

    @Value("${server.port}")
    private String Port;
    @RequestMapping("/setSession")
    public  Object setSession(HttpServletRequest request,String sessionKey,String sessionValue){
        HttpSession httpSession=request.getSession();
        httpSession.setAttribute(sessionKey,sessionValue);
        System.out.println("sessionKey"+sessionKey);
        System.out.println("sessionValue"+sessionValue);
        return "success,port:"+Port;

    }

    @RequestMapping("/getSession")
    public  Object getSession(HttpServletRequest request,String sessionKey){
        System.out.println("sessionKey:"+sessionKey);
            HttpSession httpSession=null;
                 httpSession = request.getSession(false);
                 String value=null;
        if (httpSession!=null) {
            value=(String) httpSession.getAttribute(sessionKey);
        }
        return "sessionValue:"+value+"---port"+Port;

    }
}

启动端口为6060的项目,然后修改配置文件,将端口改为6061再次启动,

把下图中的勾选就可启动两个除端口不一样的两个服务了

SpringBoot使用SpringSession和redis解决session共享问题(nginx反向代理)_java

 

 

nginx配置(可有可无)

如果不配置nginx做轮询策略的话,就往a服务器里放入一个数据,在通过b服务器访问这个session用于测试就好了

    upstream backserver { server localhost:6060; server localhost:6061;}
    server {
        listen       80;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            proxy_pass http://backserver;
            index index.html index.htm;
        }    
}

开始测试

访问Controller将值放入到session中

http://localhost/setSession?sessionKey=1&sessionValue=1516

SpringBoot使用SpringSession和redis解决session共享问题(nginx反向代理)_java_02

 

 可以看到将值放入到端接为6061的服务中了,在看看redis中的变化

SpringBoot使用SpringSession和redis解决session共享问题(nginx反向代理)_服务器_03

 

 

redis中保存着一个数据包,包中有session,key就是Session的id

接着取值

http://localhost/getSession?sessionKey=1

SpringBoot使用SpringSession和redis解决session共享问题(nginx反向代理)_取值_04

由图可见访问端口6060的服务器也是将值给取出来了

这样就可以解决Session共享的问题

 

用nginx解决话就很简单了(不推荐)

就是在负载均衡的策略下添加ip_hash,根据客户端的ip来决定访问的是哪个服务器,

这样的话相同的ip永远就会访问到同一个服务器,也就不存在什么Session共享的问题了

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;
        

        location / {
            ip_hash
            proxy_pass http://backserver;
            index index.html index.htm;
        }    
}