为什么我们需要API网关?(Why do we need API Gateway?)
To understand this pattern we must delve into the real life problems, in the microservices world. We will continue with the example of our e-commerce system. In the previous exercise, we already built Product Catalog Service, which is responsible to manage product lifecycle through — create, update, delete and get operations. Lets go through some common scenarios, you might come across, while developing the microservices.
要了解这种模式,我们必须深入研究微服务世界中的现实生活中的问题。 我们将继续以电子商务系统为例。 在上一个练习中,我们已经构建了产品目录服务,该产品目录服务负责通过创建,更新,删除和获取操作来管理产品生命周期。 在开发微服务时,让我们经历一些常见的场景,您可能会遇到。
方案1-服务的多个版本 (Scenario 1 — Multiple Versions of Service)
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/a39542ecbea303f2ad6586121eccf09f.png)
Our Product Catalog Service is updated with the new changes, but the updated service is not compatible with the mobile client.
我们的产品目录服务已通过新更改进行了更新,但是更新的服务与移动客户端不兼容。
Though we cannot achieve the service update completely, we can optimize it by running multiple versions in parallel. Our mobile client will continue using the V1 while other clients will move to V2.
尽管我们无法完全实现服务更新,但是我们可以通过并行运行多个版本来对其进行优化。 我们的移动客户端将继续使用V1,而其他客户端将移至V2。
方案2-限制访问 (Scenario 2 — Restricted Access)
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/5752ddeb7774d7eaf578bfc24b8e824c.png)
Our Product Catalog Service provides apis to both read and write the catalog data.
我们的产品目录服务提供了用于读取和写入目录数据的api。
Our security team suggests to limit the access of write apis — add, update and delete, from the vendor portal only — vendor.test-gateway-store.com.
我们的安全团队建议限制对写入api的访问-仅可从供应商门户( vendor.test-gateway-store.com)添加,更新和删除。
Rest of the clients, like e-commerce portal, can only access get product api from Product Catalog Service.
其他客户(例如电子商务门户)只能从Product Catalog Service访问get product api 。
方案3-监视Api性能 (Scenario 3 — Monitoring Api Performance)
Lot of customers are complaining delays while getting the product details. We must monitor the performance of “get product details” api to assess the severity and plan out the next steps.
许多客户抱怨获得产品详细信息时延误。 我们必须监视“获取产品详细信息” api的性能,以评估严重性并计划下一步。
方案4-更新响应标头 (Scenario 4 — Updating Response Header)
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/b712b3c2b0b4c7a6515e48e5d5eafa75.png)
We received the performance statistics of Product Catalog Service. Get product details api is getting hit too many times. This is not needed as the product details are not updated every minute.
我们收到了产品目录服务的性能统计数据。 获取产品详细信息api被击中太多次了。 不需要此操作,因为产品详细信息不会每分钟更新一次。
We can avoid the unnecessary hits by introducing Cache-Control header attribute in the response of get product details api.
我们可以通过在获取产品详细信息api的响应中引入Cache-Control标头属性来避免不必要的点击。
The above discussed scenarios typically fall into the category of cross cutting concerns and must be dealt separately . This will increase the maintainability and agility of overall system. Also if the changes are done in code, its going to create longer delivery timelines. The API Gateway pattern provides a cleaner approach to resolve such issues.
上面讨论的场景通常属于交叉关注的类别,必须单独处理。 这将增加整个系统的可维护性和敏捷性。 同样,如果更改是在代码中完成的,则将创建更长的交付时间表。 API网关模式 提供了一种更清洁的方法来解决此类问题。
API网关如何工作? (How API Gateway Works?)
The API gateway takes all the api calls, from the clients and route them to appropriate microservice(s) with request routing, composition, and protocol translation.
API网关从客户端接收所有api调用,并将它们路由到具有请求路由,组合和协议转换的适当微服务。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/5d04ded63f2b81134b77c89455596daa.png)
Exactly what the API gateway does will vary from one implementation to another. Some common functions include routing, rate limiting, billing, monitoring, authentication, api composition, policies, alerts, and security.
确切地说, API网关所做的工作因一个实现而异。 一些常用功能包括路由,速率限制,计费,监视,身份验证,API组成,策略,警报和安全性。
We will be implementing the gateway pattern to solve the problems, we discussed above. These sample implementations are primarily based on Spring Cloud Gateway. This library is the preferred gateway implementation provided by Spring Cloud. Its built with Spring 5, Spring Boot 2 and Project Reactor.
我们将实现上面讨论的网关模式来解决问题。 这些示例实现主要基于Spring Cloud Gateway。 该库是Spring Cloud提供的首选网关实现。 它使用Spring 5,Spring Boot 2和Project Reactor构建。
Spring Cloud Gateway的核心功能 (The core functions of Spring Cloud Gateway)
Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency. The framework is based on three core components — Routes, Predicates and Filters.
Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注点,例如:安全性,监视/度量和弹性。 该框架基于三个核心组件-路由,谓词和过滤器。
路线 (Routes)
This is the primary component consisting of ID, Destination Uri, Predicates and Filters.
这是主要组件,由ID,Destination Uri,Predicates和Filters组成。
谓词 (Predicates)
This is more like a condition to match the route. This is done based on the HTTP request, headers, parameters, path, cookie and other request criteria.
这更像是匹配路线的条件。 这是根据HTTP请求,标头,参数,路径,cookie和其他请求条件完成的。
筛选器 (Filters)
They are the plugins to update the request or response. They function similar to the servlet filters with the pre and post variations. You can use it for multiple purpose including “adding a request parameter”, “adding a response header”, “monitoring”, and many other utilities.
它们是用于更新请求或响应的插件。 它们的功能与servlet过滤器类似,但具有前后变化。 您可以将其用于多种用途,包括“添加请求参数”,“添加响应头”,“监视”以及许多其他实用程序。
We will see the examples for each of these aspects through the sample implementations in the next section.
在下一节中,我们将通过示例实现来查看这些方面的示例。
实施Api网关 (Implementing Api Gateway)
In this section, we will implement our Api Gateway and build the solutions mapped to the scenarios discussed earlier.
在本节中,我们将实现Api网关并构建映射到前面讨论的方案的解决方案。
方案1-服务的多个版本。 (Scenario 1 — Multiple versions of a service.)
As discussed earlier, we will have two version of our Product Catalog Service — V1 & V2. Lets create Product Catalog Service based on Spring Boot as explained in our very first series — Developing First Service. Assuming you are already aware of creating a Spring Boot based service, we will work on updating the Product Catalog Service.
如前所述,我们将提供两个版本的产品目录服务-V1和V2。 让我们 如第一个系列“开发第一服务”中所述,基于Spring Boot创建产品目录服务。 假设您已经知道创建基于Spring Boot的服务,我们将致力于更新Product Catalog Service 。
Lets introduce a new method — getVersion
in this service, which does a simple job to display the service version.
让我们在该服务中引入一个新方法getVersion
,它可以很简单地显示服务版本。
@RestController
public class ProductCatalogService {
... @GetMapping("/product/version")
public String getVersionInfo(){
return "Version - V1";
}}
Copy the whole project to create a new version of our Product Catalog Service. Implement the getVersion
method similar to the one above. The only difference is the version name — V2.
复制整个项目以创建我们产品目录服务的新版本。 实现类似于上述方法的getVersion
方法。 唯一的区别是版本名称-V2。
@RestController
public class ProductCatalogService {
... @GetMapping("/product/version")
public String getVersionInfo(){
return "Version - V2"; }}
Update the respective application properties to avoid the port conflicts. We will be running Version 1 on port 8081 and Version 2 on port 8082.
更新相应的应用程序属性,以避免端口冲突。 我们将在端口8081上运行版本1,并在端口8082上运行版本2。
server.port=8081 #8081 for V1 and #8082 for V2
Run both the service versions with the maven command mvn spring-boot:run
, in the respective directories. You should be able to view the specific versions by visiting http://localhost:8081/product/version
or http://localhost:8082/product/version
urls.
使用maven命令mvn spring-boot:run
在相应目录中运行两个服务版本。 您应该能够通过访问http://localhost:8081/product/version
或http://localhost:8082/product/version
URL来查看特定版本。
Its time to create our API Gateway server. Lets go to our favorite store to create Spring Boot application — The Spring Initializer. Add the Spring Cloud Gateway dependency.
是时候创建我们的API网关服务器了。 让我们去我们最喜欢的商店创建Spring Boot应用程序-Spring Initializer 。 添加Spring Cloud Gateway依赖项。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/849184253f551a4467366443ded52363.png)
Generate, download and unpack the archive to your local system. Open the project with your favorite code editor. We will be creating src/main/resources/application.yml
file for the gateway server configuration.
生成,下载归档文件并将其解压缩到本地系统。 使用您喜欢的代码编辑器打开项目。 我们将为网关服务器配置创建src/main/resources/application.yml
文件。
server:
port: 9090
spring:
cloud:
gateway:
routes:
- id: product_service_v1
uri: 'http://localhost:8081'
predicates:
- Path=/product/**
- Query=src,mobile
- id: product_service_v2
uri: 'http://localhost:8082'
predicates:
- Path=/product/**
We are defining two routes here — product_service_v2
and product_service_v1
. The first version can only be accessed by Mobile devices. We are using two predicates for product_service_v1
to achieve this —
我们在此处定义两条路由product_service_v2
和product_service_v1
。 第一个版本只能由移动设备访问。 我们使用product_service_v1
两个谓词来实现这一目标-
Path (/product/**) — This will match the path pattern containing ‘/product’ with any suffix.
路径(/ product / **)-这将匹配包含“ / product”和任何后缀的路径模式。
Query (src,mobile) — This will match the query parameter in the path if
src
parameter is available and has a valuemobile
查询(src,mobile)-如果
src
参数可用并且值为mobile
,则它将与路径中的查询参数匹配
If both the conditions meet, the request will be forwarded to http://localhost:8081
as specified against uri
attribute. If only the path matches, request will be forwarded to http://localhost:8082
.
如果两个条件都满足,则将根据uri
属性将请求转发到http://localhost:8081
。 如果仅路径匹配,则请求将转发到http://localhost:8082
。
Lets start our gateway server by running mvn spring-boot:run
and visit following urls
让我们通过运行mvn spring-boot:run
启动我们的网关服务器mvn spring-boot:run
并访问以下URL
http://localhost:9090/product/version?src=mobile
— You will see the message — “Version V1”http://localhost:9090/product/version?src=mobile
—您将看到消息— “ Version V1”http://localhost:9090/product/version
—You will see the message — “Version V2”http://localhost:9090/product/version
—您将看到消息— “ Version V2”
Congratulations. You just completed the first sample routing for our Api Gateway. We used predicates to route the requests to different versions of a service.
恭喜你您刚刚完成了Api网关的第一个示例路由。 我们使用谓词将请求路由到服务的不同版本。
方案2-限制访问 (Scenario 2- Restricted Access)
As discussed earlier, we need to restrict the access of our write operations including create, update and delete apis of Product Catalog Service. We will do this by updating our route definitions.
如前所述,我们需要限制对写入操作的访问,包括创建,更新和删除Product Catalog Service的api。 我们将通过更新路线定义来做到这一点。
But this time we will to do it in a different way. Spring cloud gateway supports route definition in two ways — configuration files and code. We already used the first option, now we will use the second. Update your GatewayServerApplication.java
, the auto generated java file in our gateway server, with the highlighted code.
但是这次我们将以不同的方式来做。 Spring Cloud Gateway通过两种方式支持路由定义-配置文件和代码。 我们已经使用了第一个选项,现在我们将使用第二个选项。 使用突出显示的代码更新您的GatewayServerApplication.java
中自动生成的Java文件GatewayServerApplication.java
。
@SpringBootApplication
public class GatewayServerApplication { public static void main(String[] args) {
SpringApplication.run(GatewayServerApplication.class, args);
} @Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/product").and().method("POST", "PUT", "DELETE").and().host("vendor.test-gateway-store.com")
.uri("http://localhost:8081"))
.route("path_route", r -> r.path("/product/**").and().method("GET")
.uri("http://localhost:8082"))
.build();
}}
With the customRouteLocator method, we are again defining two routes. The first route definition says — if a request is received with the path “/product” and the method type is either POST, PUT or DELETE and the host is vendor.test-gateway-store.com then allow the request to be forwarded to http://localhost:8081
使用customRouteLocator 方法,我们再次定义了两条路线。 第一个路由定义是-如果接收到带有路径“ / product”的请求,并且方法类型为POST,PUT或DELETE ,且主机为vendor.test-gateway-store.com,则允许将请求转发至http://localhost:8081
The second route takes care of all the get requests with the pattern /product/**
, and forwards them to http://localhost:8082
第二条路由使用/product/**
模式处理所有get请求,并将它们转发到http://localhost:8082
If you run your post requests from your local machine, it will fail. If you want them to pass update the host value in the first route as “localhost*”. The get requests will pass for all the different sources.
如果您从本地计算机运行发帖请求,它将失败。 如果希望它们通过,请将第一条路由中的主机值更新为“ localhost *” 。 获取请求将传递给所有不同的源。
Great! We solved another major issue with the minimal configuration. Two more to go!
大! 我们用最小的配置解决了另一个主要问题。 还有两个!
方案3-监视Apis (Scenario 3 — Monitoring Apis)
This is relatively simpler. To enable gateway metrics, add spring-boot-starter-actuator as a project dependency in our gateway sever application. Gateway Metrics Filter is a global filter and does not need any route configuration. The global filters are special filters that are conditionally applied to all the routes. Lets update the pom.xml
to include the actuator dependency —
这是相对简单的。 要启用网关指标,请在我们的网关服务器应用程序中将spring-boot-starter-actuator添加为项目依赖项。 网关度量标准筛选器是全局筛选器,不需要任何路由配置。 全局过滤器是特殊过滤器,有条件地应用于所有路由。 让我们更新pom.xml
以包括执行器依赖项-
<project>
... <dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency></dependencies></project>
Enable the specific actuator views, in src/main/resources/application.properties
. This will enable us to view the metrics through browser.
在src/main/resources/application.properties
启用特定的执行器视图。 这将使我们能够通过浏览器查看指标。
management.endpoints.web.exposure.include=gateway,metrics
Start the gateway server and access the metrics at http://localhost:9090/actuator/metrics/gateway.requests
. You can view a response similar to the one below.
启动网关服务器,并访问http://localhost:9090/actuator/metrics/gateway.requests
。 您可以查看与以下响应类似的响应。
{
"name": "gateway.requests",
"description": null,
"baseUnit": "seconds",
"measurements": [
{
"statistic": "COUNT",
"value": 4
},
{
"statistic": "TOTAL_TIME",
"value": 1.754685765
},
{
"statistic": "MAX",
"value": 0.086543555
}
],
"availableTags": [
{
"tag": "routeUri",
"values": [
"http://localhost:8082",
"http://localhost:8081"
]
},...
]
}
The above response provides valuable insights including the count of requests, total time taken and maximum time taken for the api response. The above figures reflect the numbers aggregated across all the requests. You can check the specific figures based on routeId, routeUri, outcome, status, httpStatusCode and httpMethod, which are available as filter tags. So if you want to monitor the api on http://localhost:8082
, we can access it through
上面的响应提供了有价值的见解,包括请求的计数,花费的总时间以及api响应的最长时间。 上面的数字反映了所有请求中汇总的数字。 您可以根据routeId,routeUri,结果,状态,httpStatusCode和httpMethod(可作为过滤器标签使用)检查特定数字。 因此,如果您想监视http://localhost:8082
上的api,我们可以通过访问它
http://localhost:9090/actuator/metrics/gateway.requests?tag=routeUri:http://localhost:8082
The above metrics can be easily integrated with Prometheus to create a Grafana dashboard.
可以轻松地将上述指标与Prometheus集成以创建Grafana仪表板。
方案4-更新响应标头 (Scenario 4 — Updating Response Header)
So our monitoring results indicate that the get product details api throughput is on compromising side. We will use the basic caching mechanism to improve its performance. We will take help of cache-control
response header to limit the hits on the server side. Product details or list are not updated so frequently.
因此,我们的监控结果表明,获取产品详细信息的api吞吐量处于不利的一面。 我们将使用基本的缓存机制来提高其性能。 我们将利用cache-control
响应标头来限制服务器端的点击。 产品详细信息或列表更新不是那么频繁。
For our test purpose we will add max-age
attribute to it with value of 5 mins. This means the client of this api (get product details) will keep the cache of api results for 5 mins. If the user tries to get the product details with in this period, the cached result will be returned.
出于测试目的,我们将为其添加max-age
属性,其值为5分钟。 这意味着此api的客户端(获取产品详细信息)会将api结果的缓存保留5分钟。 如果用户在此期间尝试获取产品详细信息,则将返回缓存的结果。
Lets update our GatewayServerApplication.java
让我们更新我们的GatewayServerApplication.java
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder)
{
return builder.routes()
.route("path_route", r -> r.path("/product").and().method("POST", "PUT", "DELETE").and().host("localhost*")
.uri("http://localhost:8081"))
.route("path_route", r -> r.path("/product/**").and().method("GET")
.filters(f -> f.addResponseHeader("Cache-Control", "max-age=300"))
.uri("http://localhost:8082"))
.build();}
We added the required response header with the help of a pre defined filter — Add Response Header filter.
我们在预定义的过滤器(添加响应头过滤器)的帮助下添加了所需的响应头。
Restart the gateway server and try to get the product list. Inspect its response headers and you will find the cache-control header we introduced just now. If you try to add a product now, and refresh, all with in 5 mins, your list will not be updated on the browser side.
重新启动网关服务器,然后尝试获取产品列表。 检查其响应标头,您将找到我们刚才介绍的缓存控制标头。 如果您尝试在5分钟内立即添加产品并刷新所有内容,则列表不会在浏览器端更新。
Bravo! we finished all the scenarios in less than 10 mins.
太棒了! 我们在不到10分钟的时间内完成了所有场景。
学习永无止境 (Learning never stops)
We are able to implement our basic API Gateway server based on Spring Cloud Gateway. The complete source code of the examples, is available at Github. We tried to get a practical insight into the API Gateway pattern but we just scratched the surface, in terms of features.
我们能够实现基于Spring Cloud Gateway的基本API网关服务器。 示例的完整源代码可在Github上获得。 我们尝试了 以获得对API网关模式的实用见解,但我们只是从功能上进行了介绍。
We explored few predicates like path, method and host. But the Spring Cloud Gateway provides many more built-in route predicate factories including After/Before/Between DateTime, Cookie, Header, Host, Method, Path, Query, Remote Address and Weight.
我们探索了一些谓词,例如路径,方法和宿主。 但是Spring Cloud Gateway提供了更多内置的路由谓词工厂,包括DateTime之后/ Before / Between之间,Cookie,标题,主机,方法,路径,查询,远程地址和权重。
We explored the Add Response filter to implement the cache strategy. Similar to the built-in predicates, there are many other built-in filters too, including Add Request, Add Response, Circuit Breaker, Hystrix, Fallback, Map Request, Prefix Path, Preserve Host, Request Rate Limiter, etc. We can add a custom filter too if the already available set does not suffice the needs.
我们探索了添加响应过滤器以实现缓存策略。 与内置谓词类似,也有很多其他内置过滤器,包括添加请求,添加响应,断路器,Hystrix,回退,映射请求,前缀路径,保留主机,请求速率限制器等。 如果已经可用的集合不能满足需要,我们也可以添加自定义过滤器。
The library provides options to cater advance routing needs with Cors Configuration. We already discussed monitoring api performance but the actuator api provides rich set of monitoring options. Do check out the Spring Cloud Gateway documentation to further upgrade your skills with this technology.
该库提供了一些选项,以通过Cors Configuration满足高级路由需求。 我们已经讨论了监视api的性能,但是执行器api提供了丰富的监视选项集。 请查看Spring Cloud Gateway文档,以进一步升级使用此技术的技能。
You can browse:1. Next Exercise - Implementing Circuit Breaker 2. Prev Exercise - Implementing Distributed Tracing3. Complete Series - Spring Boot Microservices - Learning through Examples
翻译自: https://medium.com/an-idea/spring-boot-microservices-api-gateway-e9dbcd4bb754