导读

我们知道在基于Spring Cloud的微服务体系中,各个微服务除了在内部提供服务外,有些服务接口还需要直接提供给客户端,如Andirod、IOS、H5等等。

而一个很尴尬的境地是,如果直接将提供外部接口的微服务暴露给公网,那么意味着为了增强这个微服务的安全性,需要做很多额外的安全性措施,如报文数字签名、加密等;而大部分场景下,微服务本身又是提供给内部其他微服务调用的,即便所有的微服务都会不同程度地直接面向App客户端提供公网服务,那么为了这确保这些微服务的安全性,涉及的微服务也都需要实现接口的安全性,这样不仅会造成重复开发,也会增加微服务体系的复杂性。所以,我们通常会在微服务体系的外部边界架设一个网关服务,俗称Gateway

Gateway这个服务本身不做任何具体的业务逻辑,业务逻辑还是由相应地微服务去实现。因为在微服务开发中,为了简化内部服务之间调用的繁琐程度,大部分实践是不会在微服务内部设防,如微服务本身是不会做报文层面的签名、加密。而在面向外部提供服务时,则由Gateway服务进行统一的安全认证,认证通过后才会把请求路由到具体的微服务

在这种模式下,微服务之间的调用因为都在内部网络,而不直接向外暴露服务接口及IP,所以微服务的安全问题都依赖于内部网络安全。(PS:如果网络被攻破,那么微服务就会直接暴露在攻击者面前,此时调用微服务的接口是可以直接影响业务的,如进行盗刷等,这个问题我们在下一篇文章中讨论!)

当然Gateway除了支持做简单的安全认证,如会话认证外,还具有服务限流,接口监控数据统一上报等其他功能和用途。在基于Spring Cloud的微服务架构体系中,目前提供了两套方案供我们实现Gateway,分别是Netflix的Zuul以及Spring Cloud自身提供的 Spring Cloud Gateway(构建在Spring 5以及Spring Boot 2.0基础之上)。本篇文章的主要内容是基于Zuul来介绍Api Gateway的搭建。

GateWay的位置

在我们具体分析基于Zuul的Gateway实现原理之前,我们先从整体架构上来了解下Gateway在整体微服务体系中所处的位置吧,这样会有利于我们更深刻的理解Gateway在微服务架构体系中的作用。如下图所示:

Gateway是一个处于内部微服务与外部公网请求之间的衔接性服务,它需要通过域名接收到用户客户端通过公网发出的服务请求,然后再路由至内部对应的微服务。因此Gateway本身既处于服务注册中心的管理之下,如注册到Consul,通过Consul来获取其他微服务的地址列表,并进行请求路由转发;又需要在被外部访问的过程中,被诸如Nginx这样的反向代理服务器进行服务代理,从而实现Gateway的负载均衡及高可用。

这里的一个技术细节是,Gateway大部分情况下是通过容器动态进行部署的,这一点与其他Spring Cloud微服务一样是扁平的,但是又因为网关服务的特殊性,其IP端口需要被Nginx识别从而进行反向代理及负载均衡。这里的问题是Nginx如何能够从茫茫的微服务中识别到那些是需要被外部访问,从而进行反向代理的呢?

毕竟如果将Gateway直接部署到固定的IP及端口机器的话,会失去一定的弹性,从架构层面来说会有些蹩脚。作者之前所在的公司是通过将Gateway服务打tag,如需要被外部访问的Gateway服务将其tag标签打成api,这样就可以借助一些工具如consul-template的方式,就可以做一些自动识别的流程来自动进行反向代理了!如果你有更好的实现方式,也欢迎给我留言哦!

到这里,相信你应该对Gateway在微服务架构体系中的位置有一个足够清晰地认识和了解了,下面我们就将重点介绍Zuul的功能与实现原理。

Zuul简介

Zuul是Neflix开源的Api Gateway服务器,它本质上是一个Servlet应用,其核心是通过一系列filters的实现来为整个微服务体系提供路由、安全、监控等边界服务。Zuul目前分为两个大版本Zuul1和Zuul2,它们的区别在于Zuul1的IO模型还是BIO的方式,而Zuul2则是使用NIO对Zuul1进行了重构,所以性能上要优于Zuul1。

