一般HttpSession是通過Servlet容器創建並進行管理的, 創建成功之後都是保存在內存中。如果是項目是搭建的集羣, 則來自於同一用戶的http請求有可能備份發到不同的實例中, 如何保證各個實例之間的Session同步共享, SpringBoot提供了自動化的Session共享配置, 主要是結合Redis解決這個問題。使用Redis解決Session共享問題的原理非常簡單, 就是把原本存儲在不同服務器上的Session拿出來放在一個獨立的服務器上,如圖:
當一個請求到達ngnix服務器後, 首先盡心請求分發, 假設請求被real server1 處理了, real server在處理請求時, 無論是存儲還是讀取Session, 都去操作Session服務器, 而不是操作本地內存, 這樣就實現了Session共享;
導入依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<artifactId>io.lettuce</artifactId>
<groupId>lettuce-core</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
配置文件:
spring.redis.database=0
spring.redis.host=192.168.0.160
spring.redis.port=6379
spring.redis.password=123456
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
- 創建Controller測試:
/** * session共享 */ @RestController public class RedisController { @Value("${server.port}") String port; @PostMapping("/save") public String saveName(String name, HttpSession session){ session.setAttribute("name",name); return port; } @GetMapping("/getname") public String getName(HttpSession session){ return port+":"+session.getAttribute("name").toString(); } }
/save接口向Session中存儲數據, get接口獲取Session中數據, 根據port來看, 具體是哪個服務在提供服務;
- 配置Nginx負載均衡:
upstream batac.com{
server 192.168.0.160:7020 weight=1;
server 192.168.0.160:7021 weight=1;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
location ~/group1/ {
ngx_fastdfs_module;
}
#access_log logs/host.access.log main;
location / {
proxy_pass http://batac.com;
proxy_redirect default;
}
}
- 請求分發: