服务网关zuul

	我们通过Ribbon或者Feign实现微服务之间的调用和负载均衡,那么我们各种微服务之间又应该如何提供给外部应用使用呢?
	因为是Rest API接口,所以外部客户端直接调用微服务是没有问题的,但是由于种种原因,这并不是一个很好的的选择。
	让客户端直接与各个微服务进行通信,会产生一下几个问题:
	-	客户端会多次请求不同的微服务,增加客户端的复杂性。
	- 存在跨域请求,在一定场景下处理变得相对比较复杂
	- 实现认证复杂,每个微服务需要独立认证
	- 难以重构,项目迭代可能会导致微服务重新划分,如果客户端直接与微服务通信,那么重构将很难实现,
	- 如果某些微服务使用了防火墙或者浏览器不友好的协议,直接访问存在一定的困难。
	那么我们该怎么解决呢?
	答案就是服务网关
	使用服务网关存在一下几个优点:
	- 易于监控, 可以在微服务网关收集监控数据并推送到外部应用进行分析
	- 易于认证, 可以在服务网关上进行认证,然后转发到微服务, 无需再每个微服务上进行认证。
	- 客户端只跟服务网关打交道,减少了客户端与各个微服务之间的交互次数。
	- 多渠道支持, 可以根据不同客户端(Web端, 移动端, 桌面端登)提供不同的API服务网关。

Spring Cloud Zuul

服务网关是微服务架构中不可或缺的部分,在通过服务网关统一向外部系统提供REST API接口的过程中, 除了具备服务路由,负载均衡功能之外, 它还具备权限控制功能。
Spring Cloud Netflix中的Zuul就担任了这样的一个角色, 为微服务的构建提供前门保护的作用, 同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面, 使得服务集群主体能够具备更高的复用性和可测试性。
在Spring Cloud 体系中, Spring Cloud zuul封装了zuul组件, 作为一个API网关, 负责提供负载均衡, 反向代理和权限认证。

Zuul的工作机制

  1. 过滤器机制
    zuul的核心是一系列的filters,其作用类似于Servlet框架中的Filter,Zuul把客户端请求路由到业务处理逻辑的过程中, 这些filter在路由的特定时期参与了一些过滤处理, 比如实现鉴权, 流量转发, 请求统计登功能
  2. 过滤器的生命周期
    FIlter的生命周期有4个,分别是“PRE”,“ROUTING”, “POST”, “ERROR”,
    基于Zuul的这些过滤器可以实现各种丰富的功能, 而这些过滤器类型则对应于请求的典型生命周期:
  • PRE:这种过滤器在请求被路由之前调用, 我们可以使用这种路由器实现身份验证, 在集群中选择请求的微服务名记录调试信息登。
  • ROUTINE:这种过滤器将请求路由到微服务, 这种过滤器用于构建发送给微服务的请求, 并使用Apache HttpClient或者Netflix Ribbon请求微服务。
  • POST: 这种过滤器在路由到微服务以后执行, 这种过滤器可以来为响应添加相应标准的Http Header:统计收集信息和指标, 将响应从微服务发送给客户端。
  • ERROR:在其他阶段错误时执行的过滤器
    3. 禁止指定的Filter
    可以在application.yml中配置需要禁用的Filter,格式为Zuul...disable=true
    另外自定义filter要继承ZuulFilter,并实现ZuulFilter中的抽象方法。

实现案例

1.  新建gateway-server作为服务网关
2. 添加依赖
添加consul,zuul以及相关依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <!--集成注册中心依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!--服务配置中心-->
        <!--监控中心-->
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-client</artifactId>
            <version>${spring-boot-admin.version}</version>
        </dependency>
        <!--集成健康检查-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  1. 启动类
    为启动类添加@EnableZuulProxy注解, 开启服务网关支持
//开启服务网关支持
@EnableZuulProxy

@SpringBootApplication
public class GatewayServerApplication {

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

}

  1. 配置文件
    配置启动端口为8204,注册服务到注册中心, 配置Zuul转发规则, 这里配置可以访问任何微服务的接口
server:
  port: 8204
spring:
  application:
    name: gateway-server
  cloud:
    consul:
      host: 172.17.0.1 #注册源
      port: 8500 #注册端口
      discovery:
        service-name: ${spring.application.name} #注册到Consul的服务名称
        health-check-url: http://172.17.0.1:8204/actuator/health
        hostname: 172.17.0.1

  boot:
    admin:
      client:
        url: "http://172.17.0.1:8205"

management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: '*'


zuul:
  sensitive-headers: #敏感头部,设置为空,防止截获Authorization
  host:
    connect-timeout-millis: 20000
    socket-timeout-millis: 20000

#遵循默认路由规则:http://ZUUL_HOST:ZUUL_PORT/微服务注册中心serviceId/**




  1. 上传到服务器测试
    DockerFile
FROM java:8
MAINTAINER lidengyin
ARG JAR_FILE
ADD ${JAR_FILE} gateway-server.jar
ADD ./simsun.ttc /usr/share/fonts
EXPOSE 8204
ENTRYPOINT ["java","-jar","gateway-server.jar"]


docker-compose.yml

version: '3'
services:
  micro-gateway-server:
    image: 172.18.0.1:5000/gateway-server:0.0.1-SNAPSHOT
    restart: on-failure
    ports:
    - 8204:8204
  1. “com.netflix.zuul.exception.ZuulException: Hystrix Readed time out”"
    因为默认的连接超时时间比较小,但是在进行一些大的查询的时候依旧会链接超时,多试几次却可以了
zuul:
  sensitive-headers: #敏感头部,设置为空,防止截获Authorization
  host:
    connect-timeout-millis: 60000
    socket-timeout-millis: 60000

