净菜加工系统后台集群部署方案落地实现

48

@[toc]

净菜加工系统后台集群部署

前言

为什么要使用集群部署

当我们单机部署的时候,前端项目是打包在后台项目中的,通过Spring MVC来访问静态资源的形式来访问页面

  • 劣势一:

    使用Tomcat来作为静态资源的服务器,同时使用Tomcat来作为后台Servlet的容器,无疑是增大了Tomcat的压力

  • 劣势二:

    单机部署如果项目挂了,或者线程被占用满了,都会成为瓶颈,在生成环境中,至少应该保证项目能够集群部署提高容错率,可用性

集群部署带来的问题

  • 问题一:

    前端打包进后台部署,前端后端都是相同的host,不存在跨域问题,如果前后端分离部署,必然前端服务和后端服务的ipport不一致导致存在跨域问题

  • 问题二:

    后台集群部署后,保存用户登录的Session信息不能在多个服务中共享,存在Session共享问题

  • 问题三:

    项目中有使用到WebSocket,用户与后端服务建立的WebSocket长链接只能存在于一个后台服务中,问题是后台服务既不能像Session一样共享长链接,长链接也不能持久化

集群部署落地实现

解决方案

问题一:跨域

跨域问题我们在后端集体配置,后端作为最后的请求响应方,应该统一允许跨域请求的响应

问题二:Session共享

Session共享问题使用Spring Session框架配合RedisSession统一管理到Redis中,所有的后台读取Session都从Redis中读取实现Session共享

问题三:分布式WebSocket

使用消息队列来驱动WebSocket推送消息,方案落地详细说明

方案落地

跨域

SpringBoot可以很方便的配置全局跨域

  1. 先添加一个处理跨域的请求过滤器CorsFilter

    /**
    
  2. 添加跨域支持
    */
    @Configuration
    public class GlobalCorsConfiguration {

    @Bean
    public CorsFilter corsFilter() {

      CorsConfiguration corsConfiguration = new CorsConfiguration();
      // 允许携带Cookies
      corsConfiguration.setAllowCredentials(true);
      // 允许的请求源,允许哪些来源的host跨域
      // TODO 为了安全,此处后期修改成前端的host
      corsConfiguration.addAllowedOrigin("*");
      // 跨域带上所有的header信息
      corsConfiguration.addAllowedHeader("*");
      // 允许所有的请求类型跨域(GET/POST/DELETE/PUT...)
      corsConfiguration.addAllowedMethod("*");
    
      // 如果想要在跨域的同时新增自定义的请求头
      // corsConfiguration.addExposedHeader("head1");
      // corsConfiguration.addExposedHeader("cookies");
    
      UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
    
      // 所有的请求都会经过该过滤器
      urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
      return new CorsFilter(urlBasedCorsConfigurationSource);
    

    }

    }

  3. 如果项目使用了Spring Security需要添加Spring Security对跨域的支持

    @Configuration
    public class WebMvcSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf()
                    .disable()
                    // 添加跨域支持
                    .cors()
                    .and()
                    .authorizeRequests()
                    //处理跨域请求中的Preflight请求,放行option类型的请求
                    .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                    ...
        }
    }
    
  4. 别忘了对前端的请求框架axios进行配置

    // 跨域允许携带cookie
    axios.defaults.withCredentials = true
    

Session共享

Spring Session框架集成Redis后默认将系统Session管理放在了Redis中,无需过多配置

  1. 首先整合RedisSpring Session

    引入依赖,SpringBoot对spring-session-data-redis有默认的版本约束

    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>
    
  2. 剩下都是配置Redis的工作

    本文侧重点不在Redis,所以此处省略,Redis整合好之后直接测试,登录系统后使用Redis图形化工具查看Redis中的数据,就会有Session信息保存了进来

消息驱动WebSocket

当需要服务端通过WebSocket给客户端发送消息时,由于客户端只与其中一台单机服务器建立了长链接,所以无法锁定到具体的某一台单机服务器调用WebSocket发消息给客户端,所以使用消息队列来发送一个广播,广播到每一台服务器上,然后服务器各自查看自己是否与客户端建立了长链接,如果建立,则发送WebSocket通知,反之不处理

使用Nginx对后台服务负载均衡

传递请求域,否则后台无法拿到域名中的公司编号

proxy_set_header Host $host;