一、Spring-Session使用的場景
HttpSession是通過Servlet容器進行創建和管理的,在單機環境中。通過Http請求創建的Session信息是存儲在Web服務器內存中,如Tomcat/Jetty。假如當用戶通過瀏覽器訪問應用服務器,session信息中保存了用戶的登錄信息,並且session信息沒有過期失,效那么用戶就一直處於登錄狀態,可以做一些登錄狀態的業務操作。
但是現在很多的服務器都采用分布式集群的方式進行部署,一個Web應用,可能部署在幾台不同的服務器上,通過LVS或者Nginx等進行負載均衡(一般使用Nginx+Tomcat實現負載均衡)。此時來自同一用戶的http請求將有可能被分發到不同的web站點中去(如:第一次分配到A站點,第二次可能分配到B站點)。那么問題就來了,如何保證不同的web站點能夠共享同一份session數據呢?
假如用戶在發起第一次請求時候訪問了A站點,並在A站點的session中保存了登錄信息,當用戶第二次發起請求,通過負載均衡請求分配到B站點了,那么此時B站點能否獲取用戶保存的登錄的信息呢?答案是不能的,因為上面說明,session是存儲在對應Web服務器的內存的,不能進行共享,此時spring-session就出現了,來幫我們解決這個session共享的問題!
如何進行Session共享呢?
簡單點說就是請求http請求經過Filter鏈,根據配置信息過濾器將創建session的權利由tomcat交給了spring-session中的SessionRepository,通過spring-session創建會話,Session的內容統一存儲在一個數據庫(如MySQL)或緩存(如Redis,Mongo)中。
當然使用Nginx的ip_hash策略也可以解決session同步的問題。
在使用Nginx的ip_hash策略時候,每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個后端服務器,這樣就解決session的同步問題。
大神文章地址:https://blog.csdn.net/qq_28602957/article/details/61615876
二、在springboot中使用spring-session
1、引入Maven依賴
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!--spring boot--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--spring session--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> </dependencies>
2、配置application.properties
server.port=8080 spring.redis.host=localhost spring.redis.port=6379 #spring session使用存儲類型,默認就是redis所以可以省略 spring.session.store-type=redis
3、在啟動類中加入注解
@EnableCaching @EnableRedisHttpSession @SpringBootApplication public class SpringsessionApplication { public static void main(String[] args) { SpringApplication.run(SpringsessionApplication.class, args); } }
4、編寫控制器
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @RestController public class IndexController { @RequestMapping("/show") public String show(HttpServletRequest request){ return "I'm " + request.getLocalPort(); } @RequestMapping(value = "/session") public String getSession(HttpServletRequest request) { request.getSession().setAttribute("userName", "admin"); return "I'm " + request.getLocalPort() + " save session " + request.getSession().getId(); } @RequestMapping(value = "/get") public String get(HttpServletRequest request) { String userName = (String) request.getSession().getAttribute("userName"); return "I'm " + request.getLocalPort() + " userName :" + userName; } }
5、配置nginx
upstream ngixServers{ server localhost:8081; server localhost:8082; } server { listen 8888; server_name localhost; location / { proxy_pass http://ngixServers; } }
6、測試結果
a)啟動redis
b)啟動nginx
c)修改springboot的啟動方式,允許啟動多個示例。
d)修改application.properties中的端口號,改為8081,啟動tomcat。
e)修改application.properties中的端口號,改為8082,啟動tomcat。
訪問地址:http://localhost:8888/show 可見如下結果(出現不分先后):
刷新可見:
以上運行結果說明負責均衡已經好使,兩台服務器都可以正常訪問。
f)接下來訪問地址:http://localhost:8888/session,將session寫入一個服務器。(服務器可能是8081,也可能是8082)
g)訪問地址:http://localhost:8888/get ,多次刷新可見兩個服務器均能獲得session。(此session存在與redis中)
或者
到此,使用nginx實現負載均衡和使用spring-session+redis實現session共享就完成了。可以使用命令或者在RedisDesktopManager中查看redis中存儲的session信息!
參考大神文章: