nginx 解決session一致性
阿新 • • 發佈:2018-11-25
- session 粘滯性
- 每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個後端伺服器,可以解決session的問題。
-
upstream backserver { ip_hash; server 192.168.0.14:88; server 192.168.0.15:80; }
- 但是有缺點,這存在單點風險,倘若我已經在192.168.0.14:88埠登入後,過段時間發現14伺服器掛了(session時間未過期),那麼這時候會訪問到15伺服器,那這時候需要重新登入,因為在拿14伺服器上的JsessionId去15伺服器請求發現不存在。
2、session 複製
- 可以通過tomcat的server.xml檔案進行配置,這樣每個tomcat都會同步對應的session,那麼此時即使某個tomcat被宕機了,也不影響服務。
- 具體的tomcat可以參見如下 ,tomcat 官網對應的tomcat叢集配置
-
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8"> <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> <Channel className="org.apache.catalina.tribes.group.GroupChannel"> <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="4000" autoBind="100" selectorTimeout="5000" maxThreads="6"/> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender> <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/> </Channel> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/> <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false"/> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster>
3、session 共享(springboot)
- 對應的專案中pom檔案新增
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
- 在對應的application.properties中配置redis資訊
-
spring.redis.host=localhost spring.redis.port=6379
- 新增開啟spring session支援的註解@EnableRedisHttpSession
-
@Configuration @EnableRedisHttpSession public class RedisSessionConfig { }
- 新增驗證的介面
-
@Value("${server.port}") String port; @GetMapping("/session") public Object getSession(HttpServletRequest request){ Map<String, Object> map = new HashMap<String, Object>(); map.put("SessionId", request.getSession().getId()); map.put("ServerPort", "服務埠號為 "+port); return map; }
- 訪問 http://localhost:8080/session
- 我們看下redis快取的資料
- 可以發現
sessionId
已經快取在redis資料庫中 - 下面我們換個埠再訪問一次看看
- 這次我把埠換成了8888 訪問:http://localhost:8888/session
- 重新整理了redis資料庫,快取的資料也沒變
- 結果中的SessionId是一致的,卻是由兩個不同專案工程來提供服務。這樣子,SpringSession 利用攔截器 Filter 幫我們在每個請求前進行了同步設定,達到了分散式系統中 session 共享。
4、session 共享(springmvc 版本)
首先在pom.xml檔案中新增對應的jar
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
在對應springmvc-context.xml檔案中配置
<bean id="redisHttpSessionConfiguration"
class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="600"/>
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="100" />
<property name="maxIdle" value="10" />
<property name="testOnBorrow" value="true" />
</bean>
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
<property name="poolConfig" ref="jedisPoolConfig" />
<property name="port" value="6379" />
<property name="hostName" value="192.168.1.11" />
<property name="password" value="xxx" />
<property name="timeout" value="30000" ></property>
</bean >
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
<property name="connectionFactory" ref="connectionFactory" />
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
</bean >
<bean id="redisUtil" class="com.isea533.mybatis.service.RedisUtil" >
<property name="redisTemplate" ref="redisTemplate" />
</bean >
其次在web.xml中配置(非常重要,filter的名字必須是springSessionRepositoryFilter)
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
訪問專案路徑呈現結果