在日常工作中,不同的场合下,我们可能都会听说网关的概念,当然通常是指业务网关(API网关),负责API的输入和输出。有了业务网关之后,各个API服务提供者可以专注于自己的业务逻辑处理,而API网关更专注于安全、流量、路由等问题。从功能层次我们又会联想到一个概念——代理。网关与代理的区别:代理本质是数据的透传,协议不会发生变化;网关在数据透传的背景下,还会涉及协议的转换,比如从HTTP到Dubbo。
那么作为一名架构师,我们该如何选型“业务网关”呢?我们自己先要学会做技术选型,自己预期有一个技术成本的预判,比如我推荐使用Spring Cloud Alibaba+Spring Gateway,就是我自己作为一个架构师的技术预判。
Zuul
Zuul是Netflix开源的微服务网关,可以和Eureka、Ribbon、Hystrix等组件配合使用,Spring Cloud对Zuul进行了整合与增强,Zuul总共有两个大的版本:Zuul1.0和Zuul2.0,目前最新的版本为v2.2.0,Zuul1.0和Zuul2.0版本之间功能差异性非常大。
Netflix的Zuul包含如下功能:
- 身份认证与安全: 识别每个资源的验证要求,并拒绝那些与要求不符的请求;
- 审查与监控:在边缘位置追踪有意义的数据和统计结果;
- 动态路由: 动态地将请求路由到不同的后端集群;
- 压力测试 : 逐渐增加指向集群的流量,以了解性能;
- 负载分配: 为每一种负载类型分配对应容量 ,并弃用超出限定值的请求 ;
- 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群;
- 多区域弹性: 跨越AWS Region进行请求路由,旨在实现ELB(Elastic Load Balancing)使用的多样化和 以及让系统的边缘更贴近系统的使用者。
以上介绍来自Zuul官方文档,但其实开源版本的Zuul以上功能一个都没有——开源的Zuul只是几个Jar包而已,以上能力指的应该是Netflix官方自用的Zuul的能力;Netflix自用的Zuul能力是比较强大的,可使用Groovy编写过滤器,并且可动态加载/卸载、修改规则,而且使用Cassandra作为数据库,然而开源版本这些一个都没有;Spring Cloud中,Zuul绝大部分功能都是Spring Cloud团队为Zuul开发的;所以Zuul 2.x的开源进度延后一年,Spring Cloud团队开发了自己的SCG,并宣布Spring Cloud不打算支持Zuul 2.x,你还觉得意外吗?看到这里,很多人可能没有动力学习Zuul了,个人认为还是可以了解一下的,后面讲到SCG时,你会发现很多设计理念是相通的。
既然说到了Spring Cloud对Zuul的封装,那么我们来简单的分析下Spring Cloud与Zuul的关系。Spring Cloud通过Spring Cloud Netflix 1.X来封装Zuul1.0,1.X的最后一个版本是v1.4.7.RELEASE,对应的Zuul版本是1.3.1。Spring Cloud Netflix从3.X开始就没有封装Zuul网关,包括Zuul1.0和Zuul2.0,也就是说开发者想要通过Spring Cloud来复用Zuul,只能使用Zuul1.0,暂时不能复用Zuul2.0。
Zuul目前在github上的star数为10.2k,fork数为2k,也就是说还是有很多开源爱好者会基于Zuul来定制化业务网关。
除了开源的Spring Cloud定制化Zuul,开源微服务框架jhipster也参与了定制,并集成到它的生态中。Jhipster主要包含generator-jhipster和jhipster-registry,前者star数微17.7k,fork数为3.5k,后者star数为604,fork为607。
Zuul1.0整体架构设计如图所示。
Zuul2.0整体架构设计如图所示。
Spring Cloud Gateway
SCG是基于Spring Framework 5.0和Spring Boot 2.0构建的API网关,提供路由等功能。其旨在提供一种简单而有效的方法路由到API,并为它们提供跨领域的关注点,例如:安全性、监视/指标和弹性。
主要特性:
- J ava8
- Spring Framework5
- Spring Boot2
- 动态路由
- Spring Handler Mapping 内置的路由匹配
- HTTP 请求的路由匹配(路径、方法、 Hea der 、主机等)
- 过滤器限定范围以匹配路由
- 过滤器可以修改下游 HTTP 请求和 HTTP 响应(添加、删除 Header 、添加 / 删除参数、重写路径、设置路径等)
- API或配置驱动
- 支持Spring Cloud Discovery Client配置路由
SCG的专业术语包括:
- 路由:它是基本构建模块,主要包含ID、URI、断言集合以及过滤器集合,如果能够匹配断言就会执行路由。
- 断言: 主要是指Java8的函数式断言,输入类型是Spring Framework的ServerWebExchange,基于断言可以匹配基于headers或者parameters的http请求。
- 过滤器: 它是通过特殊的工厂方法构造的基于Spring Framework GatewayFilter的实现,通过过滤器开发者可以在http请求下行之前修改请求响应参数,在请求响应返回之后可以修改响应的结果。
SCG整体架构设计如图所示。
自研网关
一个API网关的基本功能包括统一接入、协议适配、流量管控与容错,以及安全防护,这个四大基本功能构成了网关的核心能力。网关首要的功能是负责统一接入,然后将请求的协议转换成内部的接口协议,在调用的过程中还要限流、降级和熔断等容错的方式来保护网关的整体稳定,同时网关还要做到基本的安全防护(防刷控制),以及黑白名单(比如IP地址白名单)等基本的安全措施,主要包括:统一标准接入,具备高性能、高并发和高可靠性,具备负载均衡的能力;
除了基本的四个功能,网关运行良好的环境还包括注册中心(比如通过Nacos读取已经发布的API接口的动态配置)。为了实现高性能,将数据全部异构到缓存(比如Redis)中,同时还可以配合本机缓存来进一步的提高网关系统的性能。为了提高网关的吞吐率,可以使用NIO+Servlet3异步的方式,还可以利用Servlet3的异步特性将请求线程与业务处理线程分开,为后续的线程池隔离做好基本的支撑。访问日志的存储我们可以放到Hbase或者ES中,如果要作为开放网关使用,那么需要一个支持OAuth2.0协议的授权中心,同时还可以引入Nginx+Lua的方式,将一些基本的校验判断前置到应用系统之上,这样可以更加轻量级的处理网关接入的问题。
主要包括接入层,开发者可以通过Nginx和Lua脚本,解决限流、黑白名单、路由、负载均衡、长短连接以及容灾切换的问题。网关需要保证服务的稳定性,需要接入注册中心,因为本书是Spring Cloud Alibaba的布道书籍,所以强烈推荐使用Nacos作为注册中心和配置中心。统一的鉴权中心,主要是统一解决网关为各个API服务的鉴权问题,当然可以按照服务维度做隔离,自定义鉴权规则。统一用户中心主要是解决用户登录问题,确保微服务调用的安全性。
自研网关还需要有泛化功能,使用者在调用提供者的接口的时候,不再需要API提供者的客户端JAR包,因此也就没有了POJO,通过泛化的方式进行远程调用。一般情况下我们要通过RPC调用接口提供方的服务,首先在系统中嵌入接口提供者的JAR包,然后使用JAR包里面的类和方法。对于一个网关系统来说,如果要调用N个接口,就需要N个JAR包,这样的网关是很难维护的,当然Dubbo RPC是支持泛化的。
网关要具备时间校验、方法校验、版本校验和签名校验等功能,当然网关还需要具备服务降级、日志记录以及监控与告警功能。
对比以上三种网关
网关 | 限流 | 鉴权 | 监控 | 易用性 | 可维护性 | 成熟度 |
SCG | 可以通过IP,用户,集群限流,提供了相应的接口进行扩展 | 普通鉴权auth2.0 | Gateway Metrics Filter | 简单易用 | Spring系列可扩展强,易配置和可维护性好 | Spring社区成熟,但Gateway资源少。 |
Zuul2 | 可以通过配置文件配置集群限流和单服务器限流,也可以通过filter实现限流扩展 | filter中实现 | Filter中实现 | 参考资料比较少 | 可维护性差 | 开源不就资源少。 |
Zuul1 | 同上 | 同上 | 同上 | 同上 | 同上 | 同上 |
自研网关 | 需要开发 | 需要开发 | 需要开发 | 需要开发 | 可维护性极高 | 需要开发 |
总结
推荐使用Spring Cloud Alibaba+Spring Cloud Gateway,可以更加高效的利用Spring Cloud ALibaba的服务治理能力去融合网关API的治理,从而提升业务服务API的系统稳定性。