分布式session问题解决方案

分布式session问题解决方案_第1张图片

一、什么是分布式session问题

a、什么是session

session是一种会话技术,我们知道http是无状态协议的,就是这次连接传输数据后,下次连接服务器是不知道这次的请求是谁的,因此我们要做一个标记,让服务器知道每次请求是哪个(客户端)浏览器发出的,就是请求的时候服务器会创建一个session把session的值保存在服务器,把sessionID返回给浏览器,请求的时候把sessionID放在请求头中,这样服务器解析之后就能发现是哪个浏览器发来的请求

b、session存放在什么地方,会引起什么问题

session是存在服务器的,只是把sessionID返回给浏览器。这样我们把浏览器关掉,session也不会实现,但是只是丢失了sessionID,这样也是访问不到的。

c、session的工作原理

session是由服务器创建的,存放在服务器中,把sessionID返回给浏览器,请求的时候,每次请求把sessionID就到请求头中,服务器解析以后就知道是哪个浏览器

e、分布式session是什么

我们知道session是保存在服务器的,这样当我们的项目做了负载均衡以后,如果在session中存了数据,那么就有可能有有些项目取不到session中的数据,这就是分布式session问题

二、服务做了集群一般是怎么样做的

如果是一般的springboot项目,那么只要改下端口号启动几个,然后用nginx统一做反向代理。

springcloud微服务项目,那么这个时候,可以使用ribbon本地负载均衡。

nginx负载均衡和ribbon做负载均衡的区别:

nginx做负载均衡是服务器端的负载均衡,统一访问一个地址,根据负载均衡算法访问决定访问那一个服务器。

ribbon负载均衡,这是本地负载均衡(也可以说是客户端负载均衡),把提供服务的看客户端地址都缓存记录下来,根据本地的算法实现负载均衡。

三、分布式session解决办法

a、项目中用到了session,那么使用springsession解决分布式问题

使用springsession的原理:把项目中的session统一存在redis中,所有的参与集群的项目都在redis中取,这样就不不会出现明明在session中设了值但取不到值的情况。

maven依赖

com.junlaninfo
solveSession
1.0-SNAPSHOT


    org.springframework.boot
    spring-boot-starter-parent
    2.0.0.RELEASE
     


    2.8.0
    1.8
    1.8
    UTF-8
    UTF-8
    zh_CN



    
        org.projectlombok
        lombok
    
    
        org.springframework.boot
        spring-boot-starter-web
        
    
    
    
        com.alibaba
        fastjson
        1.2.47
    
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
        org.springframework.boot
        spring-boot-starter-data-redis
    
    
    
        org.springframework.session
        spring-session-data-redis
   
    
        org.apache.commons
        commons-pool2
    
    
    redis.clients
    jedis
    



    
        
            org.apache.maven.plugins
            maven-compiler-plugin
            
                1.8
                1.8
            
        
        
            org.springframework.boot
            spring-boot-maven-plugin
            
                com.meiteedu.WxMpApplication
            
            
                
                    
                        repackage
                    
                
            

        
    

 properties 文件

server.port=8080
redis.hostname=127.0.0.1
redis.port=6379
redis.password=

 redis配置

package com.junlaninfo.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

//这个类用配置redis服务器的连接
//maxInactiveIntervalInSeconds为SpringSession的过期时间(单位:秒)
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {

   // 冒号后的值为没有配置文件时,制动装载的默认值
    @Value("${redis.hostname:localhost}")
   String HostName;
   @Value("${redis.port:6379}")
   int Port;

   @Bean
   public JedisConnectionFactory connectionFactory() {
      JedisConnectionFactory connection = new JedisConnectionFactory();
      connection.setPort(Port);
      connection.setHostName(HostName);
      return connection;
   }
}
package com.junlaninfo.config;

import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;

//初始化Session配置
public class SessionInitializer extends AbstractHttpSessionApplicationInitializer {
    public SessionInitializer() {
        super(SessionConfig.class);
    }
}

项目启动

package com.junlaninfo;


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

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class TestSessionController {

   // 创建session 会话
    @RequestMapping("/createSession")
   public String createSession(HttpServletRequest request, String nameValue) {
      HttpSession session = request.getSession(false);
      String id = session.getId();
      System.out.println("存入Session  sessionid:信息" + session.getId() + ",nameValue:" + nameValue);
      session.setAttribute("name", nameValue);
      return "success";
   }

   // 获取session 会话
   @RequestMapping("/getSession")
   public Object getSession(HttpServletRequest request) {
      HttpSession session = request.getSession(false);
      String id = session.getId();
      System.out.println("获取Session sessionid:信息" + session.getId());
      Object value = session.getAttribute("name");
      return value;
   }

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

 

只要加入springsession的依赖,配置好redis,那么就可以解决分布式session一致性的问题,不用在原来的项目中做任何改变

 

 

使用nginx做负载均衡配置

分布式session问题解决方案_第2张图片

 

启动项目,分别用8080和8081启动,这样就可以看到解决分布式session问题的效果

 

创建session的注意点:

HttpSession session = request.getSession(false);

这里可以传入一个布尔类型的变量,ture的话表示没有这个sessionID对应的session那么就新创建一个。

如果是false,那么没有这个sessionID对应的session,那么就直接返回失败,不会新创建session

 

b、使用token代替session,这样就不会引起分布式session问题

这里我们需要提一个问题,项目中使用到了session,那么即使使用springsession解决分布式session一致性的问题,只要你换了一个浏览器操作,那么同样因为sessionID丢失的问题,也同样获取不到值,为了彻底解决分布式session的问题,那么我们可以用token代替session

@Service

public class TokenService {

@Autowired

private RedisService redisService;

 

// 新增 返回token

public String put(Object object) {

String token = getToken();

redisService.setString(token, object);

return token;

}

 

// 获取信息

public String get(String token) {

String reuslt = redisService.getString(token);

return reuslt;

}

 

public String getToken() {

return UUID.randomUUID().toString();

}

 

}

 

@RestController

public class TokenController {

@Autowired

private TokenService tokenService;

@Value("${server.port}")

private String serverPort;

 

@RequestMapping("/put")

public String put(String nameValue) {

String token = tokenService.put(nameValue);

return token + "-" + serverPort;

}

 

@RequestMapping("/get")

public String get(String token) {

String value = tokenService.get(token);

return value + "-" + serverPort;

}

 

}

 

 

c、项目中使用到了session,使用nginx的ip绑定解决分布式session的问题

分布式session问题解决方案_第3张图片

分布式session问题解决方案_第4张图片

 

代码:https://github.com/xuexionghui/solveSession.git

 

 

你可能感兴趣的:(分布式session问题解决方案)