在分布式環境下,session會存在兩個問題
第一個問題:不同域名下,瀏覽器存儲的jsessionid是沒有存儲的。比如登錄時認證服務auth.gulimall.com存儲了session,但是搜索服務search.gulimall.com是沒有這個session的;
第二個問題:即使域名相同,但是分布式的服務在相同的服務里面有多個服務集群部署的,用戶每次訪問的時候,不能總是訪問同一個服務,可能到了其他的服務,由于采用了負載均衡,有可能這次請求分發給node1服務處理,下次請求分發給node2處理,node2是沒存儲有node1的session的。
解決辦法:
第一種方式:配置tomcat
這種的只適用于3-5個tomcat服務的時候,可以使用,在分布式情況下不適合的。
存在的問題:帶寬問題,相互同步需要消耗網絡傳輸時間。tomcat內存問題,每一個tomcat都要存儲其他tomcat對應的數據消耗內存。
第二種方式:
在客戶端將所有的數據存儲到cookie中,但是這是存在安全隱患的對應的數據可以被修改,而且cookie存儲的數據是有限的只有4K。這種一般不用。
第三種方案:
選擇hash一致性,也就是用戶訪問的時候,總是訪問同一個服務。這里是修改nginx的配置,也可以結合業務字段,sid是456就到另一臺服務器,其他的到另外一臺服務器。
第四種方式:
使用公共的區域進行存儲session,比如redis,數據庫或者存儲的更快的非關系型數據庫。
?下面是解決問題一的問題
解決子域共享問題
用戶通過瀏覽器登錄會員服務,會員服務會將其對應的用戶信息存儲到內存session中,但是這里我們不將其用戶的信息存儲內存session中,我們將其對應的用戶的信息存儲到redis。接下來給瀏覽器發卡,我們將其對應的域名放大,這樣對應的子域名也可以可以訪問對應的域名放大jessionid里面的數據。
解決方案:
引入SpringSession和使用:
需要注意:1.SpringSession有自動延期:redis中的數據也是有過期時間
? ? ? ? ? ? ? ? ? 2.哪里需要SpingSesson,哪里就需要配置。都要配置。
實現步驟:
1.添加依賴
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId>
</dependency>
2.配置文件中添加配置
spring.session.store-type=redis # Session store type.#下面的是配置可以不加,這里可以添加一個過期時間
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds is used.
spring.session.redis.flush-mode=on-save # Sessions flush mode.
spring.session.redis.namespace=spring:session # Namespace for keys used to store sessions.
3.開啟EnableRedisHttpSession注解:
4.添加配置類,默認使用jdk序列化,可讀性差,這里系統化轉成Json,?方便閱讀
@Configuration
public class GulimallSessionConfig {@Beanpublic CookieSerializer cookieSerializer(){DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();//放大整個系統域的作用域,使用主域名,這樣帶這個的二級域名也能讀取到sessioncookieSerializer.setDomainName("gulimall.com");cookieSerializer.setCookieName("GULISESSION");return cookieSerializer;}/*** 序列化機制* @return*/@Beanpublic RedisSerializer<Object> springSessionDefaultRedisSerializer() {return new GenericJackson2JsonRedisSerializer();}
}
?5.在業務代碼中使用session存儲用戶信息
session.setAttribute(AuthServerConstant.LOGIN_USER,data);
?注意:存儲到session的實體類一定要系列化,否則會報異常
public class MemberRespVo implements Serializable{}
6.前端引用:${user.nickname}
總結:需要使用SpringSession的服務依照上面的步驟實現:pom添加依賴,-->application配置類指定spring.session.story.type=redis-->添加config配置類,-->在啟動類或配置類添加注解@EnableRedisHttpSession,然后在前端中進入引用即可。