栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

SpringCloud-微服务入门之Gateway+Nginx(4)

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringCloud-微服务入门之Gateway+Nginx(4)

确保你已经学完了SpringCloud-微服务入门之OpenFeign(3)

Gateway网关简介

Spring Cloud GateWay是Spring Cloud的⼀个全新项⽬,⽬标是取代Netflix Zuul,基于Spring5.0+SpringBoot2.0+WebFlux(基于⾼性能的Reactor模式响应式通信框架Netty,异步⾮阻塞模型)等技术开发,性能⾼于Zuul,官⽅测试,GateWay是Zuul的1.6倍,旨在为微服务架构提供⼀种简单有效的统⼀的API路由管理⽅式
Gateway中文文档

为什么需要网关

API网关的出现的原因是微服务架构的出现,不同的微服务一般有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成完成一个业务需求,如果让客户端直接与各个微服务通信,会出现以下的问题。

  1. 客户端会多次请求不同的微服务,增加了客户端的复杂性。
  2. 存在跨域请求,在一定场景下处理相对复制。
  3. 认证复杂,每个服务都需要独立的认证。
  4. 难以重构,随着项目的迭代。可能需要重新划分微服务。如果客户端与微服务直接通信,那么重构将会很复杂。
  5. 某些微服务可能使用了防火墙/浏览器不友好的协议,直接访问会有一定的困难。

以上的问题可以借助API网关来解决。API网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过API网关这一层。也就是说,API网关可以完成安全、性能、监控等功能,而服务提供者可以专门的完成具体的业务逻辑。

使用API网关的优点
  1. 易于监控,可以在网关收集监控数据并将其推送到外部系统进行分析;
  2. 易于认证,可以在网关进行认证,然后再将请求转发到后端的微服务,而无需在每个微服务中进行认证;
  3. 减少客户端和各个微服务之间的交互次数。
核心三要素

项目结构图

上面这图config和controller,filter是可选的有需求的话在进行添加

搭建网关(基础)

添加依赖

    
        
        
            org.example
            common
            1.0-SNAPSHOT
        

        
            org.springframework.cloud
            spring-cloud-starter-gateway
        

        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
    

添加启动类

@SpringBootApplication
public class GatewayApplication {

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

添加配置文件

server:
  port: 10010

# 设置  服务名 为gateway-service
spring:
  application:
    name: gateway
  profiles:
    active: common
  cloud:
    gateway:
      default-filters:
        # 去掉全部前缀api
        - RewritePath=/api(?/?.*),/${segment}
      routes:
        - id: consumer-route # 路由id,可以随意写不影响  一般都是以要代理的服务器名称-route
          uri: lb://consumer # 要访问的服务名称 (集群的时候可以防止宕机)
          #我们请求http://consumer/xxxx 会被拦截
          predicates: #允许的路由地址,要算上过滤器(filters)
            - Path=/api/user
                //获取请求对象
                ServerHttpRequest request = exchange.getRequest();
                //判断路径中key是否包含 ,如果包含那么就拦截
                if (request.getQueryParams().containsKey(config.param1)&&request.getQueryParams().containsKey(config.param2)) {
                    //返回一个405状态 请求的方法不允许
                    exchange.getResponse().setStatusCode(HttpStatus.METHOD_NOT_ALLOWED);
                    return exchange.getResponse().setComplete();
                }
                return chain.filter(exchange);//放行所有请求
            }
        };
        return gatewayFilter;
    }

}
自定义全局过滤器

全局过滤是在局部过滤之前执行的,作用全部的路由,一般用作权限效验等操作,无须其他配置直接继承GlobalFilter接口实现后就自动生效

import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("-----------------全局过滤器MyGlobalFilter------------------- --");
        // 获取路径参数中指定的key对应的value值
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        //判断token是否为空的
        if (StringUtils.isBlank(token)) {
             //返回一个401状态 没有权限
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        //放行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //值越小越先执行
        return 1;
    }
}
网关跨域
spring:
  application:
    name: gateway-service
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allow-credentials: true #允许携带认证信息Cookie
            allowed-origins: "*"   # 允许所有请求
            allowed-headers: "*"   #允许所有请求头
            allowed-methods:  #允许指定的请求方式
              - OPTIONS
              - GET
              - POST
            max-age: 86400  # 86400 秒,也就是 24 小时 在有效时间内,浏览器无须为同一请求再次发起预检请求,可以减少发送请求的次数,减少系统部分压力。

还可以使用代码方式进行跨域

// 解决网关跨域问题
@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}
实现负载均衡器

在gateway中已经默认集成了负载均衡相关的依赖,相关配置我们在之前common模块中已经配置完毕了

那么我们在路由的时候需要指定服务名称才行

    routes:
      - id: consumer-route
        uri: lb://consumer  #想要负载必须指定lb://服务名称

创建2个相同的consumer(消费者),都启动起来
consumer: 9001 , consumer1:9002 , consumer2:9003


