Cloud-native microservices
Cloud-native is an industry-wide methodology that enables companies to rapidly develop and deploy applications with more flexible scaling options by taking full advantage of the power of cloud computing. Cloud-native applications are microservices-oriented, containerized, and dynamically orchestrated to optimize the use of resources.
Cloud-native applications have common characteristics:
Cloud-native applications adapt microservice architecture where each application is a collection of small services that can be operated independently of each other.
Microservices are owned by individual development teams, which operate autonomously to develop, deploy, scale, and upgrade the microservices.
Cloud-native applications are packaged into containers. Containers provide isolation contexts for microservices. They are highly accessible, scalable, and easily portable from one environment to another. They also are fast to create or tear down, which makes them ideal for building and running applications composed of microservices.
Cloud-native applications are developed by using a continuous delivery model.
How to design cloud-native applications:
Follow the twelve-factor application methodology.
Break applications down into smaller chunks as microservices, so that you can easily deploy them independently.
Use API-based design to ensure every microservice has APIs so that it can easily communicate with other microservices.
Use self-service agile infrastructure so that it can be scaled up or down.
Design fault-tolerant applications that are resilient enough to handle failure, making them robust.
What are microservices?
Microservices describe an architecture in which applications are modularized and split into a set of lightweight, independent services that are each built to provide one functionality and to be developed, deployed, and updated independently without affecting other services in the application. RESTful microservices communicate with each other by using the remote access protocol Representational State Transfer (REST).
Microservices are independent. Each microservice has its own codebase and is owned by a relatively small development team. It has clear API boundaries that give the team that is developing the service flexibility to evolve the implementation.
Microservices must be resilient. Application stability depends on individual microservices being robust enough to handle failures. This stability is a big difference from traditional architectures, where the supporting infrastructure handles failures for you. Each service needs to apply isolation patterns, such as circuit breakers and bulkheads, to contain failures and define appropriate fallback behaviors to protect upstream services.
Microservices are stateless, transient processes. The state should be stored in external backing cloud services, like Redis, rather than in-memory. Fast startup and graceful shutdown behavior further allow microservices to work well in automated environments that create and destroy instances in response to load or to maintain system health.
The twelve-factor methodology: why use it?
The best practice for developing cloud-native applications is the twelve-factor application methodology, which was drafted by developers at Heroku. These guidelines are created for building portable, scalable, and resilient applications that thrive in cloud environments, specifically Software as a Service (SaaS) applications. The twelve-factor methodology can be applied to applications written in any programming language and can use any combination of backing services, such as databases, queues, memory caches, and so on.
The twelve factors are:
Codebase: Each microservice should have a separate repository so that it can evolve on its own.
Dependencies: Each microservice has its own dependencies declared. Libraries are not packaged inside the application.
Configuration: Store configuration in the environment and externalize your configuration.
Backing services: Treat backing services, such as MySQL, Amazon S3, and Twitter, as attached resources.
Build, release, run: Strictly separate build and run stages.
Processes: Treat processes as RESTful APIs. They should be stateless and share nothing so that they can scale up and down easily without losing data.
Port binding: Export services using port binding. The ports should never be hard-coded and should always be configurable.
Concurrency: Applications use processes independently from each other to allow for load balancing.
Disposability: Maximize robustness with fast startup and graceful shutdown.
Development and production parity: Keep development, staging, and production as similar as possible.
Logs: Treat logs as event streams.
Admin processes: Run administrative and management tasks as one-off processes and package them alongside the application.
How does MicroProfile help you create microservices?
MicroProfile is a set of specifications that was created by the open source community to help developers write cloud-native Java™ microservices. MicroProfile has a set of Java APIs that bind the lifecycle of stateful components to well-defined contexts and inject components into an application in a typesafe way through contexts and dependency injection (CDI).
With MicroProfile, you can create twelve-factor microservices with consideration for the factors of configuration (factor 3), port binding (factor 7), and disposability (factor 9). Two of the most important MicroProfile features that provide you these capabilities are MicroProfile Config and MicroProfile Fault Tolerance.
MicroProfile Config can be used to inject external configuration properties into microservices so that changing the configuration does not require you to repackage your application. It provides two APIs. One is a programmatic API, and the other is through CDI injection. Through CDI injection, you can directly inject either static or dynamic values. Keep in mind that all the configuration sources are prioritized. If the same property is in multiple configuration sources, the one with the highest priority is used by the application. MicroProfile Config helps you fulfill the externalizing configuration and port binding requirements in the twelve-factor methodology. It provide the ability to inject the configuration properties into the microservices, and the ability to inject ports into microservices when one microservice calls another microservice in a chain.
MicroProfile Fault Tolerance is a solution to build a resilient microservice. It provides a way for microservices to retry during failure, prevent repeated failures, limit microservices to use all system resources, timeout when waiting for responses, and fallback resolution after everything fails. MicroProfile Fault Tolerance enables you to implement applications that can shut down gracefully when failure exists, which is part of the disposability requirement of the twelve-factor methodology.
By using MicroProfile together with containers and Kubernetes, developers can easily create and manage twelve-factor microservices.