Transferred from: http://www.scienjus.com/api-gateway-and-netflix-zuul/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_ Source=toutiao.io
Recently involved in the construction of the company API Gateway, technology selection is the Netflix Zuul, mainly talk about some of the experience and experience.
This article is about how to build the gateway to the production environment and what to do with the gateway when using Zuul and without forcing the use of other Neflix OSS components. Not going to introduce any way to quickly build Zuul, or some easy-to-integrate Eureka, which has been clearly described in the official documentation.
API Gateway
API Gateway is an architectural pattern that arises along with the concept of microservices (Microservice), which is used to solve the problem that microservices are too fragmented and there is no unified access port for traffic management.
It would be appropriate to explain it in two pictures on the official Kong website.
When using microservices to build an entire API service, there are often many different applications running, which require some common functions, such as authentication, flow control, monitoring, and log statistics.
In traditional monomer applications, these functions are generally embedded in the application and run as a component. However, in microservices mode, there are dozens of or even hundreds of different types of applications that can run independently, and continuing to use this approach can result in very high management and publishing costs. Therefore, it is necessary to abstract a unified traffic entry on these applications to accomplish these functions.
In my opinion, the responsibilities of API Gateway are mainly divided into two parts:
- Features that are perceived and important to the service application, such as authentication.
- Apply a non-aware edge service to a service, such as flow control, monitoring, page-level caching, and so on.
Netflix Zuul
For API Gateway, common selection is based on Openresty Kong, Go-based Tyk, and Java-based Zuul.
There is no obvious difference between the three selection itself, mainly to see whether the technology stack can meet the rapid application and two development, such as our original technology stack is the use of Go/openresty platform group and the use of Java backend group, after discussion that the API Gateway The future is to deal with the business functions of the scene more, and the back end there are a lot of features can be directly transplanted, and eventually chose the Zuul.
With regard to Zuul, most of the people who use Java for microservices may be more or less familiar with Spring Cloud and Netflix family barrels. And for someone who doesn't know it, you can think of it as a concept similar to a filter in a Servlet.
As described in, Zuul provides APIs for four filters, namely pre (pre), post (POST), Route (route), and error four processing methods.
A request is routed through all the pre-filters sequentially, then to the back-end application in the routing filter, and the response is then passed through all the post filters and finally to the client. If an exception occurs throughout the process, it jumps to the error filter.
In general, if you need to process the request before it arrives at the backend, you will choose a pre-filter, such as authentication, request forwarding, additional request parameters, and so on. Actions that need to be processed after the request is completed are placed in a post-filter, such as statistical return values and call times, logging, and increasing cross-domain prime behavior. Routing filters generally only need to select the built-in Zuul, error filters generally only need one, so that the Gateway encountered error logic directly throws an abnormal interrupt process, and directly processing the return results.
Application Scenarios
Here are some scenarios for the different filters in the Zuul.
Pre-filter Authentication
In general, the authentication logic of the entire service can be complex.
- Client: APP, Web, backend
- Permission groups: Users, background personnel, other developers
- Implementation: OAuth, JWT
- How to use: Token, Cookie, SSO
For back-end applications, they just need to know who the request belongs to, and don't need to know why, so the Gateway can be friendly to help the backend application to complete the authentication, and the user's unique mark through the backend, and do not need, and should not even pass the identity information to the backend, Prevent certain apps from using these sensitive information to do the wrong thing.
Zuul by default, the requested Authorization
headers and headers are removed after processing Set-Cookie
, and this principle is implemented.
Traffic forwarding
The meaning of traffic forwarding is to /a/xxx.json
forward the requested request to the point /b/xxx.json
. This feature may be useful for some project migrations, or Grayscale publishing.
There is no good way to modify the Request URI in Zuul. In some Issue the developer would recommend setting requestURI
this property, but it will be overwritten again in the process of Zuul itself PreDecorationFilter
.
However, for a Servlet-based application, the use of HttpServletRequestWrapper
basic can solve all problems, in this scenario only need to rewrite its getRequestURI
methods.
Class Rewriteurirequestwrapper extends Httpservletrequestwrapper {
Private String Rewriteuri;
Public Rewriteurirequestwrapper (HttpServletRequest request, String Rewriteuri) { Super (Request); This.rewriteuri = Rewriteuri; }
@Override Public String Getrequesturi () { return Rewriteuri; }
}
|
Post Filter cross-domain
The advantage of using Gateway for cross-domain comparison or Nginx is that rules can be configured more flexibly. For example, a common rule.
- For any AJAX request, returned as, and
Access-Control-Allow-Origin
*
Access-Control-Allow-Credentials
true
is, a common configuration that allows arbitrary sources across domains, but does not allow requests to carry any cookies
- If a trusted requestor needs to carry a Cookie, it will be
Origin
added to the whitelist. For requests in the whitelist, the domain name is returned, so that the Access-Control-Allow-Origin
Access-Control-Allow-Credentials
true
requestor can request the interface normally, and can carry a Cookie when the interface is requested
- For 302 of requests, even if the whitelist must be set to
Access-Control-Allow-Origin
*
, otherwise the redirected request will be carried Origin
null
, may lead to some compatibility issues with IOS low version
Statistics
Gateway can uniformly collect all application request records, and write to the log file or to the monitoring system, compared to Nginx access log, the benefits are mainly two times to develop more convenient, such as can focus on some business-related HTTP headers, Either the request parameter and the return value are saved as logs into the message queue, which facilitates on-line failure debugging. You can also collect some performance metrics to send to a monitoring platform like STATSD.
Error filter
The main usage of the error filter is the same as in Jersey ExceptionMapper
or Spring MVC @ExceptionHandler
, when there is a problem in the processing process, a uniform exception is thrown directly, and after the error filter catches the exception, it can uniformly encapsulate the return value and end the request directly.
Configuration Management
While switching these logic to the gateway eliminates a lot of maintenance and iteration costs, there is also a big problem: the gateway has no logic but no configuration, and it doesn't know what process a request is going to take.
For example, the backend service API, some may be for the web version, some for the client, or some for the user, and some for the management, then how does Gateway know whether these APIs need to login, flow control and cache it?
In theory, we can write a management background for Gateway, which has all the APIs for the current service, and each developer can create new APIs in it and add authentication, caching, and cross-domain functions to it. In order to simplify the use, perhaps we will add an additional permission group, for example, /admin/*
all the APIs below should be the background interface, it only allows authentication access from internal sources.
But this is still too complex, and very hard to code, when developers developed a new API, even if the application has been able to receive a specific URI request and processing, but also by manual way to a management background for additional configuration, And it may be unreasonable to make an unnecessary accident by not carefully hitting a word in the wrong path.
I personally recommend the ability to remain configured in the backend application even if there is no real logic in the application. For example, it is a good choice to write an API in Java with annotation declarations, and to automatically register the Gateway when the app is launched.
/** * This interface requires authentication, the authentication method is OAuth */ @Authorization (OAuth) @RequestMapping (value = "/ Users/{id} ", method = Requestmethod.delete) public void del (@PathVariable int id) { /... /** * This interface can be cached, and each Ip/user requests up to 10 times per second */ @RateLimiting (limit = "10/1s", scope = {IP, USER}) public void info (@PathVariable int id) { } /span> |
This allows the author of the API to consider what functionality the API requires and reduce the complexity of management based on the business scenario.
In addition to some backend application-independent configurations, some of which are automated, such as malicious request interception, Gateway sends all the requested information through the message queue to some real-time data analytics applications that analyze the request, discover the characteristics of the malicious request, and pass the Gateway The provided interfaces escalate these features to Gateway,gateway to intercept these malicious requests in real time.
Stability
In the Nginx and back-end application between the establishment of a Java application as a traffic portal, many people will worry about its stability, or whether it can be like Nginx and the backend to interact with multiple upstream, the following mainly describes the Zuul isolation mechanism and retry mechanism.
Isolation mechanism
In micro-service mode, the connection between applications becomes less intense, and any application that is in the ideal can be overloaded or hung out, and should not affect other applications. But at the gateway level, is it possible that an application is overloaded, causing the entire Gateway to be crushed, and the traffic ingress for all applications cut off?
This is of course possible, imagine a application that receives a lot of requests per second, and under normal circumstances these requests can respond normally within 10 milliseconds, but if one day it goes wrong, all requests will Block to 30 seconds timeout to break (for example, frequent full GC cannot effectively free memory). At this time, too, there will be a large number of threads in the Gateway waiting for the response of the request and will eventually eat up all the threads, causing other requests for normal applications to be affected as well.
In Zuul, every backend application is called a route, and in order to avoid a route that has too many resources affecting other route occurrences, Zuul uses Hystrix to isolate and limit each route.
There are two types of isolation strategies for hystrix, either based on threads or based on semaphores. Zuul defaults to a thread-based isolation mechanism, which means that every request for a route is executed in a fixed-size, separate thread pool, so that if one of the route problems occurs, only one thread pool is blocked and the other route is not affected.
In general, when using Hystrix, the semaphore is used to isolate the policy only when the amount of the call is significant and is subject to thread overhead, and it is more secure to use thread isolation for the purpose of Zuul this network request.
Retry mechanism
In general, the health state of the backend application is unstable and the application list can be modified at any time, so the Gateway must have a good enough fault tolerant mechanism to reduce the impact of changes in the backend application.
Zuul's routing is mainly Eureka and ribbon two ways, because I have been using the ribbon, so a brief introduction of the Ribbon support which fault-tolerant configuration.
The retry scenario is divided into three types:
okToRetryOnConnectErrors
: Retry only Network error
okToRetryOnAllErrors
: Retry All errors
OkToRetryOnAllOperations
: Retry all operations (not quite understood here, guess is get/post etc requests will retry)
There are two different times to retry:
MaxAutoRetries
: Maximum number of retries per node
MaxAutoRetriesNextServer
: Maximum number of replacement node retries
In general, we would like to retry only when the network connection fails, or to retry the GET request for 5XX (the POST request is not recommended to retry, and there is no guarantee that idempotent will result in inconsistent data). The number of retries can be as small as possible, retry the number of nodes as much as possible, the overall effect will be better.
If there are more complex retry scenarios, such as the need to retry specific certain APIs, specific return values, you can also implement RequestSpecificRetryHandler
custom logic (not recommended for direct use RetryHandler
, as this subclass can use many of the existing features).
Talk about API Gateway and Netflix Zuul