然后进行访问,就会发现是走负载的

实现熔断降级

为什么要实现熔断降级?

在分布式系统中,网关作为流量的入口,因此会有大量的请求进入网关,向其他服务发起调用,其他服务不可避免的会出现调用失败(超时、异常),失败时不能让请求堆积在网关上,需要快速失败并返回给客户端,想要实现这个要求,就必须在网关上做熔断、降级操作。

为什么在网关上请求失败需要快速返回给客户端?

因为当一个客户端请求发生故障的时候,这个请求会一直堆积在网关上,当然只有一个这种请求,网关肯定没有问题(如果一个请求就能造成整个系统瘫痪,那这个系统可以下架了),但是网关上堆积多了就会给网关乃至整个服务都造成巨大的压力,甚至整个服务宕掉。因此要对一些服务和页面进行有策略的降级,以此缓解服务器资源的的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应,所以需要网关上请求失败需要快速返回给客户端。

添加网关的依赖


        
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix
        

全局路径默认熔断器配置方式

  cloud:
    gateway:
      default-filters:
        # 去掉全部前缀api
        - RewritePath=/api(?/?.*),/${segment}
        - name: Hystrix  # 网关名称(随意只要不重复就行)
          args:
            name: fallbackHystrix  # 降级名称和方法名称一样就行了
            fallbackUri: forward:/fallbackHystrix  # 当发生降级后,降级回调的controller
@RestController
public class FallbackHystrixController {

    @GetMapping("/fallbackHystrix")
    public ResponseEntity fallbackHystrix() {

        System.out.println("发送邮件给管理员,进行处理");


        //503
        ResponseEntity response = new ResponseEntity(HttpStatus.SERVICE_UNAVAILABLE);
        return response;
    }
}

指定路由配置熔断器方式
这样的好处就是能知道是哪里出现了问题

      routes:
        - id: consumer-route # 路由id,可以随意写不影响  一般都是以要代理的服务器名称-route
          uri: lb://consumer # 要访问的服务名称 (集群的时候可以防止宕机)
          #我们请求http://consumer/xxxx 会被拦截
          predicates: #允许的路由地址,要算上过滤器(filters)
            - Path=/api/user/**
          filters:
            - name: Hystrix  # 网关(固定)
              args:
                name: consumerFallbackHystrix  # 降级名称
                fallbackUri: forward:/consumerFallbackHystrix  # 当发生降级后,降级回调的controller
@RestController
public class FallbackController {

    @GetMapping("/consumerFallbackHystrix")
    public ResponseEntity consumerFallbackHystrix() {
        System.out.println(" consumer服务出问题了,发送邮件给管理员,进行处理");
        //503
        ResponseEntity response = new ResponseEntity(HttpStatus.SERVICE_UNAVAILABLE);
        return response;
    }
}
Gateway+Nginx进行高可用

基本上微服务到Gateway这一层,就无法在通过Ribbon进行负载了,因为这里已经是用户访问的最开始的入口了那么如果大量的请求都去访问一台Gateway肯定是扛不住的,比如双十一这种大量并发请求的场景世界上是没有这么高性能的单机服务的,解决办法通过负载均衡器Nginx进行代理,他是安装在服务器上的,来看下面一张部署图:

我么这里就不详细的介绍nginx具体的使用了,因为篇幅有点长,我们会专门拿一篇文章来讲解nginx和高可用部署的,下面就简单的使用Nginx进行负载多台Gateway,我们在创建2台Gateway

gateway:10010 ,gateway:10011 ,gateway:10012

我们可以自行安装Windows的Nginx然后在nginx.conf中进行配置

	upstream gateway-server {
      server 127.0.0.1:10010;
      server 127.0.0.1:10011;
      server 127.0.0.1:10012;
    }
	 server {
		listen       20202;
		server_name  localhost;
		  location / {
			proxy_pass http://gateway-server/;
		  }
	 }

然后重启nginx,进行访问http://localhost:20202/api/user/getUserAll

注意事项:

  1. 配置前需要检查listen的端口是否被占了,不然是访问不通的
  2. 从新加载配置文件nginx -s reload

小提示: 以上架构就没问题了吗? 当然不是,可以看到Nginx现在是瓶颈了,而Nginx本身并没有能力支持集群,最多只能做主从,那么如何解决呢?
我所知道的就3种:

  1. 网络层进行负载(DNS)
  2. 硬件(F5等)来进行负载 ,一些大厂用F5的还是比较多的而小厂一般都用不起太贵了
  3. 第三方平台进行流量代理转发(收费不高,小企业是能接受的)

我推荐几个大厂的负载均衡器价格还是能接受的

阿里云SLB

腾讯云CLB

华为云ELB

点赞 -收藏-关注-便于以后复习和收到最新内容
有其他问题在评论区讨论-或者私信我-收到会在第一时间回复
如有侵权,请私信联系我
感谢,配合,希望我的努力对你有帮助^_^

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/893175.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号