发布信息

API网关的技术框架和用法和优缺点有哪些?

作者:软荐小编      2023-07-22 01:04:40     272

API网段技术实战

介绍完API网段的相关理论后,你就可以了解API网段的功能、优点和缺点,然后我会介绍API网段在微服务项目中的技术框架和使用实践。

Zuul网段

虽然API网段并不是什么难的技术,但即使没有框架,我们也可以通过原生ServletFilter、HttpClient等远程调用方法来实现网段路由和过滤。 所以API网段的本质在于它解决问题的思路和方法,但是框架可以给我们带来很多便利,提高开发效率。 我们先来看看SpringCloud家族中的一个API网段框架:Zuul。

10段均衡器app_31段均衡器软件教程_均衡器算法

Zuul是应用最广泛的API网段框架之一。 它是由著名的Netflix公司开发的。 SpringCloud对Zuul进行了一层封装,提供请求路由、过滤等各种功能的灵活配置。 下面详细介绍SpringCloudNetflixZuul框架的具体使用方法。

1. 路由

首先,我们可以通过创建一个项目,但是添加Zuul依赖,或者直接将SpringCloud依赖和Zuul依赖添加到要开发的API网段项目中。 代码如下。

均衡器算法_31段均衡器软件教程_10段均衡器app

之后,只需在SpringBoot启动类上加上@EnableZuulProxy注解即可,代码如下。

均衡器算法_31段均衡器软件教程_10段均衡器app

关于完成网段的初始配置,Zuul的Spring Cloud Starter会完成实例化相关bean的工作。 接下来我们看看Zuul中如何做路由。

假设我们有一个用户服务,端口为8081,提供GET接口,请求地址为/users/{id}。 如果要查询ID1的用户信息并直接访问该用户服务的接口,则URL应为GET:8081/users/1。 如果使用Zuul进行路由,只需要在application.yml中进行配置即可。 代码如下。

10段均衡器app_31段均衡器软件教程_均衡器算法

