博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[菜鸟SpringCloud实战入门]第九章:服务网关Zuul体验
阅读量:5980 次
发布时间:2019-06-20

本文共 5992 字,大约阅读时间需要 19 分钟。

前言

欢迎来到菜鸟SpringCloud实战入门系列(SpringCloudForNoob),该系列通过层层递进的实战视角,来一步步学习和理解SpringCloud。

本系列适合有一定Java以及SpringBoot基础的同学阅读。

每篇文章末尾都附有本文对应的Github源代码,方便同学调试。

Github仓库地址:

菜鸟SpringCloud实战入门系列

你可以通过以下两种途径查看菜鸟SpringCloud实战入门系列

  • 关注我的公众号:Rude3Knife 点击公众号下方:技术推文——SpringCloud

前文回顾:

  • ...更多文章请查看上方:菜鸟SpringCloud入门实战专栏导航页

实战版本

  • SpringBoot:2.0.3.RELEASE
  • SpringCloud:Finchley.RELEASE

-----正文开始-----

[菜鸟SpringCloud实战入门]第九章:服务网关Zuul体验

服务网关 Zuul

Zuul介绍

外部的应用如何来访问内部各种各样的微服务呢?在微服务架构中,后端服务往往不直接开放给调用端,而是通过一个API网关根据请求的url,路由到相应的服务。当添加API网关后,在第三方调用端和服务提供方之间就创建了一面墙,这面墙直接与调用方通信进行权限控制,后将请求均衡分发给后台服务端。

这个API网关便是Spring Cloud Zuul

Zuul提供动态路由,监控,弹性,安全等的边缘服务。Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器。

Zuul与Ribbon以及Eureka配合:

Zuul、Ribbon以及Eureka结合可以实现智能路由和负载均衡的功能;网关将所有服务的API接口统一聚合,统一对外暴露。外界调用API接口时,不需要知道微服务系统中各服务相互调用的复杂性,保护了内部微服务单元的API接口;网关可以做用户身份认证和权限认证,防止非法请求操作API接口;网关可以实现监控功能,实时日志输出,对请求进行记录;网关可以实现流量监控,在高流量的情况下,对服务降级;API接口从内部服务分离出来,方便做测试。

Zuul通过Servlet来实现,通过自定义的ZuulServlet来对请求进行控制。核心是一系列过滤器,可以在Http请求的发起和响应返回期间执行一系列过滤器。Zuul采取了动态读取、编译和运行这些过滤器。过滤器之间不能直接通信,而是通过RequestContext对象来共享数据,每个请求都会创建一个RequestContext对象。

Zuul生命周期如下图。

Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。

Zuul中默认实现的Filter:

图片来自:

在yml中可以禁用指定的Filter:

zuul:	FormBodyWrapperFilter:		pre:			disable: true复制代码

新建Zuul子模块

本章需要用到之前章节的的模块:

  • eureka(eureka):第一章
  • eureka-hi(服务提供者):第二章

我们新建子模块(新建模块如有疑惑请看教程第一章),名为zuul

修改pom.xml:

4.0.0
zuul
0.0.1-SNAPSHOT
zuul
jar
Demo project for Spring Boot
com.pricemonitor
springcloud
0.0.1-SNAPSHOT
org.springframework.cloud
spring-cloud-starter-netflix-zuul
复制代码

在主类中加上@EnableZuulProxy:

@SpringBootApplication@EnableZuulProxypublic class ZuulApplication {    public static void main(String[] args) {        SpringApplication.run(ZuulApplication.class, args);    }}复制代码

修改yml文件:

  • 设置端口为8773
  • 在eureka注册
  • 设置个producer路由,把/producer/映射到service-hi的服务
spring:  application:    name: gateway-service-zuulserver:  port: 8773eureka:  client:    serviceUrl:      defaultZone: http://localhost:8761/eureka/zuul:  routes:    hello:      path: /producer/**      serviceId: service-hi复制代码

单机zuul运行

先后运行eureka,eureka-hi和zuul

使用官网来访问8763上eureka-hi提供的服务:

得到:

说明网关正确转发了请求

zuul服务集群模拟

为了更好的模拟服务集群,我们再新开一个eureka-hi,端口号为8764,只需要修改yml的配置文件,然后重新运行即可。

你会看到来自8763和8764随机提供的服务:

zuul默认路由规则

Zuul其实已经代理所有注册到Eureka Server的微服务,并且Zuul的路由规则如下:http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**会被转发到serviceId对应的微服务。

我们试验一下, :

zuul自定义filter

最上面的简介中我们提到,Zuul中有默认实现的Filter,当然也可以实现自己的自定义Filter,用来完成一些鉴权、流量转发、请求统计等工作。我们来实现一个自定义filter。

我们假设有这样一个场景,因为服务网关应对的是外部的所有请求,为了避免产生安全隐患,我们需要对请求做一定的限制,比如请求中含有Token便让请求继续往下走,如果请求不带Token就直接返回并给出提示。

新建TokenFilter类:

package com.pricemonitor.zuul;import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletRequest;public class TokenFilter extends ZuulFilter {    private final Logger logger = LoggerFactory.getLogger(TokenFilter.class);    @Override    public String filterType() {        // 可以在请求被路由之前调用        return "pre";    }    @Override    public int filterOrder() {        // filter执行顺序,通过数字指定 ,优先级为0,数字越大,优先级越低        return 0;    }    @Override    public boolean shouldFilter() {        // 是否执行该过滤器,此处为true,说明需要过滤        return true;    }    @Override    public Object run() {        RequestContext ctx = RequestContext.getCurrentContext();        HttpServletRequest request = ctx.getRequest();        logger.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString());        String token = request.getParameter("token");        if (StringUtils.isNotBlank(token)) {            ctx.setSendZuulResponse(true); //对请求进行路由            ctx.setResponseStatusCode(200);            ctx.set("isSuccess", true);            return null;        } else {            ctx.setSendZuulResponse(false); //不对其进行路由            ctx.setResponseStatusCode(400);            ctx.setResponseBody("token is empty");            ctx.set("isSuccess", false);            return null;        }    }}复制代码

随后,在启动类注入这个bean

@SpringBootApplication@EnableZuulProxypublic class ZuulApplication {    public static void main(String[] args) {        SpringApplication.run(ZuulApplication.class, args);    }    @Bean    public TokenFilter tokenFilter() {        return new TokenFilter();    }}复制代码

运行eureka注册中心,eureka-hi服务提供者,zuul网关三个子模块。

不带token访问:

带着token访问:

通过上面这例子我们可以看出,我们可以使用“PRE”类型的Filter做很多的验证工作,在实际使用中我们可以结合shiro、oauth2.0等技术去做鉴权、验证。

网关路由熔断

之前我们学过hystrix的熔断,主要针对的是内部服务互相调用的熔断,而zuul的熔断则主要服务于外部接口调用。

注意:Zuul 目前只支持服务级别的熔断,不支持具体到某个URL进行熔断。

实现:主要是通过继承FallbackProvider(之前继承的是ZuulFallbackProvider:默认有两个方法,一个用来指明熔断拦截哪个服务,一个定制返回内容。)

网关路由重试

可以配合Spring Retry,来对暂时不可用的服务进行重试。

注意: 开启重试在某些情况下是有问题的,比如当压力过大,一个实例停止响应时,路由将流量转到另一个实例,很有可能导致最终所有的实例全被压垮。说到底,断路器的其中一个作用就是防止故障或者压力扩散。用了retry,断路器就只有在该服务的所有实例都无法运作的情况下才能起作用。这种时候,断路器的形式更像是提供一种友好的错误信息,或者假装服务正常运行的假象给使用者。

不用retry,仅使用负载均衡和熔断,就必须考虑到是否能够接受单个服务实例关闭和eureka刷新服务列表之间带来的短时间的熔断。如果可以接受,就无需使用retry。

本章代码

参考

-----正文结束-----

菜鸟SpringCloud实战入门专栏全导航:通过以下两种途径查看

  • 关注我的公众号:Rude3Knife 点击公众号下方:技术推文——SpringCloud

关注我

我是蛮三刀把刀,后端开发。主要关注后端开发,数据安全,爬虫等方向。微信:yangzd1102

Github:

个人博客:

  • CSDN:
  • 知乎:
  • 简书:
  • 掘金:

原创博客主要内容

  • Java知识点复习全手册
  • Leetcode算法题解析
  • 剑指offer算法题解析
  • SpringCloud菜鸟入门实战系列
  • SpringBoot菜鸟入门实战系列
  • Python爬虫相关技术文章
  • 后端开发相关技术文章

个人公众号:Rude3Knife

如果文章对你有帮助,不妨收藏起来并转发给您的朋友们~

转载地址:http://lrlox.baihongyu.com/

你可能感兴趣的文章
leetcode-205-Isomorphic Strings
查看>>
Ubuntu下Apache2+Tomact7安装、配置及整合
查看>>
c++重载与覆写
查看>>
使用 JavaScript 将网站后台的数据变化实时更新到前端-【知乎总结】
查看>>
Java基础之j简析avax.swing.JOptionPane(一)showMessageDialog
查看>>
信息资源管理的标准与法规
查看>>
二进制、十进制、N进制 ○| ̄|_
查看>>
Android 数据库管理— — —创建数据库
查看>>
Jquery 校验文本框只能输入负数、小数、整数
查看>>
关于固态硬盘SSD的4K对齐
查看>>
fanc委托在项目中使用
查看>>
C# FileStream 按大小分段读取文本内容
查看>>
WGS84,GCJ02, BD09坐标转换
查看>>
如何给网页标题栏上添加图标(favicon.ico)(转)
查看>>
[转载] Linux架构
查看>>
mysql授权
查看>>
Ubuntu下SSH设置
查看>>
IOS-小项目( 网络部分 简单实现)
查看>>
C/C++基本数据类型
查看>>
C++第八章习题
查看>>