正因为Zuul1的IO采用的是BIO,所以在Spring Cloud基于Spring Boot2.0的版本中才自己推出了基于NIO模型的Spring Cloud Gateway来取代Zuul,此时虽然Zuul2已经发布,但是因为发布的时间太晚,所以Spring Cloud对其已经不再默认集成了!

因此如果要升级Zuul的版本至Zuul2的话,你需要将Spring Cloud对应的版本升级到基于Spring Boot2.0的版本,并单独引入Zuul2的版本依赖。而在这种情况下,直接选用Spring Cloud Gateway作为网关服务可能会是一个更合适的选择。以下为基于Spring boot2.0的Spring Cloud版本依赖:

<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Finchley.SR3</version>
<relativePath />
</parent>

而考虑到历史项目原因,目前不少基于Spring Cloud的项目还是构建在基于Spring boot1.0的版本之上,所以在本篇文章中对Zuul的分析还是基于Zuul1的版本,这一点请大家知悉!

Zuul原理

在前面我们提到过Zuul本质上是一个Servlet应用,其核心就是通过定义一系列的filters来对用户的请求进行过滤处理,从而实现一些定制化的边缘服务功能如安全认证,打点监控等。类似于Servlet的Filter,只不过Zuul是提供了一个框架,来实现定义不同类型的filter,并对这些filter进行加载、编译、运行。下面我们来看一下Zuul的核心类图:

因为Zuul本身就是一个Servlet应用,而其要做的事情就是拦截所有用户请求来进行过滤,在Zuul框架中ZuulServlet就是这样一个类型,它类似于SpringMvc的DispatcherServlet,所有最终需要路由到微服务的请求,都会由它进行处理。

ZuulServlet中有3个核心的方法,它们分别是:preRoute(),route(), postRoute()。Zuul对所有request的处理逻辑都在这三个方法里面,而这些方法分别对应了Zuul中定义的几种标准过滤器类型:

  • PRE:这种过滤器会在请求被路由之前调用。我们可以利用这种过滤器类型实现身份认证等前置逻辑;

  • ROUTE:这种过滤器将请求路由到微服务,用于构建发送给微服务的请求。这种类型的过滤器Zuul已经帮我们实现,用于实现Gateway到内部微服务调用的路由、负载均衡、限流等功能;

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

  • ERROR:在请求处理阶段发生错误时执行该过滤器;

从代码层面看,以上方法的实际执行则是由具体实现了ZuulFilter接口的过滤器来实现的,这些过滤器会返回自身定义的类型如"pre",这样通过Zuul框架相应的设计就会最终调用到过滤器的对应方法了。(PS:篇幅有限,更细节的实现,需要大家去阅读源码)

Zuul实践示例

使用Zuul搭建一个Gateway非常简单,只需要基于Spring Boot项目,在主类加上注解@EnableZuulProxy即可。如:

@EnableZuulProxy
@SpringBootApplication
@EnableAutoConfiguration(exclude = {RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class, DataSourceAutoConfiguration.class,
MongoAutoConfiguration.class, MongoRepositoriesAutoConfiguration.class})
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}

而在具体定制相应的Filter时只需要实现ZuulFilter接口,确定滤器类型后实现run方法就可以了。

public class LoginFilter extends ZuulFilter {
@Autowired
private GatewayLoginFilterConfig loginFilterConfig; @Override
public String filterType() {
return "pre"; //pre在请求真实url之前做处理
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
...
return null;
}

以上就是本文的基本内容了,希望能够让您能有所收获,欢迎转发+点赞!

参考资料:

https://github.com/Netflix/zuul

https://github.com/Netflix/zuul/wiki

http://www.sohu.com/a/221110905_467759

https://www.jianshu.com/p/af1554553b5c



Spring Cloud微服务中网关服务是如何实现的?(Zuul篇)的更多相关文章

  1. spring cloud学习笔记五 网关服务zuul

    网关服务是指,客户端发送的请求不用直接访问特定的微服务接口,而且是经过网关服务的接口进行交互,网关服务再去到特定的微服务中进行调用.   网关服务的路由功能和Nginx的反向代理一样,所有的服务都先会 ...

