springboot集群session共享问题(springSession+redis+nginx)
单服务架构到分布式/集群的演变
在传统的单服务架构中,一般来说,只有一个服务器,那么不存在 Session 共享问题,但是在分布式/集群项目中,Session 共享则是一个必须面对的问题。
在这样的集群架构中,如果不去解决session共享问题,那么就会给程序带来问题。
如果在某次登录时,nginx将请求分发给tomcat1,登录完以后tomcat1将session记下,后续的请求可能又会分发给tomcat2,但是toncat2中没有session信息,那么就会让你去重新登录。
或者是分布式项目,登录状态是在多个项目中共享的。
如何解决session共享问题
解决办法很简单,把所有项目的共享数据放入一个公共的容器中,大家都从这个容器中存取就可以了,主流的方案就是Redis缓存。
当所有的服务存储session时都向redis中存,需要session数据时就向redis中取这样就解决了session共享问题。那么对于springboot项目该如何实现呢?
springboot集成springSession+redis实战
创建springboot项目,选中redis ,web ,springSession如图,在这里选择的版本是2.1.4如果是2.1.5以上版本的话还需要加Spring Security依赖。
配置redis
server.port=8081
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.database=0
编写测试接口测试
package com.example.demo.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("set")
public R set(String msg,HttpSession session,HttpServletRequest request) {
int port=request.getServerPort();
String sessionId = session.getId();
session.setAttribute("user",msg);
return new R(1,null,port,sessionId);
}
@RequestMapping("get")
public R get(HttpSession session,HttpServletRequest request) {
int port=request.getServerPort();
String sessionId = session.getId();
return new R(2,session.getAttribute("user"),port,sessionId);
}
public class R{
private int code;
private Object msg;
private int port;
private String sessionId;
public R(int code,Object msg,int port,String sessionId){
this.code = code;
this.msg = msg;
this.port = port;
this.setSessionId(sessionId);
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public Object getMsg() {
return msg;
}
public void setMsg(Object msg) {
this.msg = msg;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
}
}
就这摩多,是不是特简单,下面就打包运行试试。
为了测试我们打两个包
分别启动两个项目,注意端口不能一样呦~。
首先调用8080端口的set接口
再调用8081端口的get接口
实验结果证明这种方法实现session共享成功
然后再去redis数据库中看看是否存在此session,不用看了,肯定存在~
下边使用nginx代理的方式访问
首先是nginx的配置
upstream session.test{
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8081 weight=1;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://session.test;
proxy_redirect default;
}
}
从配置中看到,nginx监听80端口。而且两个服务的权重是一致的。
启动nginx后访问测试,注意端口都变成了80
测试结果是ok的一样能够共享session
fixed
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。