Link: github.com/oopsguy/mic… Translator: Oopsguy
The book’s seven chapters are about designing, building, and deploying microservices. The first chapter introduces the microservice architecture pattern. It illustrates the advantages and disadvantages of using microservices and, nevertheless, that microservices are often ideal for complex applications. The second article in this series will explore building microservices using API gateways.
When you choose to build your application as a set of microservices, you need to decide how the application client will interact with the microservices. Singleton applications have only one set of endpoints, which are typically replicated in combination with load balancing to distribute traffic.
However, in a microservice architecture, each microservice exposes a set of typically fine-grained endpoints. In this article, we’ll look at how to improve client communication and propose a scenario using API gateways.
2.1, introduction to
Let’s say you are developing a native mobile client for a shopping application. You may need to implement a product details page that displays information about a given item.
For example, Figure 2-1 shows what you look at when scrolling through product information in Amazon’s Android mobile app.
Figure 2-1. A simple shopping application
Even though it’s a smartphone app, the product details page shows a lot of information. For example, not only is there basic product information such as name, description, and price, the page also shows:
- The number of items in a shopping cart
- Order history
- Customer comments
- Low inventory warning
- The shipping options
- A variety of recommendations, including other products that customers who buy this product often buy
- Optional purchase option
In the case of a singleton application architecture, mobile clients retrieve this data by making a single REST call to the application, for example:
GET api.company.com/productdetails/productIdCopy the code
The load balancer routes requests to one of several instances of the same application. After that, the application queries the individual database tables and returns responses to the client. In contrast, when using the microservices architecture, the data presented on the product details page comes from multiple microservices. Here are some microservices that might have the data displayed on a particular product page:
- Order Service – Order history
- Catalog service – basic product information, such as product name, picture, and price
- Evaluation service – Customer evaluation
- Inventory service – Low inventory alert
- Delivery services – Delivery options, terms and costs are provided separately by the distributor’s API
- Recommended Services – Recommended categories
Figure 2-2 mapping mobile client requirements to related microservices
We need to decide how mobile clients will access these services. Let’s look at some of the ways.
2.2. The client communicates directly with the micro-service
In theory, a client could send a request directly to each microservice. Each microservice has a public endpoint:
https://serviceName.api.company.nameCopy the code
This URL will map to the microservice load balancer used to distribute requests across the available instances, and the mobile client will send a request to each of the microservices mentioned above to retrieve specific product page information.
Unfortunately, there are challenges and limitations to this approach. The first is a mismatch between client requirements and the fine-grained apis exposed by each microservice. In this example, the client needs to make seven separate requests. In more complex applications, it may need to do more work. Amazon, for example, shows how hundreds of microservices are involved in product page rendering. While clients can send many requests over a LAN, it is inefficient under the public Internet and necessarily impractical on mobile networks.
Another problem with clients calling microservices directly is that some may be using non-Web-friendly protocols. One service might use Thrift binary RPC, while the other might use the AMQP messaging protocol. Both protocols are unfriendly to both browsers and firewalls and are best used internally. Applications should use a protocol like HTTP or WebSocket outside of the firewall.
Another disadvantage of this approach is that it is difficult to refactor microservices. Over time, we may want to change the system to divide services. For example, we might merge two services or split them into two or more. However, if the client communicates directly with the service, it becomes very difficult to perform this kind of refactoring.
Because of these issues, few clients communicate directly with microservices.
2.3. Use API gateway
It is often better to use an API gateway. An API gateway is a server, a single entry point to the system. It is similar to the Facade pattern in the object-oriented design pattern. The API gateway encapsulates the internal system architecture and provides a custom API for each client. It can also be used for authentication, monitoring, load balancing, caching, and static response processing.
Figure 2-3 shows how apis generally integrate architecture
Microservices using the API gateway
The API gateway is responsible for request routing, composition, and protocol transformation. All client requests first pass through the API gateway, after which the request is routed to the appropriate service. API gateways typically process a request by invoking multiple microservices and aggregating the results. It can translate between Web protocols, such as HTTP and WebSocket, and non-Web-friendly protocols for internal use.
The API can also provide a custom API for each client. It typically exposes a coarse-grained API for mobile clients. For example, consider the product details scenario. Can an API gateway provide an endpoint/productDetails? Productid = XXX, as shown in Figure 2-3, is a microservice that uses the API gateway. Allows mobile clients to retrieve all product details through a single request. The API gateway invokes various services (product information, recommendations, reviews, and so on) and combines the results.
A good example of an API gateway is the Netflix API Gateway. The Netflix streaming service is available on hundreds of different types of devices, including TVS, set-top boxes, smartphones, game consoles and tablets. Initially, Netflix tried to provide a common API for their streaming service. However, they found that because of the variety of devices and their different needs, it didn’t work very well. Today, they use an API gateway to provide a custom API for each device by running device-specific adaptation code.
2.4. Advantages and disadvantages of API gateway
As you might expect, there are pros and cons to using an API gateway as well. The main benefit of using an API gateway is that it encapsulates the internal structure of your application. The client only needs to communicate with the gateway without having to invoke a specific service. The API gateway provides specific apis for each type of client, reducing the number of round-trips between the client and the application. It also simplifies the client code.
There are some drawbacks to the API gateway, which is another highly available component that needs to be developed, deployed, and managed. Another risk is that THE API gateway may become a development bottleneck. Developers must update the API gateway to expose the endpoints of each microservice.
It is important that the process of updating the API gateway be as light as possible. Otherwise, developers will be forced to queue up for gateway updates. Despite these shortcomings of THE API gateway, it makes sense to use the API for most real-world applications.
2.5. Implement API gateway
We’ve seen the incentives and trade-offs for using API gateways. Let’s take a look at the various design issues you need to consider.
2.5.1 Performance and scalability
Only a handful of companies can operate on the scale of Netflix, which handles billions of requests a day. However, for most applications, the performance and extensibility of an API gateway are very important. Therefore, it is necessary to build an API gateway on a platform that supports asynchronous, non-blocking I/O. Different techniques can be used to implement an extensible API gateway. On the JVM, you can use NIO based frameworks such as Netty, Vertx, Spring Reactor, or JBoss Undertow. A popular non-JVM option is to use Node.js, a platform built on Chrome’s JavaScript engine. Another option is to use NGINX Plus.
NGINX Plus provides a mature, scalable, and high-performance Web server and reverse proxy that is easy to deploy, configure, and program. NGINX Plus manages authentication, access control, load balancing requests, cached responses, and provides application health checking and monitoring capabilities.
2.5.2 Use a responsive programming model
The API gateway handles some requests by simply routing them to the appropriate back-end service. It processes additional requests by calling multiple back-end services and aggregating the results. Some requests, such as product details requests, are separate from back-end service requests. To minimize response times, the API gateway should execute separate requests concurrently.
Sometimes, however, requests are interdependent. First, the API gateway may need to validate the request by invoking the validation service before routing it to the back-end service. Similarly, in order to retrieve information about a product from a customer’s wish list, the API gateway must first retrieve the customer profile containing that information, and then retrieve information for each product. Another interesting example of API composition is Netflix video grid.
Writing API composition code using traditional asynchronous callbacks can quickly send you into callback hell. The code will be cluttered, hard to understand, and error-prone. A better approach is to write API gateway code declaratively using a reactive approach. Examples of reactive abstraction include Future in Scala, CompletableFuture in Java 8, and Promise in JavaScript. And Reactive Extensions (also known as Rx or ReactiveX), originally developed by Microsoft for the.NET platform. Netflix created RxJava for the JVM, specifically for its API gateway. There is also RxJS for JavaScript, which runs in browsers and Node.js. Using a reactive approach allows you to write simple and efficient API gateway code.
2.5.3 Service Invocation
A microservices-based application is a distributed system that must use an inter-process communication mechanism. There are two interprocess communication schemes. One is to use message-based asynchrony. Some implementations use message brokers, such as JMS and AMQP. Others, such as Zeromq, communicate directly with the service without proxies.
Another type of interprocess communication uses synchronization mechanisms, such as HTTP and Thrift. Systems typically use both asynchronous and synchronous modes. You can even apply multiple implementations for each approach. Therefore, API gateways need to support a variety of communication mechanisms.
2.5.4 Service Discovery
The API gateway needs to know the location (IP address and port) of each microservice it communicates with. In traditional applications, you can hardcode these locations, but in modern cloud-based microservice applications, finding the desired location is not a simple problem.
Infrastructure services, such as message brokers, typically have a static location that can be specified through system environment variables. However, it is not easy to determine the location of application services.
Application services can dynamically assign locations. In addition, an entire set of instances of a service can change dynamically due to automatic scaling and upgrading. Therefore, the API gateway, like any other service client in the system, needs to use the system’s service discovery mechanism: server discovery or client discovery. Service discovery is described in more detail in Chapter 4. Now it’s important to note that if the system uses client discovery, the API gateway must be able to query the service registry, which is a database of all microservice instances and their locations.
2.5.5. Handle some Faults
Another issue that must be addressed when implementing API gateways is the problem of partial failures. This problem occurs in all distributed systems when a service calls another service that is slow to respond or unavailable. An API gateway should not wait indefinitely for downstream services. However, how failures are handled depends on the particular scenario and which services fail. For example, if the recommendation service does not respond when getting product details, the API gateway should return the remaining product details to the client because they are still useful to the user. Suggestions can be empty or replaced by something else, such as a hard-coded top 10 list. However, if the product information service does not respond, then the API gateway should return an error to the client.
The API gateway can also return cached data if it can. For example, because product prices do not change much, the API gateway can return cached price data if the price service is not available. The data can be cached by the API gateway or stored in an external cache, such as Redis or Memcached. By returning default or cached data, the API gateway ensures minimal impact on the user experience in the event of a system failure.
Netflix Hystrix is a very useful library for writing code to call remote services. Hystrix can time out calls that exceed a specified threshold. It implements a circuit breaker mode to prevent clients from waiting unnecessarily for unresponsive services. If the service’s error rate exceeds the specified threshold, Hystrix will trip and all requests will fail immediately within the specified time. Hystrix allows you to define fallback operations when a request fails, such as reading from the cache or returning default values. If you are using the JVM, you should definitely consider using Hystrix. If you are running in a non-JVM environment, you should use a library with the same role.
2.6,
For most microservices-based applications, it makes sense to implement an API gateway that acts as a single entry point to the system and is responsible for request routing, composition, and protocol transformation. It provides a custom API for each application client. API gateways can also mask back-end service failures by returning cached or default data. In the next chapter, we’ll cover communication between services.
Microservices: NGINX Plus as an API gateway
by Floyd Smith
This chapter discusses how an API gateway can act as a single entry point to a system. It handles other functions such as load balancing, caching, monitoring, and protocol translation — NGINX can act as a single entry point to the system when acting as a reverse proxy server, and supports all the additional functions mentioned in an API gateway. So hosts that use NGINX as an API gateway work just fine.
NGINX as an API gateway was not the original idea of the book. NGINX Plus is the leading platform for managing and protecting HTTP-based API traffic. You can implement your own API gateway or use existing API management platforms, many of which use NGINX.
Reasons to use NGINX Plus as an API gateway include:
- Access management – From the typical Web application level down to every individual microservice level, you can use a variety of access control list (ACL) methods and easily implement SSL/TLS.
- Manageability and resiliency – You can use NGINX’s dynamic reconfiguration APIS, Lua modules, Perl to update NGINX Plus-based API servers, or Chef, Puppet, ZooKeeper, or DNS to make changes.
- Integration with third Party Tools – NGINX Plus can already be integrated with some advanced tools such as the 3Scale, Kong and MuleSoft integration platforms (just to name the tools mentioned on the NGINX website).
NGINX Plus is widely used as an API gateway in the NGINX Microservices reference architecture. Use the articles collected here as well as MRA (Microservices Reference Architecture) to learn how to do this in your own applications.