Microservice Patterns Flashcards

1
Q

What kind of 5 categories of Microservice patterns do you know?

A

1) Decomposition pattern
2) Integration Patterns
3) Database Patterns
4) Observability patterns
5) Cross-Cutting Concern Patterns

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What are the steps for defining an application’s microservice architecture?

A

[1] IDENTIFY SYSTEM OPERATIONS
Describe Functional requirements:
“As a consumer I want to place an order so that I can …”

[2] IDENTIFY SERVICES
There are different strategies.
a) define services corresponding to business capabilities
b) Organize services around domain-driven-design
eg:
OrderService, KitchenService, RestaurantService …

[3] Define Service APIs and collaborations
a) OrderService “talks” with RestaurantService to check if ordered product exist
OrderService ——> (verifyOrder) —-> RestaurantService

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What are the obstacles to decomposition?

A

[1] NETWORK LATENCY
You might discover that a particular decomposition would be impractical due to too many round-trips between services

[2] REDUCED AVAILABILITY
synchronous communication between services reduces availability

[3] DATA CONSITENCY
The third obstacle is the requirement to maintain data consistency across services. You’ll typically need to use sagas

[4] Obtaining consistent view of the data

[5] God classes preventing decomposition

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is the difference between Decompose by business Capability and by Subdomain?

A

[1] Decompose by Business Capability
Problem: Microservices is all about making services loosely coupled and applying the single responsibility principle. However, breaking an application into smaller pieces has to be done logically. How do we decompose an application into small services?

Solution: One strategy is to decompose by business capability. A business capability is something that a business does in order to generate value. The set of capabilities for a given business depend on the type of business. For example, the capabilities of an insurance company typically include sales, marketing, underwriting, claims processing, billing, compliance, etc. Each business capability can be thought of as a service, except it’s business-oriented rather than technical.

[2] Decompose by Subdomain
Problem: Decomposing an application using business capabilities might be a good start, but you will come across so-called “God Classes” which will not be easy to decompose. These classes will be common among multiple services. For example, the Order class will be used in Order Management, Order Taking, Order Delivery, etc. How do we decompose them?

Solution: For the “God Classes” issue, DDD (Domain-Driven Design) comes to the rescue. It uses subdomains and bounded context concepts to solve this problem. DDD breaks the whole domain model created for the enterprise into subdomains. Each subdomain will have a model, and the scope of that model will be called the bounded context. Each microservice will be developed around the bounded context.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What is “Common Closure Principle” and how does it help to design microservices?

A

The idea is that if two classes change in lockstep because of the same underlying reason, then they belong in the same package. Perhaps, for example, those classes implement a different aspect of a particular business rule. The goal is that when that business rule changes, developers only need to change code in a small number of packages (ideally only one). Adhering to the CCP significantly improves the maintainability of an application.

We can apply CCP when creating a microservice architecture and package components that change for the same reason into the same service. Doing this will minimize the number of services that need to be changed and deployed when some requirement changes. Ideally, a change will only affect a single team and a single service. CCP is the antidote to the distributed monolith anti-pattern.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What is the Network latency problem and how to solve it?

A

Network latency is an ever-present concern in a distributed system. You might discover that a particular decomposition into services results in a large number of round-trips between two services. Sometimes, you can reduce the latency to an acceptable amount by implementing a batch API for fetching multiple objects in a single round trip. But in other situations, the solution is to combine services, replacing expensive IPC with language-level method or function calls.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

How to solve the problem of reduced availability of microservices when using synchronous communication?

A

Instead of using synchronous communication like REST use asynchronous communication.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

How to solve the problem of data consistency across services?

A

The solution is to use the SAGA pattern.

Another challenge is maintaining data consistency across services. Some system operations need to update data in multiple services. For example, when a restaurant accepts an order, updates must occur in both the Kitchen Service and the Delivery Service. The Kitchen Service changes the status of the Ticket. The Delivery Service schedules delivery of the order. Both of these updates must be done atomically.

The traditional solution is to use a two-phase, commit-based, distributed transaction management mechanism. But as you’ll see in chapter 4, this is not a good choice for modern applications, and you must use a very different approach to transaction management, a saga. A saga is a sequence of local transactions that are coordinated using messaging. Sagas are more complex than traditional ACID transactions but they work well in many situations. One limitation of sagas is that they are eventually consistent. If you need to update some data atomically, then it must reside within a single service, which can be an obstacle to decomposition.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

How to solve the problem of “not obtaining a consistent view of the data”?

A

