前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Cloud微服务中网关服务是如何实现的?(Zuul篇)

Spring Cloud微服务中网关服务是如何实现的?(Zuul篇)

作者头像
用户5927304
发布2019-07-31 16:26:42
1.3K0
发布2019-07-31 16:26:42
举报
文章被收录于专栏:无敌码农无敌码农

导读

我们知道在基于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版本依赖:

代码语言:javascript
复制
<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即可。如:

代码语言:javascript
复制
@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方法就可以了。

代码语言:javascript
复制
public class LoginFilter extends ZuulFilter {
    @Autowired
    private GatewayLoginFilterConfig loginFilterConfig;

    @Override
    public String filterType() {
        return "pre";   //pre在请求真实url之前做处理
    }
    @Override
    public int filterOrder() {
        return ;
    }
    @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

—————END—————

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 无敌码农 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档