為什么會產生Session共享問題
集群情況下,session保存在各自的服務器的tomcat中,當分發地址至不同服務時,導致sesson取不到,就會產生session共享問題。
解決方案
- 負載均衡中,IP綁定策略。如nginx:ip_hash
- tomcat的session共享
- 優點:不需要額外開發,只需搭建tomcat集群即可
- 缺點:tomcat 是全局session復制,集群內每個tomcat的session完全同步(也就是任何時候都完全一樣的) 在大規模應用的時候,用戶過多,集群內tomcat數量過多,session的全局復制會導致集群性能下降, 因此,tomcat的數量不能太多,5個以下為好。
- cookie同步session:第一次請求將session存在服務器,並且存入cookie,再次請求,如果在服務器沒取到session,則從cookie中取。
- 優點:減輕服務器端的壓力
- 缺點:受到cookie的大小限制,可能占用一定帶寬,因為每次請求會在頭部附帶一定大小的cookie信息,另外這種方式在用戶禁止使用cookie的情況下無效,並且不安全
- 數據庫同步session,訪問壓力大
- redis集中管理session
- 優點:redis為內存數據庫,讀寫效率高,並可在集群環境下做高可用
spring-session + redis解決session共享問題
1.maven依賴引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--spring boot 與redis應用基本環境配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--spring session 與redis應用基本環境配置 --> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
- 創建SessionConfig類
import org.springframework.context.annotation.Configuration; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; @Configuration //設置session的默認在redis中的存活時間 @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60 * 60 * 8) public class SessionConfig { }
- 創建SessionInitializer類,初始化session配置
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; import com.lb.config.SessionConfig; //初始化Session配置 public class SessionInitializer extends AbstractHttpSessionApplicationInitializer { public SessionInitializer() { super(SessionConfig.class); } }
- application.yml
server: port: 8081 spring: redis: database: '0' host: 127.0.0.1 password: 123456 pool: max-active: 8 max-idle: 5 max-wait: 5000 min-idle: 1 port: 6379 timeout: 0 session: store-type: redis #設置session保存為默認redis的方式
- controller實現
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; @RestController @SpringBootApplication public class SessionController { @Value("${server.port}") private String port; @RequestMapping("/setsession") public String setSeesion(HttpServletRequest request, String key, String value) { HttpSession session = request.getSession(); session.setAttribute(key, value); return "server port :" + port + "---- value :" + value; } @RequestMapping("/getsession") public String getSeesion(HttpServletRequest request, String key) { HttpSession session = request.getSession(); String value = (String) session.getAttribute(key); return "server port :" + port + "---- value :" + value; } public static void main(String[] args) { SpringApplication.run(SessionController.class, args); } }
測試用nginx做分發
#負載均衡分發 upstream sessionserver { server 127.0.0.1:8080; server 127.0.0.1:8081; } server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://sessionserver; index index.html index.htm; } }