首頁 > 軟體

redis實現分散式session的解決方案

2022-03-08 13:04:15

一、首先Session

Session 是使用者端與伺服器通訊對談技術, 比如瀏覽器登陸、記錄整個瀏覽對談資訊。session存放在伺服器,關閉瀏覽器不會失效。

Session實現原理

客戶對向伺服器端傳送請求後,Session 建立在伺服器端,返回Sessionid給使用者端瀏覽器儲存在本地,當下次傳送請求的時候,在請求頭中傳遞sessionId獲取對應的從伺服器上獲取對應的Sesison

請求過程:

伺服器端接受到使用者端請求,會建立一個session,使用響應頭返回 sessionId給使用者端。使用者端獲取到sessionId後,儲存到本地。

下次請求:使用者端將原生的sessionId通過請求頭傳送到伺服器。伺服器從請求頭獲取到對應的sessionId,使用sessionId在本地session記憶體中查詢。

HttpSession session = request.getSession(); 

//預設建立一個session 預設值為true 沒有找到對應的session 自動建立session

HttpSession session = request.getSession(false)

//true的情況是 使用者端使用對應的sessionId查詢不到對應的session 會直接建立一個新的session 如果有的話直接覆蓋之前的

//false 使用者端使用對應的sessionId查詢不到對應的session 不會建立新的session

session 包括 sessionId和sessionValue

session本身是臨時的 token(令牌)與 sessionId很相似 保證了臨時且唯一

玩下session:

前提需要安裝nginx

設定如下:

host檔案:c:windowssystem32driversetc

存取 www.toov5.com時候 走的nginx的伺服器域名 然後預設監聽的埠號80。 進而通過設定upstream 負載均衡!

lz在玩時候,弄到了半夜,也沒排查出來原因,媽的氣死了! 地址寫成了 127.0.0.1

yml:

server:
  port: 8080 

pom:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.toov5.loveCode</groupId>
  <artifactId>loveCode</artifactId>
  <version>0.0.1-SNAPSHOT</version>
   
  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <weixin-java-mp.version>2.8.0</weixin-java-mp.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.build.locales>zh_CN</project.build.locales>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- <exclusions> <exclusion> <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId> </exclusion> </exclusions> -->
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <!-- Testing Dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--spring session 與redis應用基本環境設定,需要開啟redis後才可以使用,不然啟動Spring boot會報錯 -->
        <!-- <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency> -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
 
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <maimClass>com.meiteedu.WxMpApplication</maimClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
 
            </plugin>
        </plugins>
    </build>
   
</project>

伺服器端程式碼:

package com.toov5.loveCode;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class TestSessionController {
    @Value("${server.port}")
    private String serverPort;

    @RequestMapping("/")
    public String index() {
        return serverPort;
    }

    // 建立session 對談
    @RequestMapping("/createSession")
    public String createSession(HttpServletRequest request, String nameValue) {
        // 預設 建立一個session,
        HttpSession session = request.getSession();
        System.out.println(
                "存入Session  sessionid:資訊" + session.getId() + ",nameValue:" + nameValue + ",serverPort:" + serverPort);
        session.setAttribute("name", nameValue);
        return "success-" + serverPort;
    }

    // 獲取session 對談
    @RequestMapping("/getSession")
    public Object getSession(HttpServletRequest request) {
        // 設定為true 情況下的時候,使用者端使用對應的sessionid 查詢不到對應的sesison 會直接建立一個新的session
        // 設定為false 情況下的時候,使用者端使用對應的sessionid 查詢不到對應的sesison 不 會直接建立一個新的session
        HttpSession session = request.getSession(true);
        if (session == null) {
            return serverPort + "  該伺服器上沒有存放對應的session值";
        }
        System.out.println("獲取Session sessionid:資訊" + session.getId() + "serverPort:" + serverPort);
        Object value = session.getAttribute("name");
        return serverPort + "-" + value;
    }

}

啟動類:啟動兩次 埠號修改8080、 8081

package com.toov5.loveCode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@EnableAutoConfiguration
@SpringBootApplication
public class AppSession {

    public static void main(String[] args) {
        SpringApplication.run(AppSession.class, args);
    }

}

執行結果:8080 和 8081來回切換 負載均衡

呼叫伺服器端方法: fist 存放在8080

查詢不到哦!

8081 沒有 就建立新的session 覆蓋原來的sessionId true沒有就建立

下次 又去8080 又沒有 又建立 來回折騰..............

此時:

