• Spring Cloud分布式Session共享实践


    通常情况下,Tomcat、Jetty等Servlet容器,会默认将Session保存在内存中。如果是单个服务器实例的应用,将Session保存在服务器内存中是一个非常好的方案。但是这种方案有一个缺点,就是不利于扩展。

    目前越来越多的应用采用分布式部署,用于实现高可用性和负载均衡等。那么问题来了,如果将同一个应用部署在多个服务器上通过负载均衡对外提供访问,如何实现Session共享?

    实际上实现Session共享的方案很多,其中一种常用的就是使用Tomcat、Jetty等服务器提供的Session共享功能,将Session的内容统一存储在一个数据库(如MySQL)或缓存(如Redis)中。

    下面我们将在springcloud微服务项目中,使用redis实现简单高效的session共享。

    项目介绍

    • eureka-server:注册中心
    • springcloud-session-redis:业务session所在项目
    • springcloud-session-zuul:路由网关

    eureka-server延用之前Eureka服务注册与发现一文中的注册中心,不再赘述

    springcloud-session-redis项目

    新建一个spring boot项目,命名springcloud-session-redis

    POM依赖配置

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     5     <modelVersion>4.0.0</modelVersion>
     6 
     7     <groupId>com.carry</groupId>
     8     <artifactId>springcloud-session-redis</artifactId>
     9     <version>0.0.1-SNAPSHOT</version>
    10     <packaging>jar</packaging>
    11 
    12     <name>springcloud-session-redis</name>
    13     <description>Demo project for Spring Boot</description>
    14 
    15     <parent>
    16         <groupId>org.springframework.boot</groupId>
    17         <artifactId>spring-boot-starter-parent</artifactId>
    18         <version>2.0.4.RELEASE</version>
    19         <relativePath /> <!-- lookup parent from repository -->
    20     </parent>
    21 
    22     <properties>
    23         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    24         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    25         <java.version>1.8</java.version>
    26         <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    27     </properties>
    28 
    29     <dependencies>
    30         <dependency>
    31             <groupId>org.springframework.boot</groupId>
    32             <artifactId>spring-boot-starter-data-redis</artifactId>
    33         </dependency>
    34         <dependency>
    35             <groupId>org.springframework.session</groupId>
    36             <artifactId>spring-session-data-redis</artifactId>
    37         </dependency>
    38         <dependency>
    39             <groupId>org.apache.commons</groupId>
    40             <artifactId>commons-pool2</artifactId>
    41         </dependency>
    42         <dependency>
    43             <groupId>org.springframework.boot</groupId>
    44             <artifactId>spring-boot-starter-web</artifactId>
    45         </dependency>
    46         <dependency>
    47             <groupId>org.springframework.cloud</groupId>
    48             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    49         </dependency>
    50         <dependency>
    51             <groupId>org.springframework.boot</groupId>
    52             <artifactId>spring-boot-starter-actuator</artifactId>
    53         </dependency>
    54 
    55     </dependencies>
    56 
    57     <dependencyManagement>
    58         <dependencies>
    59             <dependency>
    60                 <groupId>org.springframework.cloud</groupId>
    61                 <artifactId>spring-cloud-dependencies</artifactId>
    62                 <version>${spring-cloud.version}</version>
    63                 <type>pom</type>
    64                 <scope>import</scope>
    65             </dependency>
    66         </dependencies>
    67     </dependencyManagement>
    68 
    69     <build>
    70         <plugins>
    71             <plugin>
    72                 <groupId>org.springframework.boot</groupId>
    73                 <artifactId>spring-boot-maven-plugin</artifactId>
    74             </plugin>
    75         </plugins>
    76     </build>
    77 
    78 
    79 </project>

    配置文件

    在application.yml中加入redis、eureka、port等配置

    server:
      port: 8090
    spring:
      application:
        name: service-session-redis
      redis:
        host: 192.168.68.100
        port: 6379
        password: 123456
        timeout: 6000ms
        lettuce:
          pool:
            max-active: 8
            max-wait: -1ms
            max-idle: 8
            min-idle: 0
        database: 0
    eureka:
      client:
        serviceUrl:
          defaultZone: http://admin:123456@localhost:8761/eureka/
    management: 
      endpoints:
        web:
          exposure: 
            include: "*"
          cors:
            allowed-origins: "*"
            allowed-methods: "*" 

    Redis Session配置类

     1 package com.carry.config;
     2 
     3 import org.springframework.context.annotation.Configuration;
     4 import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
     5 
     6 @Configuration
     7 @EnableRedisHttpSession
     8 public class RedisSessionConfig {
     9 
    10 }

    控制层Controller中添加测试方法

     1 package com.carry.controller;
     2 
     3 import javax.servlet.http.HttpServletRequest;
     4 import javax.servlet.http.HttpSession;
     5 
     6 import org.springframework.cloud.context.config.annotation.RefreshScope;
     7 import org.springframework.util.StringUtils;
     8 import org.springframework.web.bind.annotation.GetMapping;
     9 import org.springframework.web.bind.annotation.RestController;
    10 
    11 @RestController
    12 @RefreshScope
    13 public class UserManagementController {
    14 
    15     /**
    16      * redis sesion共享
    17      * 
    18      * @param request
    19      * @return
    20      */
    21     @GetMapping("/getUser")
    22     public String getUser(HttpServletRequest request) {
    23         HttpSession session = request.getSession();
    24         String username = (String) session.getAttribute("username");
    25         if (StringUtils.isEmpty(username)) {
    26             username = "testSessionRedis|" + System.currentTimeMillis();
    27             session.setAttribute("username", username);
    28         }
    29         System.out.println("访问端口:" + request.getServerPort());
    30         return username;
    31     }
    32 }

    springcloud-session-zuul项目

    新建springboot项目,命名springcloud-session-zuul

    POM依赖配置

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     5     <modelVersion>4.0.0</modelVersion>
     6 
     7     <groupId>com.carry</groupId>
     8     <artifactId>springcloud-session-zuul</artifactId>
     9     <version>0.0.1-SNAPSHOT</version>
    10     <packaging>jar</packaging>
    11 
    12     <name>springcloud-session-zuul</name>
    13     <description>Demo project for Spring Boot</description>
    14 
    15     <parent>
    16         <groupId>org.springframework.boot</groupId>
    17         <artifactId>spring-boot-starter-parent</artifactId>
    18         <version>2.0.4.RELEASE</version>
    19         <relativePath /> <!-- lookup parent from repository -->
    20     </parent>
    21 
    22     <properties>
    23         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    24         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    25         <java.version>1.8</java.version>
    26         <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    27     </properties>
    28 
    29     <dependencies>
    30         <dependency>
    31             <groupId>org.springframework.cloud</groupId>
    32             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    33         </dependency>
    34         <dependency>
    35             <groupId>org.springframework.cloud</groupId>
    36             <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    37         </dependency>
    38     </dependencies>
    39 
    40     <dependencyManagement>
    41         <dependencies>
    42             <dependency>
    43                 <groupId>org.springframework.cloud</groupId>
    44                 <artifactId>spring-cloud-dependencies</artifactId>
    45                 <version>${spring-cloud.version}</version>
    46                 <type>pom</type>
    47                 <scope>import</scope>
    48             </dependency>
    49         </dependencies>
    50     </dependencyManagement>
    51 
    52     <build>
    53         <plugins>
    54             <plugin>
    55                 <groupId>org.springframework.boot</groupId>
    56                 <artifactId>spring-boot-maven-plugin</artifactId>
    57             </plugin>
    58         </plugins>
    59     </build>
    60 
    61 
    62 </project>

    配置文件

    server:
      port: 1100
    spring:
      application:
        name: service-session-zuul
    zuul: 
      ignoredServices: '*' #忽略所有未配置的service
      host:
        connect-timeout-millis: 20000
        socket-timeout-millis: 20000
      routes:
        redis-session-service: 
          path: /user-session/**
          serviceId: service-session-redis
          sensitiveHeaders: "*" 
    ribbon: #ribbon负载均衡参数配置
      ReadTimeout: 5000
      ConnectTimeout: 5000
    eureka:
      client:
        serviceUrl:
          defaultZone: http://admin:123456@localhost:8761/eureka/

    启动类

     1 package com.carry;
     2 
     3 import org.springframework.boot.SpringApplication;
     4 import org.springframework.boot.autoconfigure.SpringBootApplication;
     5 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
     6 import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
     7 
     8 @EnableEurekaClient
     9 @SpringBootApplication
    10 @EnableZuulProxy
    11 public class SpringcloudSessionZuulApplication {
    12 
    13     public static void main(String[] args) {
    14         SpringApplication.run(SpringcloudSessionZuulApplication.class, args);
    15     }
    16 }

    测试

    依次启动

    • eureka-server
    • springcloud-session-redis
    • springcloud-session-zuul

    多次访问网关地址http://localhost:1100/user-session/getUser,发现后台轮询访问springcloud-session-redis的8090与8091两个实例

    而我们页面得到的结果是不变的,由此可以说明session是一致的

    注意:springcloud项目中经过网关zuul转发请求后发生session失效问题,这是由于zuul默认会丢弃原来的session并生成新的session,解决方法网关配置文件application.yml 中添加 sensitiveHeaders: “*”

  • 相关阅读:
    【luogu P4139】 上帝与集合的正确用法
    pb_ds学习
    【luogu P3868】 [TJOI2009]猜数字
    BZOJ3040: 最短路(road)
    【luogu P1064】 金明的预算方案
    【luogu P2893】 [USACO08FEB]修路Making the Grade
    【luogu P2801】 教主的魔法
    UVA10816 Travel in Desert
    P2916 [USACO08NOV]安慰奶牛Cheering up the Cow
    【BZOJ 2054】 疯狂的馒头
  • 原文地址:https://www.cnblogs.com/carrychan/p/9548013.html
Copyright © 2020-2023  润新知