Saturday, December 30, 2017

Some notes on microservice design

The key to design a cloud native platform is the microservice architecture. I was investigating some of the microserice architecture for my work, and here're some of my notes with my thinkings and understandings.

- Service Scoping:
We need to decide how much functionalities to fit into one service. There can be several considerations: a) Partition the services along logical function lines. A function unit called by many others should be wrapped as its own. b) Mirror the business logic, each logic unit is a service. c) 2-week rule: a service could be re-implemented by the team in a two-week period. In general the services are loosely coupled and updated independently, by doing a separate build for each of them.

In case of rewriting a working service, it's also suggested to keep the old one, while iterating on the design and testing of the new one till it's stable.

- API:
Typically services are exposed through REST APIs. Individual services should be able to reliably send and receive data, and should be tested thoroughly beforehand. One big challenge is to maintain API stable and forward compatible across different versions, which requires careful design.

- Traffic management
Calling and called services need to communicate status and coordinate traffic loads. Calls should be tracked, responses delays be monitored, and services be redirected under backpressure. Service instances should support auto scaling w.r.t.  service loads.

- Data Store
It's recommended to create a separate data store for each microservice. The challenge is how to maintain data consistency across these data stores. On the other hand, overall service must be available despite individual service might be transient. This requires to migrate user-specific data off of service instances and into a shared, redundant storage system that's accessible from all service instances, in case of user session failure. Suggested solution is to insert a shared, memory-based cache system between a given service and the storage associated with that service. The caching system becomes another service itself.

- Deploying
It's suggested to deploy microservices in containers as one tool can deploy everything. Also treat the servers as stateless, and replace it when one failed, and use autoscaling to adjust the numbers up and down according to the needs.

- Monitoring
The monitoring system for a microservices-based application must allow for ongoing resource change, be able to capture monitoring data in a central location, and display information that reflects the frequently changing nature of microservices applications. As an end-user action triggers application work, API calls and service work cascade down the application topology, and a single action may result in tens, or hundreds, of monitorable events. Most microservices monitoring systems place a monitoring agent on each service instance, where it can track specific instance data.

In order to handle the incredibly complex and massive amount of service-to-service communication, the most recent approach is to add a service mesh layer, to reliably deliver request. Check the open sourced Linkerd and Istio project. It's worth mentioning that it also fits the nature of serverless computing.

Refs:
https://techbeacon.com/5-fundamentals-successful-microservice-design
https://www.nginx.com/blog/microservices-at-netflix-architectural-best-practices/
https://buoyant.io/2017/04/25/whats-a-service-mesh-and-why-do-i-need-one/
https://blog.envoyproxy.io/service-mesh-data-plane-vs-control-plane-2774e720f7fc