如上面的代码所示,这里我们需要声明我们想要的路由规则。 首先在zuul.routes下为用户配置一条路由规则。 规则是请求的路径匹配/users/**,转发到地址:8081。比如这里Zuul的端口是9000,向API网段发送请求,地址是:9000/users/1,这个请求会通过Zuul的路由转发到:8081/uesrs/1。

stripPrefix 是什么意思? stripPrefix默认值为true,即去掉请求的前缀。 例如,如果我们的路由规则是/users/**,Zuul会默认请求路径中的/users是路由规则,而不是实际需要转发的请求路径。 比如我们请求:9000/users/1,如果stripPrefix为true,Zuul请求的实际地址为:8081/1,路径中的/uesrs前缀会被手动去掉。 因此,如果真实的服务路径是/uesrs/**,通过将stripPrefix设置为false,Zuul将直接使用URL加上原始请求路径来转发请求。

10段均衡器app_31段均衡器软件教程_均衡器算法

其实我们也可以采用API网段与注册中心集成的形式,直接通过服务ID做路由,这样我们就不需要关心具体的服务地址和端口,从而可以手动发现服务。

假设现在Consul已经被激活为注册中心,Consul的服务地址为127.0.0.1:8500,用户服务已经向注册中心注册了自己的服务,服务ID为user-service(具体服务的注册和发现在第2章已经详细介绍过,这里不再赘述)。 作为SpringCloud的一员,SpringCloudNetflixZuul使用注册中心的配置与其他服务没有什么区别。 在API网段创建一个名为bootstrap.yml的配置文件,其配置内容如下。

10段均衡器app_均衡器算法_31段均衡器软件教程

之后,在application.yml文件中更改路由规则,如下所示。

10段均衡器app_均衡器算法_31段均衡器软件教程

这里只需要设置ServiceID即可通过注册中心直接路由到对应的服务地址。 事实上,由于这里使用Consul作为注册中心,所以首先必须启动一个Consul实例。 例如,可以使用Docker命令来快速启动Consul。 命令如下。

最后只需要引入Consul的依赖,并在build.gradle文件中添加以下内容即可。

在ZuulApplication中添加@EnableDiscoveryClient注解来开启注册功能,代码如下。

启动项目后,可以访问:8500查看服务是否注册成功,如图5.23所示。

10段均衡器app_均衡器算法_31段均衡器软件教程

2、服务整改

有人可能会问,既然集成了注册中心,那么Zuul就可以动态发现服务了。 如果部署该服务的多个实例,Zuul能否实现负载均衡和服务熔断?

通过查看注解@EnableZuulProxy的源码可以知道,SpringCloudNetflixZuul已经集成了Ribbon和Hystrix这两个框架,这在第2章和第3章中已经详细介绍过,所以Zuul本身已经具备了负载均衡和服务熔断的能力。

10段均衡器app_31段均衡器软件教程_均衡器算法

需要注意的是,Zuul的负载均衡只支持ServiceID的路由方式。 如果使用path+ServiceID的路由配置,这里就不需要写任何代码了。 Zuul可以通过外部的RibbonRoutingFilter实现负载均衡,默认使用Ribbon寻址方式。

ServiceID需要注册中心的支持。 如果当前环境没有集成的注册中心,是不是就不能用来做负载均衡呢? Ribbon本身定位为客户端的负载均衡器,不一定要和注册中心集成。 如果我们在Zuul中使用URL形式的路由规则,如何实现负载均衡呢?

很简单,只需要改几个配置,虚拟一个ServiceID,然后指定ServiceID对应的服务地址即可,配置内容如下。

10段均衡器app_均衡器算法_31段均衡器软件教程

从上面的配置可以看出,我们禁用注册中心,仍然将ServiceID配置为users-service,然后通过指定users-service的listOfServers属性来声明该服务对应的地址。 多个节点之间用“,”分隔,这样Zuul路由时就可以进行负载均衡,无需使用注册中心。

介绍完负载均衡,我们再来说说服务熔断。 之前说过SpringCloudNetflixZuul本身就集成了Hystrix。 这么具体怎么用呢? 正如第3章介绍的,Hystrix服务熔断的核心思想是指定降级(fallback)的方法,然后在服务宕机时快速给调用者反馈。 使用Zuul搭建API网段后,请求由Zuul路由到服务器。 降级应该在哪里设置? 图5.10中,API网段的断开应该是针对服务器的。 因此,为了设置服务降级,SpringCloudNetflixZuul提供了相应的socket FallbackProvider。 只有实现它才能设置服务级别的熔断策略。 代码如下。

10段均衡器app_31段均衡器软件教程_均衡器算法

其中,getRoute方法需要返回对应路由规则中配置的ServiceID。 这里断开的对象是用户服务,所以返回users-service,其实不用注册中心就可以实现服务断路器。 具体方法与前面介绍的不使用注册中心的负载均衡配置相同。 之后,在FallbackResponse方法中,返回ClientHttpResponse对象作为降级策略。 我们可以自由设置响应的状态信息、响应头、响应体等。

不仅是服务熔断和降级,SpringCloudNetflixZuul还可以配置线程隔离策略。 例如,我们可以将Hystrix默认的线程池隔离策略更改为使用信号量隔离策略,配置如下。

3. 过滤

API网段除了路由和服务调节之外,还有一个重要的功能,那就是请求过滤。 下面看一下Zuul中过滤器的使用。 在Zuul中,我们可以通过继承Zuul提供的具体类ZuulFilter来定义一个新的过滤器,代码如下。

均衡器算法_10段均衡器app_31段均衡器软件教程

其中,filterType()返回过滤器的类型。 目前,有五种类型的过滤器:pre、route、post、error 和 static。 含义如下。

(1) pre:在路由之前执行。

(2)route:路由时执行。

(3)post:路由后执行。

(4) error:当路由发生异常时执行。

(5)static:请求静态资源时执行。

定义filterType()相当于定义了过滤器的执行时机,那么如果定义了多个预过滤器,它们的顺序是怎样的呢? filterOrder() 用于定义同一类型过滤器的执行顺序。 一般情况下,如果过滤器没有顺序要求,可以直接返回0。整数值越小,对应的过滤器越早执行。

shouldFilter() 很容易理解。 只有返回true时,过滤器才会被执行,所以这里可以定义一些规则,或者通过配置文件来灵活、可插拔地使用过滤器。

10段均衡器app_均衡器算法_31段均衡器软件教程

run()方法是过滤器的执行方法,你想让过滤器完成的事情都会写在run方法中。 例如,我们需要在所有路由的返回中添加自定义的消息头,那么我们可以编写一个post类型的过滤器,然后定义run技巧,内容如下。

31段均衡器软件教程_10段均衡器app_均衡器算法

因为run方法没有注入任何参数,所以我们可以通过Zuul提供的RequestContext获取请求和响应信息,然后更改响应头并添加需要添加的内容。 如果想阻止请求通过过滤器进行路由,可以使用前置过滤器,然后在run方法中抛出异常,代码如下。

31段均衡器软件教程_10段均衡器app_均衡器算法

如上面的代码所示,当请求的token认证失败时,可以抛出认证异常,此时请求被中断,但是身份认证一般是使用Spring Security完成的,Spring Security的基本用法将在5.5.3节中介绍。

不仅可以灵活定制过滤器,SpringCloudNetflixZuul还提供了一些外部过滤器,比如敏感信息头过滤器。 我们不需要编写代码,通过简单的配置就可以过滤请求头中的一些敏感信息。 从源码中我们可以知道SpringCloudNetflixZuul默认过滤脑信息中的三种数据:cookie、Set-cookie和Authorization。 当请求通过Zuul路由到特定服务时,一旦leg中存在cookie、Set-cookie和Authorization信息,就会将其删除。 我们也可以通过配置文件来改变这个配置,内容如下。

这里需要注意的是,新的配置会取代默认的配置,所以如果只想添加一些敏感头过滤,则必须添加cookie、Set-cookie和Authorization,代码如下。

这里介绍一下Zuul的使用。 详细教程可以查看 SpringCloudNetflix 官方文档,或者直接访问 Zuul 的 GitHub 官网。

Spring云网关

继NetflixZuul之后,SpringCloud又开发了新的API网段框架——SpringCloudGateway,它是基于Spring5开发的非阻塞API网段框架。 与 Zuul 相比,Spring Cloud Gateway 还支持长连接,因此它可以支持使用 WebSocket 来提供简单有效的方式路由到 API,并为其提供横切关注点,例如安全性、监控/指标和弹性。

Spring官网上列出了Spring Cloud Gateway的功能特点,如下。

(1)基于Springframework5、ProjectReactor和SpringBoot2.0建立。

(2)可以根据请求的任意属性来匹配路由。

(3)判断条件(Predicates)和过滤器(Filters)可以作用于具体的路由。

(4) 集成Hystrix断路器。

(5)集成Spring Cloud Discovery客户端。

(6) 判定条件(Predicates)和过滤器(Filters),方便编译。

(7)请求速率限制,即限流。

(8)路径重绘。

可见Spring Cloud Gateway比Zuul更灵活、更强大,更适合Spring Cloud。 下面介绍Spring Cloud Gateway的使用。

首先,您可以使用该工具或新建一个Gradle项目来添加SpringCloudGateway的依赖。 build.gradle文件的内容如下。

均衡器算法_31段均衡器软件教程_10段均衡器app

1. 路由

假设有一个用户服务,提供一个用于查询用户的套接字。 与Zuul的使用类似,我们可以快速减少配置文件中的路由配置,更改application.yml的内容如下。

31段均衡器软件教程_10段均衡器app_均衡器算法

上面的代码中,我们可以定义多条路由规则,其中id是路由的唯一标识,uri是原始服务的地址,predicates是判断请求是否匹配的条件。

不仅仅是Path,Spring Cloud Gateway还提供了更灵活的判断规则。 例如我们可以使用cookie来进行路由,代码如下。

均衡器算法_10段均衡器app_31段均衡器软件教程

上面的配置意味着只要请求中包含key为test、value为123的cookie,该请求就会匹配到该路由。 其实条件也是可以组合的,比如下面的配置。

均衡器算法_31段均衡器软件教程_10段均衡器app

上述配置意味着请求必须同时满足/users/**的路径,并且请求必须有test=123和test2=456的两组cookie来匹配路由。

不仅仅是Path和cookie,Spring Cloud Gateway还提供了多种匹配方式。 例如我们可以根据请求头来匹配路由,配置如下。

31段均衡器软件教程_10段均衡器app_均衡器算法

上述配置意味着请求头必须包含X-request-id信息,但值必须是users-service,这样请求才会匹配路由。 据悉,还可以基于HTTP Method进行路由,比如匹配所有GET方法,如下。

10段均衡器app_均衡器算法_31段均衡器软件教程

或者也可以根据请求的参数进行路由,配置如下。

31段均衡器软件教程_10段均衡器app_均衡器算法

上述配置意味着请求的URL参数必须包含参数a=123才能匹配路由,如//localhost:8080/users/1?a=123。

不仅仅是这种匹配方式,Spring Cloud Gateway还提供了一些特殊的路由形式,比如按照时间来进行Before、After、Between等。 这里以Between为例,我们会按照时间段的规则请求路由,配置如下。

31段均衡器软件教程_均衡器算法_10段均衡器app

上述配置意味着2018年1月1日到2018年12月31日期间的所有请求都会匹配该路由规则。 值得注意的是,因为匹配的是客户端产生请求的时间,所以时间配置需要配置时区。 Between 表示请求时间在两个指定时间之间。 同样,Before和After表示请求时间在指定时间之前和之后,只需要一次。

据悉,Spring Cloud Gateway还提供了基于Host和RemoteAddr的匹配规则,这里不再一一演示,所有规则都可以组合使用。

2.过滤

不仅仅是路由,Spring Cloud Gateway还提供了很多强大的外部过滤器,每个过滤器都可以直接配置成路由。 例如,我们可以使用AddRequestHeader和AddResponseHeader来减少请求或响应的腹部信息。 以AddResponseHeader为例,配置如下。

均衡器算法_10段均衡器app_31段均衡器软件教程

请求API网段后,在返回的响应头中可以获取到X-test=1的信息。 除了添加标头信息外,还可以通过RemoveRequestHeader和RemoveResponseHeader删除请求和响应标头信息。 以RemoveRequestHeader为例,配置如下。

31段均衡器软件教程_均衡器算法_10段均衡器app

上述配置可以删除请求头中关键字为Set-cookie的腹部信息。 不仅可以改变请求和响应的肚皮信息,Spring Cloud Gateway还提供了一个过滤器来改变请求的参数,配置如下。

31段均衡器软件教程_均衡器算法_10段均衡器app

上面的配置可以将我们所做的前缀添加到请求的路径中。 例如,如果请求路径为/users/1,则实际请求将路由到:8081/myservice/users/1。

除了上述外部过滤器之外,Spring Cloud Gateway还提供了其他过滤器。 例如,用于管理Session的SaveSession过滤器、用于设置状态的SetStatus过滤器、用于重定向的RedirectTo过滤器等等。

3、服务整改

不仅仅是这个路由级别的过滤器31段均衡器软件教程,Spring Cloud Gateway还提供了一些全局的过滤器,比如LoadBalancerClient,它可以帮助我们完成负载均衡的工作。

其实如果需要集成注册中心,首先要添加注册中心的相关依赖,在build.gradle中添加如下依赖。

之后,减少并配置其他注册表服务,例如减少bootstrap.yml文件,内容如下。

31段均衡器软件教程_均衡器算法_10段均衡器app

最后更改路由uri,配置如下。

10段均衡器app_31段均衡器软件教程_均衡器算法

这里lb://前面是服务的应用名称,这样SpringCloudGateway就可以通过LoadBalancerClient完成客户端负载均衡操作。

不仅仅是负载均衡,SpringCloudGateway还集成了Hystrix,可以完成服务熔断和降级的处理。 首先需要添加SpringCloudNetflixHystrix的依赖,并在build.gradle中添加如下依赖。

之后,更改application.yml的路由配置,如下所示。

均衡器算法_31段均衡器软件教程_10段均衡器app

在上面的配置中,减少一个Hystrix过滤器,然后SpringCloudGateway会创建一个HystrixCommand来完成服务熔断和降级操作。 通过参数(args)的配置,可以指定HystrixCommand的名称和fallback的uri,并配置降级策略跳转到/users/fallback地址31段均衡器软件教程,因此需要添加一个降级服务,并在API网段添加一个Controller。 代码如下。

31段均衡器软件教程_均衡器算法_10段均衡器app

我们可以关闭用户服务,测试一下熔断是否有效。 关闭用户服务后,通过API网段再次调用用户接口,会返回usersservicecrashed消息。

Spring Cloud Gateway不仅提供基本的负载均衡和服务熔断,还提供了基于Redis的服务限流功能。 Spring Cloud Gateway通过RequestRateLimiter过滤器完成限流工作。 由于Spring Cloud Gateway是非阻塞架构,因此需要集成spring-boot-starter-dataredis-reactive来连接Redis,并在build.gradle中添加以下依赖。

然后就可以配置Redis的连接信息了,默认是localhost:6379,内容如下。

然后添加RequestRateLimiter过滤器并进行如下配置。

31段均衡器软件教程_10段均衡器app_均衡器算法

这里用到了令牌桶算法(TokenBucketAlgorithm)。 参数redis-rate-limiter.replenishRate表示每秒允许用户的最大请求数,即每秒令牌桶的填充率。 如果设置为10,则表示令牌桶每秒最多只能装满10个请求,多余的请求不会丢失。 相反,请等待令牌桶中有可用空间,然后再继续执行。 redis-rate-limiter.burstCapacity 也表示 1s 允许的最大请求数,但与 redis-rate-limiter.burstCapacity 不同的是,burstCapacity 会直接拒绝多余的请求。 例如burstCapacity设置的值为20,那么一旦请求超过20,多余的请求就会被放弃,不再执行。

当然限流需要指定一个KeyResolver才能正常工作。 KeyResolver可以理解为限流的维度。 比如我们根据请求的路径进行限流,配置一个KeyResolver Bean,内容如下。

均衡器算法_10段均衡器app_31段均衡器软件教程

配置文件中,key-resolver: "#{@pathKeyResolver}" 指定bean的名称,即pathKeyResolver,之后对相同路径的请求将被限制。

Spring Cloud Gateway的使用就介绍到这里了,大家可以去Spring Cloud Gateway官网查看更详细的教程。

本文讲解的内容是API网段技术实战。 上一篇文章给大家讲解了SpringSecurity; 觉得文章不错的同学可以转发这篇文章关注小编; 感谢您的支持!

相关内容 查看全部