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