天天看點

Nginx系列教程(9)nginx 解決session一緻性session 粘滞性session 複制session 共享(springboot)session 共享(springmvc)往期文章

Nginx系列教程(9)nginx 解決session一緻性session 粘滞性session 複制session 共享(springboot)session 共享(springmvc)往期文章
Nginx系列教程(9)nginx 解決session一緻性session 粘滞性session 複制session 共享(springboot)session 共享(springmvc)往期文章

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伺服器請求發現不存在。

在nginx配置檔案中,增加配置, 對IP進行HASH後,散列到伺服器。

這個實作最簡單。但對于前端部署了SBC的,或者很多請求都是從某一個外網網關過來的,就沒用了。而且對于app會切換wifi變ip的,也不好用。

session 複制

可以通過tomcat的server.xml檔案進行配置,這樣每個tomcat都會同步對應的session,那麼此時即使某個tomcat被當機了,也不影響服務。

具體的tomcat可以參見如下 ,

tomcat 官網對應的tomcat叢集配置

在 tomcat的web.xml中配置為叢集模式,

在tomcat的server.xml中配置叢集資訊。

配置後,就可以自動複制session了。

缺點是每台伺服器上都要儲存全量的session資訊,在伺服器多的情況下,基本不可用。但開發簡單,在隻有兩三台伺服器的時候,是可以的。

<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>
           

session 共享(springboot)

Nginx系列教程(9)nginx 解決session一緻性session 粘滞性session 複制session 共享(springboot)session 共享(springmvc)往期文章

對應的項目中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
Nginx系列教程(9)nginx 解決session一緻性session 粘滞性session 複制session 共享(springboot)session 共享(springmvc)往期文章

下面我們換個端口再通路一次看看

這次我把端口換成了8888 通路:

http://localhost:8888/session
Nginx系列教程(9)nginx 解決session一緻性session 粘滞性session 複制session 共享(springboot)session 共享(springmvc)往期文章

重新整理了redis資料庫,緩存的資料也沒變

Nginx系列教程(9)nginx 解決session一緻性session 粘滞性session 複制session 共享(springboot)session 共享(springmvc)往期文章

結果中的SessionId是一緻的,卻是由兩個不同項目工程來提供服務。這樣子,SpringSession 利用攔截器 Filter 幫我們在每個請求前進行了同步設定,達到了分布式系統中 session 共享。

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>
           

通路項目路徑呈現結果

Nginx系列教程(9)nginx 解決session一緻性session 粘滞性session 複制session 共享(springboot)session 共享(springmvc)往期文章
Nginx系列教程(9)nginx 解決session一緻性session 粘滞性session 複制session 共享(springboot)session 共享(springmvc)往期文章

往期文章

Nginx系列教程(1)nginx基本介紹和安裝入門 Nginx系列教程(2)nginx搭建靜态資源web伺服器 Nginx系列教程(3)nginx緩存伺服器上的靜态檔案 Nginx系列教程(4)nginx處理web應用負載均衡問題以保證高并發 Nginx系列教程(5)如何保障nginx的高可用性(keepalived) Nginx系列教程(6)nginx location 比對規則詳細解說 Nginx系列教程 (7) nginx rewrite配置規則詳細說明 Nginx系列教程(8)nginx配置安全證書SSL