Designing and running microservices
Microservices collaborate with each other through technology-agnostic messaging protocols,either point to point or asynchronously
Gather together the things that change for the same reasons. Separate those things that change for different reasons. Robert C. Martin’s Single Responsibility Principle is a useful way to consider the former:
The Art of Scalability
Monolithic applications typically scale through horizontal duplication: deploying multiple, identical instances of the application. This is also known as cookie-cutter, or X-axis, scaling. Conversely, microservice applications are an example of Y-axis scaling, where you decompose a system to address the unique scaling needs of different functionality. The Z axis refers to horizontal data partitions: sharding. You can apply sharding to either approach— microservices or monolithic applications—but we won’t be exploring that topic in this book.
- Scoping and identifying microservices requires substantial domain knowledge
- The right boundaries and contracts between services are difficult to identify and ， once you‘re established them， can be time-consuming to change.
- Microservices are distributed system and therefore require different assumptions to be made about state，consistency, and network reliability.
- By distributing system components across networks, and increasing technical heterogeneity, microservices introduce new modes of failure.
- It’s more challenging to understand and verify what should happen in normal operation.
- Once the application is distributed—where the application’s underlying state data is spread across a multitude of places—consistency becomes challenging .It won't ve possible to maintain ACID -like transactional guarantees of the order of operations.
- Rather than eliminating risk, microservices move that cost to later in the lifecycle of your system: reducing friction in development but increasing the complexity of how you deploy, verify, and observe your application in operation. When something goes wrong , you need to have some way of tracing how the system did behave,but you also need some way of knowing how the system should've behaved.
- Design for failure / design for avoid failure
Microservice Development Lifecycle
- Migrate form monolith or strat fresh
- Async vs sync
- implement CD pipelines
- standardize microservices deployment artifacts
- You want to proactively identify and refactor fragile implementation in your system.
- You need to understand how your system is behaving.
IDENTIFY AND REFACTOR POTENTIALLY FRAGILE IMPLEMENTATION
UNDERSTAND BEHAVIOR ACROSS HUNDREDS OF SERVICES
- business metrics,application logs, operational metrics, and infrastructure metrics - that make that capability obserable
- Reliability—Is your service available and error free? Can you rely on your deployment process to push out new features without introducing instability or defects?
- Scalability—Do you understand the resource and capacity needs of a service? How will you maintain responsiveness under load?
- Transparency—Can you observe a service in operation through logs and metrics? If something goes wrong, is someone notified?
- Fault tolerance—Have you mitigated single points of failure? How do you cope with the failure of other service dependencies?
Architecture of microservice application
Think of it like a city: building a monolith is like building a skyscraper; whereas building a microservice application is like building a neighborhood: you need to build infrastructure (plumbing, roads, cables) and plan for growth (zone for small businesses versus houses). 很形象生动
To achieve these things, an artchitect should guide development in two ways:
- Principles - Guidelines that the team should follow to achieve higher level technical or organizational goals
- Conceptual models - High-level models of system relationships and application-level patterns
four tiers of a microservice application
- boundary - entrypoint、aggregation
- business and technical capabilities
- aggregation and higher order services
- services on critical and noncritical paths
use synchronous drawbacks
- They create tighter coupling between services, as services must be aware of their collaborators.
- They block code execution while waiting on responses. In a thread- or process-based server model, this can exhaust capacity and trigger cascading failures.
- Overuse of synchronous messages can build deep dependency chains, which increases the overall fragility of a call path. 构建了深度依赖的关系链
when to use asynchronous messages
Kafka specializes in high-volume, replayable event storage, whereas RabbitMQ provides higher level messaging middleware (based on the AMQP protocol (https://www.amqp.org/)).
asynchronous communication patterns
- job queue : winner takes all, Redis|Resque|Celery|Sidekiq
The boundary layer also may implement other client-facing capabilities:
- Authentication and authorization—To verify the identity and claims of an API client
- Rate limiting—To provide defense against client abuse
- Caching—To reduce overall load on the backend
- Collect logs and metrics—To allow analysis and monitoring of client requests
Develope new feature microservices
Design in for stages
- Understanding the business problem，use cases, and potential solution
- Identifying the different entities and business capabilities your service should support
- Scoping services that are responsible for those capabilities
- Validating your design against current and potenttial future requirements
If you scope services by use case, you might find yourself writing services that explicitly orchestrate the behavior of several other services. This isn’t always ideal:
Orchestration can increase coupling between services and increase the risk of dependent deployments.
Underlying services can become anemic and lack purpose, as the orchestrating service takes on more and more responsibility for useful business output.
Transactions in microservices
In case of an error, or if you need to debug a distributed system, the monitoring and tracing capabilities act as a flight recorder.
Although sagas rely heavily on compensating actions, they’re not the only approach you might use to achieve consistency in service interactions. So far, we’ve encountered two patterns for dealing with failure: compensating actions (refund my coffee payment) and retries (try to make the coffee again). Table 5.1 outlines other strategies.
You should focus on four golden signals while collecting metrics from any user-facing system:latency, errors, traffic, and saturation
types of metrics
- counters 累计度量
- Number of requests
- Number of errors
- number of eah code received
- Bytes transmitted
- gauges 可以上升下降会变化的值
- number of connections to a database
- memory used
- cpu used
- load average
- Number of services operating abnormally
- Latency of a request
- I/O latency
- Bytes per response
logs and traces
useful information to include in log entries
- class or module
- level or category