  2. Spring Cloud 微服务三: API网关Spring cloud gateway

    前言:前面介绍了一款API网关组件zuul,不过发现spring cloud自己开发了一个新网关gateway,貌似要取代zuul,spring官网上也已经没有zuul的组件了(虽然在仓库中可以更新到 ...

  3. Spring Cloud 微服务二:API网关spring cloud zuul

    前言:本章将继续上一章Spring Cloud微服务,本章主要内容是API 网关,相关代码将延续上一章,如需了解请参考:Spring Cloud 微服务一:Consul注册中心 Spring clou ...

  4. 在eclipse中使用maven构建spring cloud微服务

    使用eclipse中使用maven构建spring cloud微服务,springcloud通过maven构建项目.springcloud项目搭建. 工具/原料   eclipse maven spr ...

  5. Spring Cloud 微服务架构学习笔记与示例

    本文示例基于Spring Boot 1.5.x实现,如对Spring Boot不熟悉,可以先学习我的这一篇:<Spring Boot 1.5.x 基础学习示例>.关于微服务基本概念不了解的 ...

  6. Spring Cloud 微服务

    https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw==&mid=2247486301&idx=2&sn=f6d45860269b61 ...

  7. Spring Cloud 微服务架构的五脏六腑,统统晒一晒!

    Spring Cloud 是一个基于 Spring Boot 实现的微服务框架,它包含了实现微服务架构所需的各种组件. 注:Spring Boot 简单理解就是简化 Spring 项目的搭建.配置.组 ...

  8. 浅谈现公司的Spring Cloud微服务框架

    目录 说在前面 服务注册与发现 服务网关及熔断 配置中心 消息中心.服务链路追踪 小言 说在前面 本文偏小白,大佬慎入,若有错误或者质疑,欢迎留言提问,谢谢,祝大家新年快乐. spring cloud ...

  9. 一张图了解Spring Cloud微服务架构

    Spring Cloud作为当下主流的微服务框架,可以让我们更简单快捷地实现微服务架构.Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟.经得起实际考验的服务框架组合起来 ...

随机推荐

  1. abp 设置默认语言为中文

    abp 设置默认语言为中文 abp的默认语言设置,存放于数据库表AbpSettings中,这样配置可使默认语言为中文: name: Abp.Localization.DefaultLanguageNa ...

  2. LINUX日常操作二

    参见:Linux日常操作一  selinux 开启和关闭 一.查看SELinux状态:1./usr/sbin/sestatus -v      ##如果SELinux status参数为enabled ...

  3. kvm 客户机加载移动硬盘

    1,宿主机安装usbutils yum install usbutils -y 2,插入U盘或者移动硬盘并查看 [root@localhost ~]# lsusb Bus Device : ID 10 ...

  4. 返回上一页 html A标记代码

    <a class="sjad" href="#" onClick="javascript:history.back(-1);"> ...

  5. rsync @ERROR: auth failed on module backup 解决思路及附录rsync常见问题及解决办法

    昨晚小版本上线,使用rsync往服务器上传文件时,client报如下异常: @ERROR: auth failed on module backup rsync error: error starti ...

  6. Golang之路【目录】

    我正在写一套使用Golang全栈开发的教程,名字暂叫“Golang之路”,希望大家多提建议. 目录如下: Golang之路[第一篇]:Golang简介和入门Golang之路[第二篇]:Golang基础 ...

  7. JavaScript RegExp(正则)

    第一种方式是直接通过/正则表达式/写出来,第二种方式是通过new RegExp('正则表达式')创建一个RegExp对象. 两种写法是一样的: var re1 = /ABC\-001/; var re ...

  8. SSM框架集成及配置详解(Maven管理)

    一.pom.xml(依赖管理) <?xml version="1.0" encoding="UTF-8"?> <project xmlns=& ...

  9. mybatis中String参数的传递

    mybatis中String参数的传递 Keywords selectKeywords(@Param("key") String key); 可以在mapper方法的参数钱添加 @ ...

  10. mybatis 中使用oracle merger into

    项目背景:设计到excel导入,数据量也比较大,保证性能的情况下还要考虑到:如果数据中有这条数据的主键,则更新(update),不存在的情况,执行插入(insert). mybatis代码: < ...