通常情况下,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依赖配置

 <?xml version="1.0" encoding="UTF-8"?>
<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.carry</groupId>
<artifactId>springcloud-session-redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>springcloud-session-redis</name>
<description>Demo project for Spring Boot</description> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </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配置类

 package com.carry.config;

 import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; @Configuration
@EnableRedisHttpSession
public class RedisSessionConfig { }

控制层Controller中添加测试方法

 package com.carry.controller;

 import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession; import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@RefreshScope
public class UserManagementController { /**
* redis sesion共享
*
* @param request
* @return
*/
@GetMapping("/getUser")
public String getUser(HttpServletRequest request) {
HttpSession session = request.getSession();
String username = (String) session.getAttribute("username");
if (StringUtils.isEmpty(username)) {
username = "testSessionRedis|" + System.currentTimeMillis();
session.setAttribute("username", username);
}
System.out.println("访问端口:" + request.getServerPort());
return username;
}
}

springcloud-session-zuul项目

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

POM依赖配置

 <?xml version="1.0" encoding="UTF-8"?>
<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.carry</groupId>
<artifactId>springcloud-session-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>springcloud-session-zuul</name>
<description>Demo project for Spring Boot</description> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </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/

启动类

 package com.carry;

 import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @EnableEurekaClient
@SpringBootApplication
@EnableZuulProxy
public class SpringcloudSessionZuulApplication { public static void main(String[] args) {
SpringApplication.run(SpringcloudSessionZuulApplication.class, args);
}
}

测试

依次启动

  • 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: “*”

Spring Cloud分布式Session共享实践的更多相关文章

  1. Spring Boot(十一)Redis集成从Docker安装到分布式Session共享

    一.简介 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API,Redis也是技术领域使用最为广泛的存储中间件,它是 ...

  2. Spring boot整合redis实现shiro的分布式session共享

    我们知道,shiro是通过SessionManager来管理Session的,而对于Session的操作则是通过SessionDao来实现的,默认的情况下,shiro实现了两种SessionDao,分 ...

  3. Spring Cloud Config 配置中心实践过程中,你需要了解这些细节!

    本文导读: Spring Cloud Config 基本概念 Spring Cloud Config 客户端加载流程 Spring Cloud Config 基于消息总线配置 Spring Cloud ...

  4. 039.[转] 基于 Kubernetes 和 Spring Cloud 的微服务化实践

    http://dockone.io/article/2967 基于 Kubernetes 和 Spring Cloud 的微服务化实践 写在前面 网易云容器平台期望能给实施了微服务架构的团队提供完整的 ...

  5. 分布式session共享

    一.前言 为什么会出现session共享问题? 客户端与服务器交互时会产生唯一的sessionid用于标记用户,但是在分布式架构中,如果还是采用 session 的方式,用户发起请求,通过 nginx ...

  6. SpringBoot搭建基于Apache Shiro+Redis的分布式Session共享功能

    我们在上一遍文档中已经完成了Shiro验证功能.(http://www.cnblogs.com/nbfujx/p/7773789.html),在此基础上我们将完成分布式Session共享功能. Red ...

  7. 分布式Session共享(二):tomcat+memcached实现session共享

    一.前言 本文主要测试memcached实现session共享的实现方式,不讨论如何让nginx参与实现负载均衡等. 二.环境配置 本测试在Window下进行 name version port To ...

  8. 分布式Session共享(一):tomcat+redis实现session共享

    一.前言 本文主要测试redis实现session共享的实现方式,不讨论如何让nginx参与实现负载均衡等. 二.环境配置 本测试在Window下进行 name version port Tomcat ...

  9. Spring Cloud 分布式事务管理

    Spring Cloud 分布式事务管理 在微服务如火如荼的情况下,越来越多的项目开始尝试改造成微服务架构,微服务即带来了项目开发的方便性,又提高了运维难度以及网络不可靠的概率. Spring Clo ...

随机推荐

  1. 51nod 1096 距离之和最小 思维题,求中位数

    题目: 在一条直线上,与两个点距离之和最小的点,是怎样的点? 很容易想到,所求的点在这两个已知点的中间,因为两点之间距离最短. 在一条直线上,与三个点距离之和最小的点,是怎样的点? 由两个点的规律,我 ...

  2. 「JavaSE 重新出发」02. 数据类型与运算符

    「TOC」 Java 程序基本要求 Java 数据类型 基本数据类型 复合数据类型 运算符 逻辑运算符 位运算符 运算符优先级 Java 程序基本要求 public class : 一个 Java 文 ...

  3. windows 路由

    route ? 查看帮助 route print 查看路由表 添加一条路由: route add 10.10.10.0 mask 255.255.255.0  192.168.1.1 #到达10.10 ...

  4. 3dmax实例教程-使用3ds Max 创建一个完整的场景

    本篇教程讲述了利用3ds max创建一个完整的场景. 灵感来源:当我在遇到一些事情睡不着觉的时候我便在努力想象一些别的事情,于是我便想到了这个场景,其实对于我的这个角色我即没有参考图也没有草稿图,有的 ...

  5. Debian9.5系统DNS服务器BIND软件配置说明

    DNS的出现的历史 网络出现的早期是使用IP地址通讯的,那时就几台主机通讯.但是随着接入网络主机的增多,这种数字标识的地址非常不便于记忆,UNIX上就出现了建立一个叫做hosts的文件(Linux和W ...

  6. 路飞学城Python-Day9

    [23.函数-高阶函数]变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称为高阶函数如果一个函数可以接收另一个函数,这个函数就称为高阶函数 def func ...

  7. matplotlib bar函数重新封装

    参考: https://blog.csdn.net/jenyzhang/article/details/52047557 https://blog.csdn.net/liangzuojiayi/art ...

  8. [APIO2014]回文串(回文自动机)

    题意 给你一个由小写拉丁字母组成的字符串 s.我们定义 s 的一个子串的存在值为这个子串在 s 中出现的次数乘以这个子串的长度. 对于给你的这个字符串 s,求所有回文子串中的最大存在值. |S|< ...

  9. Tomcat跨域资源共享

    1.下载Jar包 cors-filter-1.7.jar java-property-utils-1.9.jar 下载完成后将Jar拷贝到tomcat下lib目录中 2.修改web.xml配置 在29 ...

  10. PKU 2184 Cow Exhibition 01背包

    题意: 有一些牛,每头牛有一个Si值,一个Fi值,选出一些牛,使得max( sum(Si+Fi) ) 并且 sum(Si)>=0, sum(Fi)>=0 思路: 随便选一维做容量(比如Fi ...