Spring Cloud微服务中网关服务是如何实现的?(Zuul篇)
导读
我们知道在基于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篇)的更多相关文章
- spring cloud学习笔记五 网关服务zuul
网关服务是指,客户端发送的请求不用直接访问特定的微服务接口,而且是经过网关服务的接口进行交互,网关服务再去到特定的微服务中进行调用. 网关服务的路由功能和Nginx的反向代理一样,所有的服务都先会 ...
- Spring Cloud 微服务三: API网关Spring cloud gateway
前言:前面介绍了一款API网关组件zuul,不过发现spring cloud自己开发了一个新网关gateway,貌似要取代zuul,spring官网上也已经没有zuul的组件了(虽然在仓库中可以更新到 ...
- Spring Cloud 微服务二:API网关spring cloud zuul
前言:本章将继续上一章Spring Cloud微服务,本章主要内容是API 网关,相关代码将延续上一章,如需了解请参考:Spring Cloud 微服务一:Consul注册中心 Spring clou ...
- 在eclipse中使用maven构建spring cloud微服务
使用eclipse中使用maven构建spring cloud微服务,springcloud通过maven构建项目.springcloud项目搭建. 工具/原料 eclipse maven spr ...
- Spring Cloud 微服务架构学习笔记与示例
本文示例基于Spring Boot 1.5.x实现,如对Spring Boot不熟悉,可以先学习我的这一篇:<Spring Boot 1.5.x 基础学习示例>.关于微服务基本概念不了解的 ...
- Spring Cloud 微服务
https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw==&mid=2247486301&idx=2&sn=f6d45860269b61 ...
- Spring Cloud 微服务架构的五脏六腑,统统晒一晒!
Spring Cloud 是一个基于 Spring Boot 实现的微服务框架,它包含了实现微服务架构所需的各种组件. 注:Spring Boot 简单理解就是简化 Spring 项目的搭建.配置.组 ...
- 浅谈现公司的Spring Cloud微服务框架
目录 说在前面 服务注册与发现 服务网关及熔断 配置中心 消息中心.服务链路追踪 小言 说在前面 本文偏小白,大佬慎入,若有错误或者质疑,欢迎留言提问,谢谢,祝大家新年快乐. spring cloud ...
- 一张图了解Spring Cloud微服务架构
Spring Cloud作为当下主流的微服务框架,可以让我们更简单快捷地实现微服务架构.Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟.经得起实际考验的服务框架组合起来 ...
随机推荐
- 当多线程并发遇到Actor
https://mp.weixin.qq.com/s/mzZatZ10Rh19IEgQvbhGUg
- ABP 依赖注入
1.ABP自动注入 //IapplicationService注入方式暴露接 //ITransientDependency 不会暴露接口 ITransientDependency和ISingleton ...
- HttpWebRequest 自定义header,Post发送请求,请求形式是json,坑爹的代码
public static string PostMoths(string url, LoginDTO obj_model, Dictionary<string, string> dic ...
- 【mysql】:mysql性能优化总结
一.Mysql引擎概述 1.MyISAM存储引擎 MyISAM表是独立于操作系统的,这说明可以轻松地将其从Windows服务器移植到Linux服务器:每当我们建立一个MyISAM引擎的表时,就会在本地 ...
- C++ 使用命名规范
刚开始正式学习C++, 之前写了一个C++ 的小程序,但是并没有注意命名规范之类的.这一次重写一个类似的程序,再加上这几天学习 c++Prime(发现好喜欢这本书.虽然看的很慢,每一小节都感是满满的干 ...
- 4yue 22
1 # 1 . 进程 线程 协程 之间的相同点和不同点 #相同点:都能帮助我们实现并发操作,规避IO时间,提高执行效率 #进程:内存隔离 操作系统级别 可以利用多核(高计算) 计算机中资源分配的最小单 ...
- js常用通用方法
验证身份证详细方法 function isCardNo(pId) { var arrVerifyCode = [1, 0, "x", 9, 8, 7, 6, 5, 4, 3, 2] ...
- Problem creating zip: Execution exce ption (and the archive is probably corrupt but I could not delete it): Java heap space -> [Help 1]
今天mvn编译的时候报错: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.5.5:s ...
- 安装完Ubuntu后通过shell脚本一键安装软件
安装完Ubuntu后通过shell脚本一键安装软件 以下代码中#是单行注释 :<<! ! 是多行注释. 运行的时候需要把多行注释去掉. 比如把以下代码保存为install.sh, 那么在终 ...
- 携带cookie的跨域访问
携带cookie的跨域解决方案 有的时候访问后台的请求需要携带cookie以供后台分析,比如jQuery的ajax请求: $.ajax({ url: a_cross_domain_url, xhrFi ...