Another obstacle to decomposition is the inability to obtain a truly consistent view of data across multiple databases. In a monolithic application, the properties of ACID transactions guarantee that a query will return a consistent view of the database. In contrast, in a microservice architecture, even though each service’s database is consistent, you can’t obtain a globally consistent view of the data. If you need a consistent view of some data, then it must reside in a single service, which can prevent decomposition. Fortunately, in practice, this is rarely a problem.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What are god classes and how God classes prevent decomposition?

A

A god class typically implements business logic for many different aspects of the application. It normally has a large number of fields mapped to a database table with many columns. Most applications have at least one of these classes, each representing a concept that’s central to the domain: accounts in banking, orders in e-commerce, policies in insurance, and so on. Because a god class bundles together state and behavior for many different aspects of an application, it’s an insurmountable obstacle to splitting any business logic that uses it into services.

[1] NOT OPTIMAL SOLUTION
One solution is to package the Order class into a library and create a central Order database. All services that process orders use this library and access the access database. The trouble with this approach is that it violates one of the key principles of the microservice architecture and results in undesirable, tight coupling. For example, any change to the Order schema requires the teams to update their code in lockstep.

[2] BETTER SOLUTION
A much better approach is to apply DDD and treat each service as a separate subdomain with its own domain model.
This means that each of the services in the FTGO application that has anything to do with orders has its own domain model with its version of the Order class.

A great example of the benefit of multiple domain models is the Delivery Service. Its view of an Order, shown in figure 2.11, is extremely simple: pickup address, pickup time, delivery address, and delivery time. Moreover, rather than call it an Order, the Delivery Service uses the more appropriate name of Delivery.

The Kitchen Service also has a much simpler view of an order. Its version of an Order is called a Ticket. As figure 2.12 shows, a Ticket simply consist of a status, the requestedDeliveryTime, a prepareByTime, and a list of line items that tell the restaurant what to prepare. It’s unconcerned with the consumer, payment, delivery, and so on.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What are client-service integration styles?

A

[1] Asynchronous and synchronous
[2] One-to-one (queuing); One-to-Many (Pub/Sub)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What are the two types of messages? Give examples.

A

1) text (JSON, XML, YAML)
2) binary (AVRO, Protocol Buffers)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What are the pros and cons of text-type messages?

A

PROS:
1) human readable
2) self describing

CONS:
1) the messages tend to be verbose, especially XML. Every message has the overhead of containing the names of the attributes in addition to their values.
2) the overhead of parsing text, especially when messages are large. Consequently, if efficiency and performance are important, you may want to consider using a binary format.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

What are the pros and cons of binary-type messages?

A

PROS:
a) smaller size than text-type messages

CONS:
a) format is binary so we can’t see the message if want to view what was actually sent

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What is the difference between Protocol Bufferes message type and AVRO?

A

One difference between these two binary formats is that Protocol Buffers uses tagged fields, whereas an Avro consumer needs to know the schema in order to interpret messages. As a result, handling API evolution is easier with Protocol Buffers than with Avro

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Describe The REST maturity model by Leonard Richardson.

A

Maturity model for REST:

LEVEL 0 - Clients of a level 0 service invoke the service by making HTTP POST requests to its sole URL endpoint. Each request specifies the action to perform, the target of the action (for example, the business object), and any parameters

LEVEL 1 - A level 1 service supports the idea of resources. To perform an action on a resource, a client makes a POST request that specifies the action to perform and any parameters.

LEVEL 2 - A level 2 service uses HTTP verbs to perform actions: GET to retrieve, POST to create, and PUT to update. The request query parameters and body, if any, specify the actions’ parameters. This enables services to use web infrastructure such as caching for GET requests.

LEVEL 3- The design of a level 3 service is based on the terribly named HATEOAS (Hypertext As The Engine Of Application State) principle. The basic idea is that the representation of a resource returned by a GET request contains links for performing actions on that resource.

17
Q

What are the benefits of REST?

A

1) Simple and familiar

2) You can test an HTTP API from within a browser using, for example, the Postman plugin, or from the command line using curl (assuming JSON or some other text format is used).

3) It directly supports request/response style communication.

4) It doesn’t require an intermediate broker, which simplifies the system’s architecture.

18
Q

What are the drawbacks of REST?

A

1) It only supports the request/response style of communication.

2) Reduced availability. Because the client and service communicate directly without an intermediary to buffer messages, they must both be running for the duration of the exchange.

3) Clients must know the locations (URLs) of the service instances(s). Clients must use “Client discovery mechanism”

4) Fetching multiple resources in a single request is challenging.

5) It’s sometimes difficult to map multiple update operations to HTTP verbs.

18
Q

What are the drawbacks of REST?

A

1) It only supports the request/response style of communication.

2) Reduced availability. Because the client and service communicate directly without an intermediary to buffer messages, they must both be running for the duration of the exchange.

3) Clients must know the locations (URLs) of the service instances(s). Clients must use “Client discovery mechanism”

