网关

网关的职责:网关 = 路由器(基础职能) + 过滤器(可选职能)

对于路由:如果需要对流量的特征进行分析,那必须是要在七层操作,否则直接在四层直接进行流量转发就可以了

不同的网关采用的网络IO模型不同 性能表现也不同

网关的可用性考虑:

  1. 网关应该轻量 达到功能性与可用性的平衡 职责过多是很危险的
  2. 选择成熟的网关产品
  3. 在网关之间加上负载均衡器或者路由器 以便让网关也能进行扩展

主要功能点

流量网关

业务网关

网关部署架构

202002221510

BFF( Backend for frontend)网关

20201119152838

Spring Cloud Zuul

202037144831

使用

<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>
server.port=8010spring.application.name=gateway# 这里的配置表示,访问/bd/** 直接重定向到http://baidu.com/**zuul.routes.baidu.path=/bd/**zuul.routes.baidu.url=http://baidu.com/eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
@EnableZuulProxy

默认路由规则

http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**

比如访问http://localhost:8010/producer/

则gateway就会把请求转发到producer服务上面去

简化路由配置

zuul:  routes:    user-service: /user-service/** # 这里是映射路径

Zuul的核心

自定义Filter

@Componentpublic class MyFilter extends ZuulFilter {    @Override    public String filterType() {return FilterConstants.PRE_TYPE;}    @Override    public int filterOrder() {return FilterConstants.PRE_DECORATION_FILTER_ORDER;}    @Override    public boolean shouldFilter() {return true;}    @Override    public Object run() throws ZuulException {        RequestContext ctx = RequestContext.getCurrentContext();        HttpServletRequest request = ctx.getRequest();        String token = request.getParameter("token");        if ("my".equals(token)){            ctx.setSendZuulResponse(true);            ctx.setResponseStatusCode(200);            ctx.set("isSuccess",true);        }else{            ctx.setSendZuulResponse(false);            ctx.setResponseStatusCode(400);            ctx.setResponseBody("error token");            ctx.set("isSuccess",false);        }        return null;    }}

这样当通过网关访问服务时,不符合条件的请求将会被过滤掉

整合配置中心

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-config</artifactId></dependency><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-actuator</artifactId></dependency>
@RefreshScope@ConfigurationProperties("zuul")public ZuulProperties zuulProperties() {    return new ZuulProperties();}

进行跨域配置

@Configurationpublic class CorsConfig {    @Bean    public CorsFilter corsFilter() {        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();        final CorsConfiguration config = new CorsConfiguration();        config.setAllowCredentials(true); // 允许cookies跨域        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部        config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了        config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许        source.registerCorsConfiguration("/**", config);        return new CorsFilter(source);    }}

忽略

# 忽略该服务zuul.ignored-services: upload-servie 

路由熔断

@Componentpublic class MyFallback implements FallbackProvider {    @Override    public String getRoute() {        return "producer";    }    @Override    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {        cause.printStackTrace();        return new ClientHttpResponse() {            @Override            public HttpStatus getStatusCode() throws IOException {                return HttpStatus.valueOf(500);            }            @Override            public int getRawStatusCode() throws IOException {                return 500;            }            @Override            public String getStatusText() throws IOException {                return "SERVER ERROR";            }            @Override            public void close() {            }            @Override            public InputStream getBody() throws IOException {                return new ByteArrayInputStream("service is unavailable".getBytes());            }            @Override            public HttpHeaders getHeaders() {                HttpHeaders headers = new HttpHeaders();                headers.setContentType(MediaType.TEXT_PLAIN);                return headers;            }        };    }}

当producer挂掉时,将会返回相关信息

路由重试

<dependency>    <groupId>org.springframework.retry</groupId>    <artifactId>spring-retry</artifactId></dependency>
#是否开启重试功能zuul.retryable=true#对当前服务的重试次数ribbon.MaxAutoRetries=2#切换相同Server的次数ribbon.MaxAutoRetriesNextServer=0

当相同的服务挂掉一部分后,如果多次请求不成功,则接下来的请求则会转发到其他服务上

也就是说,自动的寻找到正确响应的服务上去.错误的实例被抛弃

zuul高可用

upstream gateway {        server 127.0.0.1:8000;        server 127.0.0.1:7000;}server {        listen 6060;        location / {                proxy_pass http://gateway;                proxy_connect_timeout 1s;                proxy_send_timeout 1s;                proxy_read_timeout 1s;        }}

Spring Cloud Gateway

批注 2020-04-07 130836

配置

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-gateway</artifactId></dependency>

定义路由规则

@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder builder) {    return builder.routes()            .route("path_route", r -> r.path("/hi")                    .uri("http://localhost:8503"))            .build();}
builder.routes()       .route("path_route", r -> r.before(ZonedDateTime.now())               .uri("http://localhost:8503"))       .build();
builder.routes()       .route("path_route", r -> r.cookie("key","value")               .uri("http://localhost:8503"))       .build();

服务化

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
server:  port: 8888spring:  application:    name: gateway  cloud:    gateway:      discovery:        locator:          enabled: trueeureka:  client:    service-url:      defaultZone: http://localhost:8001/eureka/logging:  level:    org.springframework.cloud.gateway: debug

http://网关/服务serviceId/具体的url

Filter

这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等

这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等

简单过滤器实例

server:  port: 8888spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: add_request_parameter_route        uri: http://localhost:9003        filters:        - AddRequestParameter=name, my        predicates:          - Method=GET      discovery:        locator:          enabled: trueeureka:  client:    service-url:      defaultZone: http://localhost:8001/eureka/logging:  level:    org.springframework.cloud.gateway: debug

在上面的配置中,添加了一个路由过滤规则:对9003端口的get请求添加一个请求参数name:my

改成uri: lb://producer 则路由配置只会对producer服务生效

修改路径的过滤器

- id: nameRoot  uri: lb://producer  predicates:    - Path=/name/**  filters:    - StripPrefix=2

如果访问/name/my/hello,网关就会将路径修改为/hello

- id: prefixpath_route  uri: lb://producer  predicates:  - Path=*  filters:  - PrefixPath=/mypath

自动给URL加上mypath前缀

自定义Filter

@Componentpublic class TokenFilter implements GlobalFilter {    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {        var token = exchange.getRequest().getQueryParams().get("token");        if (!CollectionUtils.isEmpty(token)){            return chain.filter(exchange);        }        ServerHttpResponse response = exchange.getResponse();        response.setStatusCode(HttpStatus.FORBIDDEN);        return response.writeWith(                Mono.just(                        response.bufferFactory().wrap("token is null".getBytes())                )        );    }}

限速路由器

熔断路由器

<dependency>    <groupId>org.springframework.cloud</groupId>    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>
- id: hystrix_route  uri: http://localhost:9001  predicates:    - Path=/*  filters:    - Hystrix=myCommandName

重试路由器

比较

网关限流鉴权监控易用性可维护性成熟度
Spring Cloud Gateway可以通过IP,用户,集群限流,提供了相应的接口进行扩展 ,gateway不依赖servlet api,所以性能更强
gateway的转发是在tcp层普通鉴权、auth2.0Gateway Metrics Filter简单易用spring系列可扩展强,易配置 可维护性好spring社区成熟,但gateway资源较少
Zuul2可以通过配置文件配置集群限流和单服务器限流亦可通过filter实现限流扩展filter中实现filter中实现参考资料较少可维护性较差开源不久,资料少
OpenResty需要lua开发需要lua开发需要开发简单易用,但是需要进行的lua开发很多可维护性较差,将来需要维护大量lua脚本很成熟资料很多
Kong根据秒,分,时,天,月,年,根据用户进行限流。可在原码的基础上进行开发普通鉴权,Key Auth鉴权,HMAC,auth2.0可上报datadog,记录请求数量,请求数据量,应答数据量,接收于发送的时间间隔,状态码数量,kong内运行时间简单易用,api转发通过管理员接口配置,开发需要lua脚本"可维护性较差,将来需要维护大量lua库相对成熟,用户问题汇总,社区,插件开源

不同技术栈网关选型