分布式session问题解决方案

一、什么是分布式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-SNAPSHOTorg.springframework.bootspring-boot-starter-parent2.0.0.RELEASE 

2.8.01.81.8UTF-8UTF-8zh_CN
org.projectlomboklombokorg.springframework.bootspring-boot-starter-webcom.alibabafastjson1.2.47org.springframework.bootspring-boot-starter-testtestorg.springframework.bootspring-boot-starter-data-redisorg.springframework.sessionspring-session-data-redisorg.apache.commonscommons-pool2redis.clientsjedis
org.apache.maven.pluginsmaven-compiler-plugin1.81.8org.springframework.bootspring-boot-maven-plugincom.meiteedu.WxMpApplicationrepackage

 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;@Beanpublic 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做负载均衡配置

 

启动项目,分别用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的问题

 

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

 

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部