Microservices architecture is now a must-talk topic when it comes to enterprise application architecture. Microservices are also popular because they have many advantages compared to previous application development methods, such as being more flexible and better able to adapt to the current environment of rapidly changing requirements.
First, the concept of microservices
Microservices architecture consists of a lightweight, loosely coupled collection of services. Each service implements a single business function. Ideally, these services should be cohesive enough to be independently developed, tested, published, deployed, extended, integrated, and maintained.
A formal definition
“The microservices architecture style is a way of developing a single application as a set of small services, each running in its own process and communicating with a lightweight mechanism (usually HTTP REST apis). These services are built around business capabilities and can be deployed independently by a fully automated deployment organization. These services are minimally managed centrally and can be written in different programming languages and use different data storage technologies.”
— James Lewis and Martin Fowler
Define the characteristics of microservices
Each service is a lightweight, independent, and loosely coupled business unit.
Each service has its own code base, managed and developed by a small team (primarily for agile environments).
Each service takes care of a portion of the functionality or business capability and does it well.
Each service can choose the best technology stack for its use case (without tying the entire application into a framework).
Each service has its own DevOps schedule (testing, release, deployment, expansion, integration, and independent maintenance).
Each service is deployed in a separate, self-contained environment.
Services communicate with each other using well-defined apis (smart endpoints) and simple protocols such as HTTP-based REST protocols (dumb pipes).
Each service is responsible for persisting its own data and maintaining external state (this is only handled in the common data layer if multiple services use the same data).
Small white: white
Smart endpoints and dumb pipes, in fact I always thought “dumb” pipes were not as easy to understand as “dumb” or “dumb” pipes. Anti-dull design is a design concept to prevent bad consequences caused by users’ wrong use of the product. For example, HALF of USB is designed with solid chip, so that users can directly turn around and plug in the wrong way without thinking. Don’t let the user think is “stupid” meaning. “Dumb” pipe “dumb” is embodied in the communication process of micro service as simple as possible, don’t let the communication mechanism is “thinking”, is not one of them to join too much handling mechanism, counterexample is the era of SOA ESB products, ESB products usually contain complex facilities used for message routing, and transformation, and business rules. , in turn, would be easy to understand the concept of intelligent terminal, also is associated with a particular service processing are confined within the category of micro service, micro service endpoint as a “smart” in the process of communication, it also reflects the micro service from the aspects of a “high cohesion” meaning, have high cohesion, can have the autonomy and independence, which can support the mechanism of “loose coupling”.
Benefits of microservices
Microservices can be used to scale large systems and also provide great capabilities for continuous integration and delivery.
Scaling independently: The Art of Scalability (t.cn/EAvlQ4o) this excellent book… The Cube concept is supported by the microservices architecture. When microservices are developed for functional decomposition, applications scale automatically along the Y-axis. When service calls are high, microservices can scale along the X-axis by cloning more CPUS and memory. To distribute data across multiple machines, it is possible to scale the Z-axis by separating large databases (sub-databases and sub-tables) into smaller, faster, and more manageable parts.
Independent publishing and deployment: With microservices, Bug fixes and feature publishing are easier to manage and less risky. Services can be updated without redeploying the entire application, and updates can be rolled back or forward if problems occur.
Independent development: Each service has its own code base, developed, tested, and deployed by a small focus group. Developers can focus on one service and focus on a relatively small scope. This will improve productivity, project speed, continuous innovation, and source quality.
Graceful degradation: If a service crashes, the impact does not spread to other parts of the application and cause a catastrophic failure of the system, thereby providing some degree of robustness.
Decentralized governance: Developers are free to choose technology stacks and make design criteria and implementation decisions that best fit their services. Teams don’t have to be penalized for past technical decisions.
Business concerns
Individual services do not form a system by themselves. For microservices architectures to be truly successful, significant investments are needed to address cross-system issues such as:
Service replication: A metadata-based mechanism for making services easily extensible
Service registration and discovery: Enables the mechanism for services to find and find service endpoints
Service monitoring and logging: Mechanisms to collect logs from different microservices and provide consistent reporting
Resilience: The mechanism by which a service automatically takes corrective action during a failure
DevOps: Mechanisms for handling continuous integration and deployment (CI and CD)
API gateway: A mechanism that provides an entry point for clients
Middleware and design patterns
API Gateway (single entry point for all clients)
Api-gateway-style microservices architecture (image from Microsoft Azure Docs) is the most common design pattern used for microservices. The API gateway is an intermediate layer with minimal routing functionality that acts as a “dumb pipe” with no business logic in it. In general, API gateways allow clients to invoke managed apis based on REST/HTTP. Other types of microservice integration patterns are: point-to-point style (calling services directly from client applications) and message broker style (enabling asynchronous messaging).
Acting as a single point of entry for all clients, THE API gateway also acts as an edge service to expose microservices as hosted apis to the outside world. This may sound like a reverse proxy, but there are some additional responsibilities such as simple load balancing, authentication and authorization, troubleshooting, auditing, protocol transformation, and routing mechanisms. The development team can choose to implement the API gateway in one of the following ways.
Self programming: with better ability of customization and control.
Deploy existing API gateway products: Save initial development time and use advanced built-in features (downside: such products are vendor-dependent and not entirely free). Configuration and maintenance are often lengthy and time consuming.)
Some of the design patterns that explain API gateway behavior are as follows (see microservice design Patterns t.cn/RKx8bhG).
Gateway Aggregation (t.cn/EAvT2jl) : Pin…
Gateway shunting (t.cn/EAvTGmA) : Enables single…
Gateway routing (Layer 7 routing, typically HTTP requests t.cn/EAvTMm4) : uses…
Note that the API gateway should always be a high-availability and high-performance component, as it is the entry point to the entire system.
Event bus (publish/subscribe, mediation channel for asynchronous event-driven communication)
Event-driven asynchronous communication between microservices achieves final consistency
(Photo: Microsoft.com)
The event bus can be used when different parts of an application communicate with each other, regardless of the order of messages (for processing asynchronous messages) or the language used (for language independence). Most event buses support publish/subscribe, distributed, point-to-point, and request response messaging. Some event buses (like vert.x) allow clients to use the same event bus to communicate with corresponding server nodes, a cool feature that the full stack team loves.
Service Grid (Sidecar mechanism for communication between services)
Service grid-style communication between services
(Image credit: Microservices Practice http://t.cn/EAAJWRi)
How do I use the service grid in my application
(Photo credit: t.cn/EAAizgn)
The service grid implements the plug-in mode by providing an auxiliary architecture for communication between services, including resiliency (fault tolerance, load balancing), service discovery, routing, observability, security, access control, communication protocol support and other functions.
Location of the service grid in the network stack
(Photo credit: t.cn/EAAizgn)
In effect, a plug-in instance is deployed next to each service (ideally in the same container). They can communicate through the network capabilities of the service itself. The control plane of the service grid is deployed separately to provide central functions such as service discovery, access control, and observability (monitoring, distributed logging). Most importantly, the service grid style design pattern allows developers to separate network communication functions from microservice code and focus services solely on business functions. (From: Netflix Prana, Microservices Grid)
Although the picture above shows a direct connection between services, a good way to handle communication between services is to use a simple event bus as a mediator to maintain a minimal level of coupling.
Aggregator (BFF mode)
Implement the BFF pattern and aggregator pattern at the API gateway level
(Photo: Microsoft.com)
If an application needs to tailor each API to suit the type of client application (Web, mobile, and other different platforms), different business rules can be executed through aggregators, or different configurations can be performed to suit different builds based on client functionality. This can be done at the API gateway level or in parallel at the service level. This pattern is useful for providing a specific user experience. However, the development team should be careful to keep the BFF within manageable limits.
Small white: white
Through an aggregator, via a facade. Facade pattern (FACADE pattern) is a Java design pattern that provides a unified access interface for a set of interfaces in a subsystem. It is derived from a front store and back factory business model, with facade in front and feeding, production, and packaging services in the back. In this case, related services are aggregated together through an aggregator, which is the facade. Service the caller and facade interaction rather than with a group of service interaction reduces the coupling, but also violates the principle of object-oriented design principles of open and close, open closed principle requires module in an extension can not change the code, but obviously when the aggregator back end a service change, need to also change in aggregator level, This is why the article states that “development teams should be careful” because violating the open close principle reduces reusability.
Best practices
✅ Domain-driven design: Services are modeled around business domains.
To handle large models and teams, domain-driven design (DDD) can be applied. DDD defines the interrelationships and subdomains of large models by dividing them into different bounded contexts. These bounded contexts can be transformed into individual microservices at the application design level. (See: Bounded context in Domain-driven Design t.cn/EAAK4Xk)
✅ Decentralized data management (avoiding shared databases) : When multiple services use a shared data architecture, there is tight coupling at the data layer. To avoid this, each service should have its own data access logic and separate data stores. The development team is free to choose the most appropriate data persistence approach depending on the nature of the service and data.
Avoid shared data stores and access mechanisms
(Photo credit: t.cn/RcLB5Kv)
✅ Smart endpoints and dumb pipes: Each service has a well-defined external communication API and tries to avoid giving away implementation details. Communication always uses simple protocols, such as THE HTTP-based REST protocol.
✅ Asynchronous communication: When asynchronous communication is used across services, other services do not block the data flow.
Synchronous and asynchronous messaging
(Source: t.cn/EAA9xRU)
✅ Avoid service coupling: Services should remain loosely coupled and highly cohesive. The main reasons for coupling include shared database models and strict communication protocols.
✅ Decentralized development: Avoid sharing code bases, data architectures, or development team members across multiple services/projects. Let developers focus on innovation and quality from the source.
✅ Keep domain knowledge out of the gateway: let the gateway handle routing and cross-service issues (such as authentication, SSL terminals, and so on).
✅ token-based authentication: Do not implement security components at every microservice level, as this would require components to talk to a centralized/shared user repository and retrieve authentication information; Instead, consider implementing API gateway-level authentication using widely used API security standards such as OAuth2 and OpenID Connect. Once a token is obtained from an authentication provider, it can be used to communicate with other microservices.
Microservice security using OAuth2 and OpenID Connect
(Credit: Kasun’s Blog t.cn/EAACGvY)
✅ event-driven nature: Since humans can be autonomous agents responding to events, so can systems. (See: Why Microservices should be Event-driven: Autonomy and Authority t.cn/EAACWOx)
✅ Final consistency: Due to the highly cohesive nature of microservices, it is difficult to achieve strong consistency across the system. So the development team must deal with final consistency.
✅ fault tolerance: Because the system consists of multiple services and middleware, it can be vulnerable to failure in some places. For these vulnerabilities, there are implementation patterns such as circuit breakers, watertight pods, retry, timeout, fast failure, failover caching, rate limiting, and load release that can minimize the risk of major failures. (See: Designing a failure-oriented microservice Architecture http://t.cn/RChKlg9)
✅ Product engineering: Engineering microservices as a product, not as a project, can make microservices play a better role. This means not just thinking about usability and timely delivery, but a long-term commitment to engineering excellence.
4. Micro-service practice
When to use microservices
Microservices architecture is most suitable for the following application scenarios:
Applications with high scalability requirements
Projects requiring high speed of delivery
Business use cases with rich domains or multiple subdomains
Agile environments where small, cross-functional development teams collaborate to develop large products (see: True success stories of microservices Architecture t.cn/EAANng7)
Some introductory frameworks for implementing microservices
Vert. X: Lightweight, easy to understand/implement/maintain, multi-language support (support multiple languages), event driven, non-blocking, so to speak, with the high concurrency with minimal hardware processing requirements of the best performance and scalability, and have enough openness (unlike traditional restrictive framework, Vert. X only provides useful components, Developers are free to innovate and carefully build their applications)
Akka: Satisfactory performance that implements the Actor model (a concurrency model) for responsive and event-driven microservices
Spring Boot/Spring Cloud: Easy to get started (familiar paradigm), based on a good old Spring framework, a bit heavy framework, lots of integrations available, massive community support
Drop the Wizard: It makes for fast development of RESTful Web services, and it comes with some great Java tools and libraries such as Google Guava, Jetty Server, Logback, Hibernate Validator, Joda Time, Jersey, and Jackson.
Deployment options
Containers: Facilitate DevOps goals (rapid development, reduced time to market, seamless scaling)
Cloud computing architecture: It facilitates building reliable and scalable infrastructures that serve geographically dispersed users.
Serverless architecture: Suitable for handling highly volatile traffic.
Maintain your OWN IT infrastructure: This is a good thing for organizations that have the capacity and resources to build their entire infrastructure.
The development concept of microservices
Self-contained systems: Software assembled from independent systems (vertically shard systems by business)
Microfrontend: The Web UI of a single application is divided into separate features that can be developed as separate UI components and communicate directly with microservices.
Keywords to search and learn
Domain driven design (DDD) (BC) | | bounded context polymerization persistence (PP) | command and query responsibility isolation (CQRS) | query separation (CQS) | event source (ES) | | end CAP theorem consistency twelve elements application | | | SOLID principles
5. Reference framework
Microservice architecture for online shopping applications
(Photo: Microsoft.com)
This architecture was developed by Microsoft developers using Microsoft technologies. Here, the API Gateway is customized for different Web and mobile users. For the data layer, data storage technologies are carefully selected based on business capabilities (relational databases for structured data, Redis for temporary data caching, MongoDB and Cosmos DB for unstructured data). The event bus handles communication between services. Technology aside, this is the most common integration pattern for microservices-based applications.
A microservice architecture for a non-blocking application that uses a large stream of input data from a variety of event sources (such as traffic data, weather indices, stock market cues, social media posts, sensor output) to show real-time updates to end users. These input streams are initially collected by event logs implemented using Kafka. It keeps data on disk, so it can be used for batch calls (analysis, reporting, data science, backup, auditing) or for real-time calls (operations analysis, CEP, administrative dashboards, alert applications). In the figure above, Spark is used to divide a continuous stream of input data into microbatches at specified intervals and input them into the WSO2 Siddhi CEP engine. The latter identifies events and uses MongoDB stores to store data in an unstructured form. Microservices retrieves this data and displays it to the end user. Looking closely at this design, the vert.x event bus is able to create connections to the front-end UI components, a feature that is only used to effectively update relevant parts of the UI. Technology aside, this is a great architecture for event-driven, non-blocking microservice applications.
For order management application of cloud native flood channel micro service architecture (photo: ibm.com) is a major feature of this design is that IBM architects don’t use the API gateway, but for each client channel (mobile applications, Web applications, IOT device, API user) proposed a independent backend edge layer. Another feature is that the microservices layer is divided into two sub-layers: the business logic layer and the base layer. The base layer (the core services layer) handles persistence and integration tasks using a variety of cloud native services (cloud data storage, integration, and Elastic search engine for indexing Watson sessions). The business logic layer integrates data from the base layer and provides meaningful business functionality. This would be a good architecture for serving a large, geographically dispersed user base and accessing applications across a variety of platforms.