4) Fetching multiple resources in a single request is challenging.

5) It’s sometimes difficult to map multiple update operations to HTTP verbs.

19
Q

How do you deploy a new version of some services (rest or messaging)?

A

. You usually can’t force all clients to upgrade in lockstep with the service. Also, because modern applications are usually never down for maintenance, you’ll typically perform a rolling upgrade of your service, so both old and new versions of a service will be running simultaneously.

YOU KEEP OLD VERSION, and deploy NEW ONE. Simeoltenously you have deployed to version and clients has time to change to new version.

20
Q

What is a Circuit breaker pattern? What kind of problem does it solve?

A

Track the number of successful and failed requests, and if the error rate exceeds some threshold, trip the circuit breaker so that further attempts fail immediately. A large number of requests failing suggests that the service is unavailable and that sending more requests is pointless. After a timeout period, the client should try again, and, if successful, close the circuit breaker.

In a distributed system, whenever a service makes a synchronous request to another service, there is an ever-present risk of partial failure. Because the client and the service are separate processes, a service may not be able to respond in a timely way to a client’s request

Because the client is blocked waiting for a response, the danger is that the failure could cascade to the client’s clients and so on and cause an outage.

21
Q

What kind of mechanism developer should use to design robust synchronous integration between services?

A

[1] Network timeouts
Never block indefinitely and always use timeouts when waiting for a response. Using timeouts ensures that resources are never tied up indefinitely.

[2] Limiting the number of outstanding requests from a client to a service.
Impose an upper bound on the number of outstanding requests that a client can make to a particular service. If the limit has been reached, it’s probably pointless to make additional requests, and those attempts should fail immediately.

[3] Circuit breaker pattern
Track the number of successful and failed requests, and if the error rate exceeds some threshold, trip the circuit breaker so that further attempts fail immediately. A large number of requests failing suggests that the service is unavailable and that sending more requests is pointless. After a timeout period, the client should try again, and, if successful, close the circuit breaker.

22
Q

What are the ways to recover from unavailable service?

A

[1] Return an error to the client
[2] Return default value or value from cache

23
Q

What is API Composition Pattern?

A

API Composition pattern solves the problem of querying data from multiple microservices that do not share a database.

In microservice architecture and design where each service has its own database, there is a problem with fetching data from many databases.

API Composition pattern solves this problem by loading data from many services and joining them in memory.

24
Q

How would you design a REST service in an e-commerce application which shows some report data from multiple, independent services? Let’s say, your report needs data from Order service, Delivery Service, and Stock Service.

A

I would use the API composition pattern to execute all services and in-memory join data.

When we want to invoke multiple services in order to load data and later join them, it may happen that some of the services may fail. In order to avoid frequent errors we can assume that It’s likely that each service’s data isn’t equally important to the client. So, we can design our API Composition service in partial failure that way:
a) The data from “Order Service” are critical, so in case of a failure of this service, I would return an error or cached data.
b) Data from other services are not critical and can be omitted. We can return some default/cache data or just return order data with the warning “data from Delivery service” was not loaded.

In general, It’s essential that you design your services to handle partial failure.

25
Q

What is the problem of unknown service addresses in microservice applications and how it can be solved?

A

In traditional applications, running on physical machines, machines have a static address. In microservices, it is not like that. Microservice applications are more dynamic. Service instances have dynamically assigned addresses because of autoscaling, failures, and upgrades.

The solution is Service discovery.
Service discovery is a component that uses a “service registry” to find addresses of available services. You can think of it as a database of service addresses. Service addresses in the service registry are added/removed from it when the application start/stops working.

When a client invokes a service, the service discovery mechanism queries the service registry to obtain a list of available service instances and routes the request to one of them.

26
Q

What are two ways of implementing a service discovery pattern?

A

1) The services and their clients interact directly with the service registry. - application-level service discovery (Example spring cloud)

2) The deployment infrastructure handles service discovery - platform-provided service discovery (Kubernetes)

27
Q

Describe application-level service discovery patterns.
What kind of two patterns does this type of service discovery using?

A

Application services and their clients interact with the service registry. Application service registers their service location(address) in the service registry.
A service client invokes the first service registry to obtain a list of service addresses and then it then sends a request to one of those instances.

This approach to service discovery is a combination of two patterns:
1) Self-registration pattern - a service instance invokes the service registry’s registration API to register its network location. It may also supply a health check URL. PI to register its network location. It may also supply a health check URL, described in more detail in chapter 11. The health check URL is an API endpoint that the service registry invokes periodically to verify that the service instance is healthy and available to handle request