修改false 沒有時候不建立

然後傳入 value 然後繼續輪訓存取;

二、分散式Session

1、直接使用cookie替代session 不安全(存使用者端)

2、Nginx的IP繫結 目的是同一個IP只能指定同一個機器存取(相當於沒做叢集了)

3、 使用資料庫(效率低)

4、tomcat內建Session同步,通過廣播可能產生延遲,佔用頻寬

5、使用 Spring-Session框架,相當於把session快取快取到redis中 (快取框架,快取Session的值)

6、可以使用token替代session功能。自定義令牌替代session

Spring-Session 重寫httpsession框架,將對應的值快取到redis中,有點類似於一級、二級快取。

必須要有的!

yml檔案:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.toov5.loveCode</groupId>
  <artifactId>loveCode</artifactId>
  <version>0.0.1-SNAPSHOT</version>
   
  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <weixin-java-mp.version>2.8.0</weixin-java-mp.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.build.locales>zh_CN</project.build.locales>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- <exclusions> <exclusion> <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId> </exclusion> </exclusions> -->
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <!-- Testing Dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--spring session 與redis應用基本環境設定,需要開啟redis後才可以使用,不然啟動Spring boot會報錯 -->
           <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
 
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <maimClass>com.meiteedu.WxMpApplication</maimClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
 
            </plugin>
        </plugins>
    </build>
   
</project>

 非常非常重要的:一定要jredis引入 同時這個對session提供了大力支援哈哈

yml 的redis組態檔:

server:
  port: 8080
 
redis:
  hostname: 192.168.91.3    
  port:  6379
  password:  123

 後臺業務邏輯:

package com.toov5.loveCode;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class TestSessionController {
    @Value("${server.port}")
    private String serverPort;

    @RequestMapping("/")
    public String index() {
        return serverPort;
    }

    // 建立session 對談
    @RequestMapping("/createSession")
    public String createSession(HttpServletRequest request, String nameValue) {
        // 預設 建立一個session,
        HttpSession session = request.getSession();
        System.out.println(
                "存入Session  sessionid:資訊" + session.getId() + ",nameValue:" + nameValue + ",serverPort:" + serverPort);
        session.setAttribute("name", nameValue);
        return "success-" + serverPort;
    }

    // 獲取session 對談
    @RequestMapping("/getSession")
    public Object getSession(HttpServletRequest request) {
        // 設定為true 情況下的時候,使用者端使用對應的sessionid 查詢不到對應的sesison 會直接建立一個新的session
        // 設定為false 情況下的時候,使用者端使用對應的sessionid 查詢不到對應的sesison 不 會直接建立一個新的session
        HttpSession session = request.getSession(false);
        if (session == null) {
            return serverPort + "  該伺服器上沒有存放對應的session值";
        }
        System.out.println("獲取Session sessionid:資訊" + session.getId() + "serverPort:" + serverPort);
        Object value = session.getAttribute("name");
        return serverPort + "-" + value;
    }

}

設定:

package com.toov5.loveCode;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

//這個類用設定redis伺服器的連線
//maxInactiveIntervalInSeconds為SpringSession的過期時間(單位:秒)
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {

    // 冒號後的值為沒有組態檔時,制動裝載的預設值
    @Value("${redis.hostname:localhost}")
    String HostName;
    @Value("${redis.port:6379}")
    int Port;
    @Value("${redis.password}") 
    String password;
    
    @Bean
    public JedisConnectionFactory connectionFactory() {
        JedisConnectionFactory connection = new JedisConnectionFactory();
        connection.setPort(Port);
        connection.setHostName(HostName);
        connection.setPassword(password);
        return connection;
    }
}

初始化:

package com.toov5.loveCode;

import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;

//初始化Session設定
public class SessionInitializer extends AbstractHttpSessionApplicationInitializer{
    public SessionInitializer() {
        super(SessionConfig.class);
    }
}

啟動類:

package com.toov5.loveCode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@EnableAutoConfiguration
@SpringBootApplication
public class AppSession {

    public static void main(String[] args) {
        SpringApplication.run(AppSession.class, args);
    }

}

雖然是存放在8081,但是存取時候 都有哦~ 大家試試玩玩吧~~

 引入的jar包重寫了 HttpSession類 去解決Session共用問題

而此時的:redis

控制檯:

補充:

Spring Boot 整合redis:

 到此這篇關於redis實現分散式session的解決方案的文章就介紹到這了,更多相關redis 分散式session內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com