Monday, November 26, 2018

JTD-DesignerSeries-15-Micorservices-101


A brief Context
Past decade is about SOA architectures, SOAP protocol which provided a standard way of platform neutral communication between applications in an enterprise environment. SOA services are usually deployed as application packages on application servers running on VMs, but SOA business & architectures initiatives evolved to support reusability, composability, portability, service discovery etc.

Cloud computing, container based docker support, Restful Architecture & Tooling & success stories like Netflix, are suggesting to design application features as small autonomous deployable containers that can be created, destroyed, scaled independently. This approach of dividing monoliths into small services, or creating platforms backed by 1000s of small services working together, improved & released iteratively with CI/CD can be defined as Microservices.

Enterprises are getting several benefits by adopting microservices & cloud computing like cost, time to market, automation but there is a significant design challenges & management complexity that has to be embraced along with it.

Heroku suggested 12-factor app design practices for cloud native applications, which can constrain architects & developers to Microservices architecture.


12-Factor App Methodology
Apps developed with 12-Factor design generally employs immutable infrastructure [containers rather than VMs], ephemeral applications [non-persistent, can be deleted or restarted], declarative setup [IAAS, Deployments with desired state], and automation at scale [fault-tolerance, auto-scaling, self-healing] and are considered more scalable, maintainable, portable.

I. Codebase
It suggests that you should use version control in proper way, just to say that a single repository per application. In a literal sense, you shouldn't entangle the commits across application to maintain clean isolation at source code level.

II. Dependencies
It is more likely that modules / or services will have dependencies, but a suggested approach to explicitly declared in a pom.xml [Java / Maven] or package.json [NodeJS]. Jars / or node modules shouldn't be checked into code repositories & manually included in the application.

III. Config
Configuration are things that changes between environments like DB URLs, credentials should not be part of the code, rather defined as config strings in properties file and the runtime environment provides values to these config variables.

IV. Backing Services
Consider things like Postgres DB, Redis as attachable resources, and one of the pattern is to treat these resources as external resources, maybe use a CName to map the DB URL, and for sure use config vars that gets URL from the runtime environment.

V. Build, Release, Run
As you push code to the repository, build process should create a single artifact [jar with mvn install, container with docker build], which then picks up the environment specific configurations to create an deployable image. Once the release it tagged, runtime will run that application image [java -jar myApp.jar / node app.js]

VI. Processes
It is quite important that service design doesn't rely on application between restarts, rather have the application pull the current state from persisted storage like Redis or DB like MongoDB.

VII. Port Binding
Traditional application deployment rely on server container for request routing which means that request are received at a specific listener on the server, but in modern application development, port mapping is managed as a service inside the application itself.

VIII. Concurrency
It may help to design the application as processes that may scale out easily depending upon the availability of worker nodes, rather than just always scaling up during peak loads.

IX. Disposability
This refers to a fast startup, responsive service with a graceful shutdown. Microservices are treated more as cattle, pay as you need them with cloud resources and are not really pets as the application servers have been over last decade.

X. Dev/Prod Parity
This principle is quite important as it advocates that the app dev environment is same as your app prod environment along with other envs in between. As all the code & dependencies is packaged in a same image that runs everywhere, it solves the problem of that it worked on my machine.

XI. Logs
It suggests that keeping the logging process separate from application processes and treat logs as events.

XII. Admin Processes
One-time admin tasks like migrating DBs, generating reports should be run just like other application processes as containers etc.


Guiding Principles in Microservices Architecture
It will be nice to have some high level overarching principles that you can rely on while designing your small autonomous microservices. Sam Newman explained quite well in conferences and it is worthwhile to make some notes out of it.


I. Modelled around Business Domain
It helps to design microservice for each feature / capability of a platform / or application. Instead of designing services in horizontal layers like system, process, UI; it is better to design across vertical business layer.

II. Culture of Automation
As there is large number of deployable units, automation is way to manage containers at scale. It is quite important that to enable small teams that provision their infrastructure, manage & operate their service. Org should adopt CI/CD tools to automate deployments & releases as much as possible.

III. Hide Implementation Details
In microservice architecture, service design will also define the bounded context and API layer will manage the exposed data rather than multiple services hitting the same objects / or tables.

IV. Decentralize All the Things
It is about service teams making their own smart decisions, and sharing best practices without centralized governance, and keeping messaging & middleware as dumb pipes business context creeping into gateway services.

IV. Deploy Independently
This directly relates to deployable dependencies and whether the service is running on VM / or as a container image. In SOA ecosystem, developer can develop independently but have to wait for scheduled deployment & releases, and a progressive approach is developed to reduce dependencies while evolving towards microservice architectures. You also want to run

IV. Consumer First
It is about getting feedback as you develop your APIs, and in the SOAP driven webservices, there is a WSDL document which is a spec driven way of telling about how to use your service. Similarly there are API documentation tools like Swagger & registries that provides a way of calling & discovering the service to your consumers.

IV. Isolate Failure
As you design many microservices, you have to think about how not to fail the application when a service fails to accept request or brought down. Pattern like circuit breaker, appropriate timeouts helps increase the resiliency of your application.

IV. Highly Observable
It is about understanding your deployed system, monitoring it as it runs & providing a faster & easier way to troubleshoot issues. It is suggested to have a log aggregation system which collects logs from all your services & provides some kind of query framework against the aggregated logs. Another design approach is to create a correlationID that traverses along the path of transaction & can provide a runtime view of the service model.

No comments:

Post a Comment