2) Client-side discovery pattern - When a service client wants to invoke a service, it queries the service registry to obtain a list of the service’s instances. To improve performance, a client might cache the service instances. The service client then uses a load-balancing algorithm, such as a round-robin or random, to select a service instance. It then makes a request to a select service instance.

28
Q

Describe the platform-provided service discovery pattern.
What kind of two patterns does this type of service discovery using?

A

Docker and Kubernetes have a BUILT-IN service registry and service discovery mechanism. The deployment platform gives each service a DNS name, a virtual IP (VIP) address, and a DNS name that resolves to the VIP address. A service client makes a request to the DNS name/VIP, and the deployment platform automatically routes the request to one of the available service instances. As a result, service registration, service discovery, and request routing are entirely handled by the deployment platform.

This approach is a combination of two patterns:

1) 3rd party registration pattern— Instead of a service registering itself with the service registry, a third party called the registrar, which is typically part of the deployment platform, handles the registration.

2) Server-side discovery pattern— Instead of a client querying the service registry, it makes a request to a DNS name, which resolves to a request router that queries the service registry and load balances requests.

29
Q

What are the benefits of broker-based messaging?

A

1) LOOSE COUPLING
A client makes a request by simply sending a message to the appropriate channel. The client is completely unaware of the service instances. It doesn’t need to use a discovery mechanism to determine the location of a service instance.

2) MESSAGE BUFFERING
The message broker buffers messages until they can be processed. With a synchronous request/response protocol such as HTTP, both the client and service must be available for the duration of the exchange. With messaging, though, messages will queue up until they can be processed by the consumer. This means, for example, that an online store can accept orders from customers even when the order-fulfillment system is slow or unavailable. The messages will simply queue up until they can be processed.

30
Q

What are the drawbacks of broker-based messaging?

A

1) POTENTIAL SINGLE POINT of FAILURE
It’s essential that the message broker is highly available—otherwise, system reliability will be impacted. Fortunately, most modern brokers have been designed to be highly available.

2) ADDITIONAL OPERATIONAL COMPLEXITY
The messaging system is yet another system component that must be installed, configured, and operated.

3) POTENTIAL PERFORMANCE BOTTLENECK
There is a risk that the message broker could be a performance bottleneck. Fortunately, many modern message brokers are designed to be highly scalable.

31
Q

How to solve the problem of “Competing consumers and message ordering” in messaging-based systems?

A

A common solution, used by modern message brokers like Apache Kafka and AWS Kinesis, is to use sharded (partitioned) channels.

There are three parts to the solution:
1) A sharded channel consists of two or more shards (partitions), each of which behaves like a channel.

2) The sender specifies a shard key in the message’s header, which is typically an arbitrary string or sequence of bytes. The message broker uses a shard key to assign the message to a particular shard/partition. It might, for example, select the shard by computing the hash of the shard key modulo the number of shards.

3) The messaging broker groups together multiple instances of a receiver and treats them as the same logical receiver. Apache Kafka, for example, uses the term consumer group. The message broker assigns each shard to a single receiver. It reassigns shards when receivers start up and shut down.

32
Q

What message delivery guarantees do you know?

A

1) At-most-once
for each message sent, the side effects of its processing may either be missing or applied once

2) At-least-once
the side effect of processing messages may be applied multiple times but they may never be skipped.

3) exactly-once
the message is processed only once

33
Q

How to deal with duplicate messages in messaging systems?

livebook.manning.com/book/microservices-patterns/chapter-3/323

A

[1] IDEMPOTENT MESSAGE HANDLERS (idempotent business logic)
If the application logic that processes messages is idempotent, then duplicate messages are harmless. Application logic is idempotent if calling it multiple times with the same input values has no additional effect. For instance, cancelling an already-cancelled order is an idempotent operation. So is creating an order with a client-supplied ID. An idempotent message handler can be safely executed multiple times, provided that the message broker preserves ordering when redelivering messages.

Unfortunately, business logic is quite often not idempotent and because of that there is another solution:
[2] TRACKING MESSAGES AND DISCARD DUPLICATES
A simple solution is for a message consumer to track the messages that it has processed using the message id and discard any duplicates. It could, for example, store the message id of each message that it consumed in a database table.

When a consumer handles a message, it records the message id in the database table as part of the transaction that creates and updates business entities. In this example, the consumer inserts a row containing the message id into a PROCESSED_MESSAGES table. If a message is a duplicate, the INSERT will fail and the consumer can discard the message.

34
Q

What is a “Transaction script”?

A

Transaction script is a pattern that organizes a business logic by procedures where each procedure handles a single request from the presentation.

It is characterized by usually long methods that change the state of an object, mixing different subdomains and anemic domain entities which do not encapsulate their state (attributes).

Transaction script is not considered valid in Object-oriented languages. An alternative and more proper way of designing a system is to use Domain Driven Design.