分布式/集群,session共享一个必须面对的问题

首先讲一下对分布式、集群和微服务得理解

  • 分布式:一个业务拆分成多个子业务,部署在不同的服务器上。分布式需要做好事务管理
  • 集群:同一个业务,部署在多个服务器上,集群需要做好session共享,确保在不同服务器切换的过程中不会因为没有获取到session而终止与i出服务。一般是配置nginx的负载均衡实现:静态资源共享,Session共享可以附带实现,Nginx支持5000个并发量。
  • 集群是解决高可用的,而分布式是解决高性能、高并发的。分布式中的每一个节点都可以做集群。而集群不一定就是分布式的。集群是一个有组织性的,如果一台服务器垮了,其它的服务器可以顶上来。而分布式的每一个节点,都完成不同的任务,如果一个节点垮了,那这个业务就不可访问了。
  • 比如一个程序员是单机,多个程序员是集群;一个后端程序员加上一个前端程序员是分布式
  • 微服务就是微小紧凑的服务,提供统一简捷的API供外部访问,实现一组独立的功能。微服务的设计是为了不因为某个模块的升级和bug影响现有的系统业务。
  • 分布式和微服务的架构很相似,只是部署的方式不同。微服务与分布式的细微差别是,微服务的应用不一定是分散在多个服务器上,它也可以是同一个服务器。

 

分布式/集群,session共享一个必须面对的问题

 

在这样的架构中,会存在单服务中不存在的问题,例如客户端发起一个请求,当请求到达Nginx上之后,被Ngnix转发到TomcatA上,之后在TomcatA上往session中保存了一份数据,下次又来一个请求,这个请求则被转发到TomcatB上,此时再去Session中获取数据,发现没有之前的数据。对这类问题的解决,办法是将各个服务之间需要共享的数据,保存到一个公共的地方(比较常见的是用redis)

分布式/集群,session共享一个必须面对的问题

当所有Tomcat需要往session中写数据时,都往Redis中写,当所有Tomcat需要读数据时,都从Redis中读。这样,不同的服务就可以使用相同的session数据了。可以由开发者手动实现,即手动往Redis中存储数据,手动从Redis中读取数据,相当于使用一些Redis客户端工具来实现这样的功能,这样手动实现的工作量很大。

比较简化的方案就是使用Spring Session来实现这一共功能,Spring Session就是使用Spring中的代理过滤器,将所有Session操作拦截下来,自动的将数据同分到Redis中,或则自动的从Redis中读取数据。

对于开发者,所有session同步的操作都是透明的,开发者使用 Spring Session ,配置完成后就像使用普通的session一样。

首先在我们的spring boot 项目中,引入web,Spring Session以及Redis

pom.xml文件如下

分布式/集群,session共享一个必须面对的问题

这里根据Spring boot版本的不同,会有些变化,最新版本的除了上面的之外还需要添加Spring Security依赖(其他操作不受影响,仅仅只是多了一个依赖,当然也多了 Spring Security 的一些默认认证流程)。

redis配置

分布式/集群,session共享一个必须面对的问题

或则 这里的 Redis ,我虽然配置了四行,但是考虑到端口默认就是 6379 ,database 默认就是 0,所以真正要配置的,其实就是两行。

分布式/集群,session共享一个必须面对的问题

配置完成后就可以使用 Spring Session,就是使用普通的HttpSession,其他的Session同步到Redis等操作。框架可以自动帮你完成。

分布式/集群,session共享一个必须面对的问题

Spring Boot会以集群的方式启动,为了获取每一个请求对应的Spring Boot提供的服务,需要在每次请求时返回当前服务的端口号,因此需要注入server.port

项目打包

分布式/集群,session共享一个必须面对的问题

打包之后启动项目的两个实例

分布式/集群,session共享一个必须面对的问题

然后先访问 localhost:8080/set8080 这个服务的 Session 中保存一个变量,访问完成后,数据就已经自动同步到 Redis 中 了 :

分布式/集群,session共享一个必须面对的问题

然后,再调用 localhost:8081/get 接口,就可以获取到 8080 服务的 session 中的数据:

分布式/集群,session共享一个必须面对的问题

此时关于 session 共享的配置就已经全部完成了,session 共享的效果我们已经看到了,但是每次访问都是我自己手动切换服务实例,因此,接下来我们来引入 Nginx ,实现服务实例自动切换。

首先讲一下Nginx的安装

到nginx官网上下载相应的安装包,http://nginx.org/en/download.html

分布式/集群,session共享一个必须面对的问题

 

分布式/集群,session共享一个必须面对的问题

分布式/集群,session共享一个必须面对的问题

分布式/集群,session共享一个必须面对的问题

分布式/集群,session共享一个必须面对的问题

分布式/集群,session共享一个必须面对的问题

分布式/集群,session共享一个必须面对的问题

进入Nginx的安装目录的conf找到nginx.conf文件

分布式/集群,session共享一个必须面对的问题

配置中:

  1. upstream 表示配置上游服务器

  2. javaboy.org 表示服务器集群的名字,这个可以随意取名字

  3. upstream 里边配置的是一个个的单独服务

  4. weight 表示服务的权重,意味者将有多少比例的请求从 Nginx 上转发到该服务上

  5. location 中的 proxy_pass 表示请求转发的地址, / 表示拦截到所有的请求,转发转发到刚刚配置好的服务集群中

  6. proxy_redirect 表示设置当发生重定向请求时,nginx 自动修正响应头数据(默认是 Tomcat 返回重定向,此时重定向的地址是 Tomcat 的地址,我们需要将之修改使之成为 Nginx 的地址)。

配置完成后,将本地的Spring Boot打包好的jar上传到linux,然后在linux上分别启动两个Spring Boot实例

分布式/集群,session共享一个必须面对的问题

其中

  • nohup 表示当终端关闭时,Spring Boot 不要停止运行

  • & 表示让 Spring Boot 在后台启动    

配置完成后,重启 Nginx

192.168.101.54为linux系统的ip地址(centos版本可以通过 ip addr查看)这里https://blog.****.net/zhaomengxia123/article/details/90728931有详细讲解

分布式/集群,session共享一个必须面对的问题

Nginx 启动成功后,我们首先手动清除 Redis 上的数据,然后访问 192.168.101.54/set 表示向 session中保存数据,这个请求首先会到达 Nginx 上,再由 Nginx 转发给某一个 SpringBoot 实例

如上,表示端口为 8081SpringBoot 处理了这个192.168.101.54 /set 请求,再访问 192.168.101.54/get 请求:

 总结

本文主要向大家介绍了 Spring Session 的使用,另外也涉及到一些 Nginx 的使用 ,虽然本文较长,但是实际上 Spring Session 的配置没啥。

我们写了一些代码,也做了一些配置,但是全都和 Spring Session 无关,配置是配置 Redis,代码就是普通的 HttpSession,和 Spring Session 没有任何关系!

唯一和 Spring Session 相关的,可能就是我在一开始引入了 Spring Session 的依赖吧!

如果大家没有在 SSM 架构中用过 Spring Session ,可能不太好理解我们在 Spring Boot 中使用 Spring Session 有多么方便,因为在 SSM 架构中,Spring Session 的使用要配置三个地方 ,一个是 web.xml 配置代理过滤器,然后在 Spring 容器中配置 Redis,最后再配置 Spring Session,步骤还是有些繁琐的,而 Spring Boot 中直接帮我们省去了这些繁琐的步骤!不用再去配置 Spring Session。