7. 默认路由规则
由于如果后端的微服务特别多, 每一个这样的配置很麻烦, Spring Cloud Zuul做了默认的设置, 默认情况下, Zuul会代理所有注册到注册中心的微服务, 并且Zuul的默认路由规则如下:

http://ZUUL_HOST:ZUUL_PORT/微服务在注册中心的serviceId/**

会被转发到serviceId对应的微服务。如果遵循默认路由规则就没有什么需要配置的了。
8. 路由熔断
 Zuul作为Netfilx组件, 可以与Ribbon, Eureka和Hystrix登组件结合, 实现负载均衡。熔断器的功能。 默认情况下,Zuul与Ribbon登组件相互结合,实现负载均衡。实现负载均衡需要时先FallBackProvider接口, 实现该接口的两个方法:一个是getRoute(), 用于指定熔断器功能需要用到那些路由服务;另一个方法就是fallbackResponse()接口, 为进入熔断器功能时执行的逻辑。
 创建MyFallBackProvider类, getRoute()方法返回"*",用于针对所有路由服务添加熔断器功能。getBody()方法返回发送熔断时的反馈信息, 这里在发送熔断时返回信息“Sorry, the service is unavaliable now”;


public class MyFallbackProvider implements FallbackProvider {
    @Override
    /**
     * 指定熔断器功能对那些路由起作用,*为匹配所有为服务
     */
    public String getRoute() {
        return "*";
    }

    /**
     * 降级服务
     * @param route
     * @param cause
     * @return
     */
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        System.out.println("route:"+route);
        System.out.println("exception:"+cause.getMessage());
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 200;
            }

            @Override
            public String getStatusText() throws IOException {
                return "ok";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("sorry, the service is unavailable now.".getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.setContentType(MediaType.APPLICATION_JSON);
                return httpHeaders;
            }
        };
    }
}

### 路由熔断

{
  "timestamp": "2020-03-23T01:42:00.207+0000",
  "status": 504,
  "error": "Gateway Timeout",
  "message": "com.netflix.zuul.exception.ZuulException: Hystrix Readed time out"
}
can't parse JSON.  Raw result:

sorry, the service is unavailable now.
micro-gateway-server_1  | route:hcnet-website-1
micro-gateway-server_1  | exception:null
micro-gateway-server_1  | route:hcnet-website-1
micro-gateway-server_1  | exception:null
micro-gateway-server_1  | route:hcnet-website-1
micro-gateway-server_1  | exception:null
micro-gateway-server_1  | route:hcnet-website-1
micro-gateway-server_1  | exception:null
micro-gateway-server_1  | route:hcnet-website-1
micro-gateway-server_1  | exception:null

"class java.util.Collections$SingletonMap is not a type supported by this en

关掉zuul依旧是这个报错
并且生产者没有任何反映,应该是消费者与zuul中的错误。

    @Configuration
    class MultipartSupportConfig {
        @Bean
        public Encoder feignFormEncoder() {
            return new SpringFormEncoder();
        }
    }

我想到解决图片流传输的时候,设置过这个feign传输文件设置,注释掉试一试
结果,图片流依旧可以,但是依旧包这个错

{
  "timestamp": "2020-03-23T03:44:58.534+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "Type definition error: [simple type, class java.io.FileDescriptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.Collections$SingletonMap[\"uploadFile\"]->org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile[\"inputStream\"]->java.io.FileInputStream[\"fd\"])",
  "path": "/feign/upload/apk"
}

这个错

  "message": "class java.util.Collections$SingletonMap is not a type supported by this encoder.",

最后又回到了这个问题

@RequestMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)

我忘记加consumer

"Incomplete output stream executing POST http://hcnet-website-1/upload/apk

然后就是上面的问题

 ***************************
micro-micro-consumer_1  | APPLICATION FAILED TO START
micro-micro-consumer_1  | ***************************
micro-micro-consumer_1  | 
micro-micro-consumer_1  | Description:
micro-micro-consumer_1  | 
micro-micro-consumer_1  | An attempt was made to call a method that does not exist. The attempt was made from the following location:
micro-micro-consumer_1  | 
micro-micro-consumer_1  |     org.springframework.cloud.openfeign.support.SpringMvcContract.processAnnotationOnClass(SpringMvcContract.java:179)
micro-micro-consumer_1  | 
micro-micro-consumer_1  | The following method did not exist:
micro-micro-consumer_1  | 
micro-micro-consumer_1  |     feign.RequestTemplate.uri(Ljava/lang/String;)Lfeign/RequestTemplate;
micro-micro-consumer_1  | 
micro-micro-consumer_1  | The method's class, feign.RequestTemplate, is available from the following locations:
micro-micro-consumer_1  | 
micro-micro-consumer_1  |     jar:file:/micro-consumer.jar!/BOOT-INF/lib/feign-core-8.17.0.jar!/feign/RequestTemplate.class
micro-micro-consumer_1  |     jar:file:/micro-consumer.jar!/BOOT-INF/lib/feign-core-10.4.0.jar!/feign/RequestTemplate.class
micro-micro-consumer_1  | 
micro-micro-consumer_1  | It was loaded from the following location:
micro-micro-consumer_1  | 
micro-micro-consumer_1  |     jar:file:/micro-consumer.jar!/BOOT-INF/lib/feign-core-8.17.0.jar!/
micro-micro-consumer_1  | 
micro-micro-consumer_1  | 
micro-micro-consumer_1  | Action:
micro-micro-consumer_1  | 
micro-micro-consumer_1  | Correct the classpath of your application so that it contains a single, compatible version of feign.RequestTemplate

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值