Wednesday, April 7, 2021

System design | Design patterns | Event Sourcing Pattern | Docs Cloud Design Patterns: Prescriptive Architecture Guidance for Cloud Applications Design Patterns Event Sourcing Pattern

April 7, 2021

Here is the article. 

I like to learn more about system design. I think that it is better for me to read technical books from Microsoft first, prepare myself to work on large scale system. Also it is important for me to invest time to read more about Microsoft Azure service, and I need to learn basics of cloud solution. 

Event Sourcing Pattern

Data ManagementPerformance & ScalabilityDesign PatternsShow All

Use an append-only store to record the full series of events that describe actions taken on data in a domain, rather than storing just the current state, so that the store can be used to materialize the domain objects. This pattern can simplify tasks in complex domains by avoiding the requirement to synchronize the data model and the business domain; improve performance, scalability, and responsiveness; provide consistency for transactional data; and maintain full audit trails and history that may enable compensating actions.


Context and Problem

Most applications work with data, and the typical approach is for the application to maintain the current state of the data by updating it as users work with the data. For example, in the traditional create, read, update, and delete (CRUD) model a typical data process will be to read data from the store, make some modifications to it, and update the current state of the data with the new values—often by using transactions that lock the data.

The CRUD approach has some limitations:

  • The fact that CRUD systems perform update operations directly against a data store may hinder performance and responsiveness, and limit scalability, due to the processing overhead it requires.
  • In a collaborative domain with many concurrent users, data update conflicts are more likely to occur because the update operations take place on a single item of data.
  • Unless there is an additional auditing mechanism, which records the details of each operation in a separate log, history is lost.

 Note

For a deeper understanding of the limits of the CRUD approach see “CRUD, Only When You Can Afford It” on MSDN.

Solution

The Event Sourcing pattern defines an approach to handling operations on data that is driven by a sequence of events, each of which is recorded in an append-only store. Application code sends a series of events that imperatively describe each action that has occurred on the data to the event store, where they are persisted. Each event represents a set of changes to the data (such as AddedItemToOrder).

The events are persisted in an event store that acts as the source of truth or system of record (the authoritative data source for a given data element or piece of information) about the current state of the data. The event store typically publishes these events so that consumers can be notified and can handle them if needed. Consumers could, for example, initiate tasks that apply the operations in the events to other systems, or perform any other associated action that is required to complete the operation. Notice that the application code that generates the events is decoupled from the systems that subscribe to the events.

Typical uses of the events published by the event store are to maintain materialized views of entities as actions in the application change them, and for integration with external systems. For example, a system may maintain a materialized view of all customer orders that is used to populate parts of the UI. As the application adds new orders, adds or removes items on the order, and adds shipping information, the events that describe these changes can be handled and used to update the materialized view.

 Note

See the Materialized View pattern for more information.

In addition, at any point in time it is possible for applications to read the history of events, and use it to materialize the current state of an entity by effectively “playing back” and consuming all the events related to that entity. This may occur on demand in order to materialize a domain object when handling a request, or through a scheduled task so that the state of the entity can be stored as a materialized view to support the presentation layer.

Figure 1 shows a logical overview of the pattern, including some of the options for using the event stream such as creating a materialized view, integrating events with external applications and systems, and replaying events to create projections of the current state of specific entities.

Figure 1 - An overview and example of the Event Sourcing pattern

Figure 1 - An overview and example of the Event Sourcing pattern

The Event Sourcing pattern provides many advantages, including the following:

  • Events are immutable and so can be stored using an append-only operation. The user interface, workflow, or process that initiated the action that produced the events can continue, and the tasks that handle the events can run in the background. This, combined with the fact that there is no contention during the execution of transactions, can vastly improve performance and scalability for applications, especially for the presentation level or user interface.
  • Events are simple objects that describe some action that occurred, together with any associated data required to describe the action represented by the event. Events do not directly update a data store; they are simply recorded for handling at the appropriate time. These factors can simplify implementation and management.
  • Events typically have meaning for a domain expert, whereas the complexity of the object-relational impedance mismatch might mean that a database table may not be clearly understood by the domain expert. Tables are artificial constructs that represent the current state of the system, not the events that occurred.
  • Event sourcing can help to prevent concurrent updates from causing conflicts because it avoids the requirement to directly update objects in the data store. However, the domain model must still be designed to protect itself from requests that might result in an inconsistent state.
  • The append-only storage of events provides an audit trail that can be used to monitor actions taken against a data store, regenerate the current state as materialized views or projections by replaying the events at any time, and assist in testing and debugging the system. In addition, the requirement to use compensating events to cancel changes provides a history of changes that were reversed, which would not be the case if the model simply stored the current state. The list of events can also be used to analyze application performance and detect user behavior trends, or to obtain other useful business information.
  • The decoupling of the events from any tasks that perform operations in response to each event raised by the event store provides flexibility and extensibility. For example, the tasks that handle events raised by the event store are aware only of the nature of the event and the data it contains. The way that the task is executed is decoupled from the operation that triggered the event. In addition, multiple tasks can handle each event. This may enable easy integration with other services and systems that need only listen for new events raised by the event store. However, the event sourcing events tend to be very low level, and it may be necessary to generate specific integration events instead.

 Note

Event sourcing is commonly combined with the CQRS pattern by performing the data management tasks in response to the events, and by materializing views from the stored events.

Issues and Considerations

Consider the following points when deciding how to implement this pattern:

  • The system will only be eventually consistent when creating materialized views or generating projections of data by replaying events. There is some delay between an application adding events to the event store as the result of handling a request, the events being published, and consumers of the events handling them. During this period, new events that describe further changes to entities may have arrived at the event store.

     Note

    See the Data Consistency Primer for information about eventual consistency.

  • The event store is the immutable source of information, and so the event data should never be updated. The only way to update an entity in order to undo a change is to add a compensating event to the event store, much as you would use a negative transaction in accounting. If the format (rather than the data) of the persisted events needs to change, perhaps during a migration, it can be difficult to combine existing events in the store with the new version. It may be necessary to iterate through all the events making changes so that they are compliant with the new format, or add new events that use the new format. Consider using a version stamp on each version of the event schema in order to maintain both the old and the new event formats.

  • Multi-threaded applications and multiple instances of applications may be storing events in the event store. The consistency of events in the event store is vital, as is the order of events that affect a specific entity (the order in which changes to an entity occur affects its current state). Adding a timestamp to every event is one option that can help to avoid issues. Another common practice is to annotate each event that results from a request with an incremental identifier. If two actions attempt to add events for the same entity at the same time, the event store can reject an event that matches an existing entity identifier and event identifier.

  • There is no standard approach, or ready-built mechanisms such as SQL queries, for reading the events to obtain information. The only data that can be extracted is a stream of events using an event identifier as the criteria. The event ID typically maps to individual entities. The current state of an entity can be determined only by replaying all of the events that relate to it against the original state of that entity.

  • The length of each event stream can have consequences on managing and updating the system. If the streams are large, consider creating snapshots at specific intervals such as a specified number of events. The current state of the entity can be obtained from the snapshot and by replaying any events that occurred after that point in time.

     Note

    For more information about creating snapshots of data, see Snapshot on Martin Fowler’s Enterprise Application Architecture website and Master-Subordinate Snapshot Replication on MSDN.

  • Even though event sourcing minimizes the chance of conflicting updates to the data, the application must still be able to deal with inconsistencies that may arise through eventual consistency and the lack of transactions. For example, an event that indicates a reduction in stock inventory might arrive in the data store while an order for that item is being placed, resulting in a requirement to reconcile the two operations; probably by advising the customer or creating a back order.

  • Event publication may be “at least once,” and so consumers of the events must be idempotent. They must not reapply the update described in an event if the event is handled more than once. For example, if multiple instances of a consumer maintain an aggregate of a property of some entity, such as the total number of orders placed, only one must succeed in incrementing the aggregate when an “order placed” event occurs. While this is not an intrinsic characteristic of event sourcing, it is the usual implementation decision.

When to Use this Pattern

This pattern is ideally suited to the following scenarios:

  • When you want to capture “intent,” “purpose,” or “reason” in the data. For example, changes to a customer entity may be captured as a series of specific event types such as Moved home, Closed account, or Deceased.
  • When it is vital to minimize or completely avoid the occurrence of conflicting updates to data.
  • When you want to record events that occur, and be able to replay them to restore the state of a system; use them to roll back changes to a system; or simply as a history and audit log. For example, when a task involves multiple steps you may need to execute actions to revert updates and then replay some steps to bring the data back into a consistent state.
  • When using events is a natural feature of the operation of the application, and requires little additional development or implementation effort.
  • When you need to decouple the process of inputting or updating data from the tasks required to apply these actions. This may be to improve UI performance, or to distribute events to other listeners such as other applications or services that must take some action when the events occur. An example would be integrating a payroll system with an expenses submission website so that events raised by the event store in response to data updates made in the expenses submission website are consumed by both the website and the payroll system.
  • When you want flexibility to be able to change the format of materialized models and entity data if requirements change, or—when used in conjunction with CQRS—you need to adapt a read model or the views that expose the data.
  • When used in conjunction with CQRS, and eventual consistency is acceptable while a read model is updated or, alternatively, the performance impact incurred in rehydrating entities and data from an event stream is acceptable.

This pattern might not be suitable in the following situations:

  • Small or simple domains, systems that have little or no business logic, or non-domain systems that naturally work well with traditional CRUD data management mechanisms.
  • Systems where consistency and real-time updates to the views of the data are required.
  • Systems where audit trails, history, and capabilities to roll back and replay actions are not required.
  • Systems where there is only a very low occurrence of conflicting updates to the underlying data. For example, systems that predominantly add data rather than updating it.

Example

A conference management system needs to track the number of completed bookings for a conference so that it can check whether there are seats still available when a potential attendee tries to make a new booking. The system could store the total number of bookings for a conference in at least two ways:

  • The system could store the information about the total number of bookings as a separate entity in a database that holds booking information. As bookings are made or cancelled, the system could increment or decrement this number as appropriate. This approach is simple in theory, but can cause scalability issues if a large number of attendees are attempting to book seats during a short period of time. For example, in the last day or so prior to the booking period closing.
  • The system could store information about bookings and cancellations as events held in an event store. It could then calculate the number of seats available by replaying these events. This approach can be more scalable due to the immutability of events. The system only needs to be able to read data from the event store, or to append data to the event store. Event information about bookings and cancellations is never modified.

Figure 2 shows how the seat reservation sub-system of the conference management system might be implemented by using event sourcing.

Figure 2 - Using event sourcing to capture information about seat reservations in a conference management system

Figure 2 - Using event sourcing to capture information about seat reservations in a conference management system

The sequence of actions for reserving two seats is as follows:

  1. The user interface issues a command to reserve seats for two attendees. The command is handled by a separate command handler (a piece of logic that is decoupled from the user interface and is responsible for handling requests posted as commands).

  2. An aggregate containing information about all reservations for the conference is constructed by querying the events that describe bookings and cancellations. This aggregate is called SeatAvailability, and is contained within a domain model that exposes methods for querying and modifying the data in the aggregate.

     Note

    Some optimizations to consider are using snapshots (so that you don’t need to query and replay the full list of events to obtain the current state of the aggregate), and maintaining a cached copy of the aggregate in memory.

  3. The command handler invokes a method exposed by the domain model to make the reservations.

  4. The SeatAvailability aggregate records an event containing the number of seats that were reserved. The next time the aggregate applies events, all the reservations will be used to compute how many seats remain.

  5. The system appends the new event to the list of events in the event store.

If a user wishes to cancel a seat, the system follows a similar process except that the command handler issues a command that generates a seat cancellation event and appends it to the event store

As well as providing more scope for scalability, using an event store also provides a complete history, or audit trail, of the bookings and cancellations for a conference. The events recorded in the event store are the definitive and only source of truth. There is no need to persist aggregates in any other way because the system can easily replay the events and restore the state to any point in time.

 Note

You can find more information about this example in the chapter Introducing Event Sourcing in the patterns & practices guide CQRS Journey on MSDN.

Related Patterns and Guidance

The following patterns and guidance may also be relevant when implementing this pattern:

  • Command and Query Responsibility Segregation (CQRS) Pattern. The write store that provides the immutable source of information for a CQRS implementation is often based on an implementation of the Event Sourcing pattern. The Command and Query Responsibility Segregation pattern describes how to segregate the operations that read data in an application from the operations that update data by using separate interfaces.
  • Materialized View Pattern. The data store used in a system based on event sourcing is typically not well suited to efficient querying. Instead, a common approach is to generate pre-populated views of the data at regular intervals, or when the data changes. The Materialized View pattern shows how this can be achieved.
  • Compensating Transaction Pattern. The existing data in an event sourcing store is not updated; instead new entries are added that transition the state of entities to the new values. To reverse a change, compensating entries are used because it is not possible to simply reverse the previous change. The Compensating Transaction pattern describes how to undo the work that was performed by a previous operation.
  • Data Consistency Primer. When using event sourcing with a separate read store or materialized views, the read data will not be immediately consistent; instead it will be only eventually consistent. The Data Consistency Primer summarizes the issues surrounding maintaining consistency over distributed data.
  • Data Partitioning Guidance. Data is often partitioned when using event sourcing in order to improve scalability, reduce contention, and optimize performance. The Data Partitioning****Guidance describes how to divide data into discrete partitions, and the issues that can arise.

More Information

Investors Big And Small Are Driving Stock Gains With Borrowed Money

 April 7, 2021

Here is the article.

Investors are borrowing huge sums of money to buy stocks. Is that a problem?

The “everything rally” that started in stocks last year has been boosted by investors betting money they’ve borrowed. That includes both small players like the day traders on Robinhood Markets Inc. and heavyweights like Archegos Capital Management, the investing firm that triggered a mini meltdown for several companies’ stocks.

As of late February, investors had borrowed a record $814 billion against their portfolios, according to data from the Financial Industry Regulatory Authority, Wall Street’s self-regulatory arm. That was up 49% from one year earlier, the fastest annual increase since 2007, during the frothy period before the 2008 financial crisis. Before that, the last time investor borrowings had grown so rapidly was during the dot-com bubble in 1999.

Finra’s data doesn’t necessarily mean that investor borrowing has fueled the S&P 500’s epic 53% rally over the past 12 months. There are many other factors behind those gains, including the U.S. economy’s rebound from the depths of the Covid-19 pandemic and the Federal Reserve’s easy-money policies.

The Finra data also isn’t a perfect gauge for how much investors are trading on margin—when they pledge securities in exchange for loans from brokerages to make further investments. The data covers loans that some investors take out for other purposes, for instance. And it’s only natural for investor borrowings to rise along with the overall value of the stock market, since that increases the total pool that investors can use for collateral.

Still, some analysts say run-ups in margin debt contribute to bubbles, and they fear that today’s levels of borrowing will hurt investors if the market has a downturn. 

“It fuels bull markets and it exacerbates bear markets and to a certain extent you put it on the list of irrational exuberance,” said Edward Yardeni, president of consulting firm Yardeni Research. “The further that this stock market goes, the higher that margin debt will go, and when something blows up that will be one of the factors for why stocks are going down.”

Margin trading is a double-edged sword. Borrowing money gives investors more buying power, but it also puts them at greater risk. When stocks fall, lenders can ask investors to put up more collateral or sell the shares, a demand known as a margin call.

Some regulators have voiced concern about investors taking on too much leverage, the broad term for when investors put on big trades with a relatively small amount of money, usually by borrowing.

Leverage combined with internet hype can be dangerous, the Commodity Futures Trading Commission said in a notice to investors Tuesday. “Speculative short-term trading is always risky, but mixing it with unfamiliar products and markets, leverage, and advice from anonymous individuals is a recipe for disaster,” the CFTC said.

Finra’s data doesn’t break down the proportion of the margin debt held by small investors versus big ones. But the largest players often use other tools to amplify their bets, like derivatives. The degree of leverage used in such trades isn’t tracked in public data, and it often comes to light only after a bet goes spectacularly wrong.

Archegos, the family-investment vehicle of hedge-fund veteran Bill Hwang, attained eye-popping amounts of leverage by using derivative contracts called total return swaps. Such swaps provide investors with exposure to the gains or losses of a particular stock or basket of stocks, without requiring them to hold the underlying shares.

They also allow sophisticated investors like Mr. Hwang to place giant bets while paying a small amount of money up front—effectively creating a turbocharged version of the margin loans offered by online brokerages like Robinhood.

In general, Fed rules require investors to have at least 50 cents of collateral at their brokerages to buy $1 worth of securities on margin. But by using swaps, Archegos could put up as little as 15 cents for every $1 in shares, The Wall Street Journal has reported. That let Archegos punch above its weight: Though the firm is estimated to have managed $10 billion of its own money, its total positions that were unwound approached $30 billion, the Journal and others have reported.

It’s unclear how many other investment firms have obtained Archegos-style levels of leverage. Little disclosure is required in the market for total return swaps, which Wall Street banks privately tailor for clients.

“The total-return-swap market is more opaque than the cash market,” said Josh Galper, managing principal of Finadium, a research and advisory firm. “The lack of transparency in this market makes it not possible for the average market participant to know what is going on.”


Total margin debt: $900 billion | SPX gains with over 30%

 


Investors are borrowing huge sums of money to buy stocks. Is that a problem?

The “everything rally” that started in stocks last year has been boosted by investors betting money they’ve borrowed. That includes both small players like the day traders on Robinhood Markets Inc. and heavyweights like Archegos Capital Management, the investing firm that triggered a mini meltdown for several companies’ stocks.

As of late February, investors had borrowed a record $814 billion against their portfolios, according to data from the Financial Industry Regulatory Authority, Wall Street’s self-regulatory arm. That was up 49% from one year earlier, the fastest annual increase since 2007, during the frothy period before the 2008 financial crisis. Before that, the last time investor borrowings had grown so rapidly was during the dot-com bubble in 1999.

Finra’s data doesn’t necessarily mean that investor borrowing has fueled the S&P 500’s epic 53% rally over the past 12 months. There are many other factors behind those gains, including the U.S. economy’s rebound from the depths of the Covid-19 pandemic and the Federal Reserve’s easy-money policies.

Book reading: Cloud design patterns: Prescriptive Architecture Guidance for Cloud Applications | System design | 2021 book reading

 April 7, 2021

Here is the link. 

I like to spend two hours to read the book. I like to highlight the content I need to learn more first, and then continue to read other interesting books. 

I like to try various ways to read books, and then I have chance to learn more about cloud solution. I need to learn some basics first. It is much better to read well-written book content before I watch videos on system design topics. 

I need to be patient, and also focus on fundamental basics of distributed system. 

  1. pessimistic locking
  2. eventual consistency

Managing Data Consistency

Every web application and service uses data. This data is frequently required to help users and organizations make business decisions, and therefore it may be important that this data accurately represents the most current information available and that it is consistent. Data consistency implies that all instances of an application are presented with the same set of data values all of the time. This approach is sometimes referred to as strong data consistency.

In the world of relational databases, consistency is often enforced by transactional models that use locks to prevent concurrent application instances from modifying the same data at the same time. In a strongly consistent system, the locks also block concurrent requests to query data, but many relational databases enable an application to relax this rule and provide access to a copy of the data that reflects the state it was in before the update started. Many applications that store data in non-relational databases, flat files, or other structures follow a similar strategy, known as pessimistic locking. An application instance locks data while it is being modified, and then releases the lock when the update is complete.

In a modern cloud application, the data is likely to be partitioned across data stores hosted at different sites, some of which could be dispersed over a wide geography. This can occur for a variety of reasons: to improve scalability by balancing the load across multiple computers, to improve response time by co-locating data close to the users and services that access it, or to improve availability by replicating data across different sites.

Maintaining data consistency across distributed data stores can be a significant challenge. The issue is that strategies such as serialization and locking only work well if all application instances share the same data store, and the application is designed to ensure that the locks are very short-lived. However, if data is partitioned or replicated across different data stores, locking and serializing data access to maintain consistency can become an expensive overhead that impacts the throughput, response time, and scalability of a system. Therefore, most modern distributed applications do not lock the data that they modify, and they take a rather more relaxed approach to consistency, known as eventual consistency.

The following sections provide more information on strong consistency and eventual consistency, and the issues that surround these different approaches to maintaining data consistency in a distributed environment such as the cloud.

  1. strong consistency model
  2. inconsistent view of the data
  3. Argument: The aim of the strong consistency model is to minimize the chance that an application instance might be presented with an inconsistent view of the data
  4. D

Strong Consistency

In the strong consistency model, all changes are atomic. If a transaction updates multiple data items, the transaction is not allowed to complete until either all of the changes have been made successfully, or (in the event of a failure) they have all been undone. In the time between a transaction starting and completing, other concurrent transactions may not be able access any of the data that has been modified; they will be blocked. If data is being replicated, a transaction that implements strong consistency may not be allowed to complete until every copy of each item that has changed has been successfully updated.

The aim of the strong consistency model is to minimize the chance that an application instance might be presented with an inconsistent view of the data. The cost of implementing this model is the impact it has on the availability, performance, and scalability of the resulting solution. In a distributed environment, if the data stores holding the data affected by a transaction are geographically remote from each other, network latency could adversely impact the performance of such transactions and result in concurrent access to data being blocked for an extended period. If a network failure renders one or more of the data stores inaccessible during a transaction, an application updating data in a system that implements strong consistency may be blocked until every data store becomes accessible again.

Additionally, in a distributed environment such as the cloud, implementing strong consistency is not tolerant of the types of failure that may occur. For example, it may not be possible to roll back a transaction and release the resources that it holds if a component participating in the transaction has stopped responding due to a long-lasting network outage. In this case, it will be necessary to resolve the situation through other means, such as manually reconciling the data.

In a cloud application, you should implement strong consistency only where it is absolutely necessary. For example, if an application updates multiple items that are located within the same data store, the benefits of strong consistency may outweigh the disadvantages because data is likely to be locked only for a very short period. However, if the items to be updated are dispersed across a network, it may be more appropriate to relax the requirement for strong consistency.

In a system that implements strong consistency but also replicates data to remote locations, it may be appropriate to propagate changes to replicas outside the scope of a strongly consistent transaction. Some level of transient inconsistency is almost inevitable while replicas are updated—but the data will eventually become consistent after the synchronization between replicas has completed. For more information, see the Data Replication and Synchronization Guidance.

An alternative approach for maintaining strong consistency across replicated data that is frequently implemented by highly scalable NoSQL databases is to use read and write quorums and versioning. This approach avoids locking data, at the expense of some additional complexity in the processes that read and write data. For more information see the section “Improving Consistency” in Chapter 1, “Data Storage for Modern High-Performance Business Applications” of the guide Data Access for Highly-Scalable Solutions: Using SQL, NoSQL, and Polyglot Persistence on MSDN.

  1. Eventual consistency also impacts data consistency when using caching. 
  2. implementing techniques such as the Cache Aside pattern, can help to reduce the chances of inconsistencies occurring. 

Eventual Consistency

Eventual consistency is a rather more pragmatic approach to data consistency. In many cases, strong consistency is not actually required as long all the work performed by a transaction is completed or rolled back at some point, and no updates are lost. In the eventual consistency model, data update operations that span multiple sites can ripple through the various data stores in their own time, without blocking concurrent application instances that access the same data.

One of the drives for eventual consistency is that distributed data stores are subject to the CAP Theorem. This theorem states that a distributed system can implement only two of the three features (Consistency, Availability, and Partition Tolerance) at any one time. In practice, this means that you can either:

  • Provide a consistent view of distributed (partitioned) data at the cost of blocking access to that data while any inconsistencies are resolved. This may take an indeterminate time, especially in systems that exhibit a high degree of latency or if a network failure causes loss of connectivity to one or more partitions.
  • Provide immediate access to the data at the risk of it being inconsistent across sites. Traditional database management systems focus on providing strong consistency, whereas cloud-based solutions that utilize partitioned data stores are typically motivated by ensuring higher availability, and are therefore more oriented towards eventual consistency.

An application instance may see a view of a data item affected by an operation in the state it is in while the operation is in flight, and this view may be temporarily inconsistent. Depending on the requirements of the system, the developer might need to design applications to detect and handle such inconsistencies, and then take steps to resolve them if necessary.

Eventual consistency also impacts data consistency when using caching. If the data in the remote data store changes, all copies cached by applications will be most likely be out of date. Configuring a cache expiration policy that prevents cached data from becoming too stale, and implementing techniques such as the Cache Aside pattern, can help to reduce the chances of inconsistencies occurring. However, these approaches are unlikely to completely eliminate inconsistencies in cached data, and it is important that applications that use caching as an optimization strategy can handle these inconsistencies.

It is worth bearing in mind that an application may not actually require data to be consistent all of the time. For example, in a typical ecommerce web application that enables a user to browse and purchase goods, any stock levels presented to a user are likely to be static values determined when the details for a stock item are queried. If another concurrent user purchases the same item, the stock level in the system will decrease but this change will probably not need to be reflected in the data displayed to the first user. If the stock level drops to zero and the first user attempts to purchase the item, the system could either alert the user that the item is now out of stock, or place the item on back order and inform the user that the delivery time may be extended.

Considerations for Implementing Eventual Consistency

Eventual consistency is often the preferred model for managing distributed data in a cloud environment, but there are many issues that you must consider if you follow this model. These issues are best summarized by using an example. Figure 1 shows a simple ecommerce application that could benefit from following the eventual consistency approach.

When a customer places an order, the application instance performs the following operations across a collection of heterogeneous data stores held in various locations:

  1. Update the stock level of the item ordered.
  2. Record the details of the order.
  3. Verify payment details for the order.

Although these operations comprise a logical transaction, attempting to implement strong transactional consistency in this scenario is likely to be impractical. Instead, implementing the order process as an eventually consistent**series of steps, where each step in the process is essentially an autonomous operation, is a much more scalable solution. While these steps are progressing, the state of the overall system is inconsistent. For example, after the stock level has been updated but before the details of the order have been recorded the system has temporarily lost some stock. However, when all the steps have been completed, the system returns to a consistent state and all stock items can be accounted for.

Despite the fact that implementing eventual consistency in this example appears to be conceptually quite simple, the developer must ensure that the system does eventually become consistent. In other words, the application is responsible for guaranteeing either that all three steps in the order process complete, or determining the actions to take if any of the steps fail. How you resolve this situation in any given system is inevitably application specific.

For an example showing how you can implement an eventually consistent system spanning different data stores, see Chapter 8, “Building a Polyglot Solution,” in the guide “Data Access for Highly-Scalable Solutions: Using SQL, NoSQL, and Polyglot Persistence” on MSDN. The following sections of this guidance also provide some suggestions.

Retrying Failing Steps

In a distributed environment, the inability to complete an operation is often due to some type of temporary error (communication failure is always a possibility.) If such a failure occurs, an application might assume that the situation is transient and simply attempt to repeat the step that failed. Less transient exceptions, such as database or virtual machine failure, may also occur and the remedy might be similar—wait for the system to be recovered and then try the failing operation again. This approach could result in the same step actually being run twice, possibly resulting in multiple updates. It is very difficult to design a solution to prevent this repetition from occurring, but the application should attempt to render such repetition harmless.

One strategy is to design each step in an operation to be idempotent. This means that a step that had previously succeeded can be repeated without actually changing the state of the system. The steps that comprise a business operation are naturally heavily dependent on the business logic of your system, and the way in which you implement them will be heavily influenced by the structure of the data. Defining idempotent steps requires a deep, domain-specific understanding of your system.

Some steps might be naturally idempotent. For example, a step that sets a particular item to a specific value (such as “ZipCode = 11111”) can be repeated many times and the result will always be the same. However, natural idempotency is not always possible. In a system that incorporates services, such as the payment system shown in the ecommerce example, it may be possible to implement some form of artificial idempotency. A common technique is to associate the message sent to the service with a unique identifier. The service can store the identifier for each message it receives locally, and only process a message if the identifier does not match that of a message it received earlier. This technique is known as de-duping (the removal of duplicate messages). This strategy, exemplified by the Idempotent Receiver pattern, depends on the service being able to store message identifiers successfully.

Partitioning Data and Using Idempotent Commands

Multiple instances of an application competing to modify the same data at the same time are another common cause of failure to achieve eventual consistency. If possible, you should design your system to minimize these situations. You should try and partition your system to ensure that concurrent instances of an application attempting to perform the same operations simultaneously do not conflict with each other.

Rather than thinking in terms of simple CRUD (create, retrieve, update, and delete) operations, you can structure your system around atomic commands that perform business tasks in an idempotent style. For more information, see the Command and Query Responsibility Segregation pattern. The commands in a CQRS solution are frequently implemented by following the Event Sourcing pattern. Event sourcing performs operations on data by driving tasks from a sequence of events, each of which is recorded in an append-only store.



GOTO 2019 • Not Just Events: Developing Asynchronous Microservices • Chris Richardson

 April 7, 2021

Here is the link. 

This presentation was recorded at GOTO Chicago 2019. #GOTOcon​ #GOTOchgo​ http://gotochgo.com​ Chris Richardson - Creator of the original CloudFoundry.com and author of 'POJOs in Action' and 'Microservices Patterns' ABSTRACT The microservice architecture functionally decomposes an application into a set of services. Each service has its own private database that’s only accessible indirectly through the services API. Consequently, implementing queries and transactions that span multiple services is challenging. In this presentation, you will learn how to solve these distributed data management challenges using asynchronous messaging. Chris will share with you how to implement transactions using sagas, which are sequences of local transactions. You will learn how to coordinate sagas using either events or command messages. Chris will also explore how to implement queries using Command Query Responsibility Segregation (CQRS), which [...] Download slides and read the full abstract here: https://gotochgo.com/2019/sessions/717​


Tuesday, April 6, 2021

System design: Learn microservice from Chris Richardson

 April 6, 2021

Introduction

I like to write a short research topic about how to advance myself in system design. I have worked on this from 2016 to 2021, and I had chance to come cross Microservice, Chris Richardson and his book and videos on youtube.com. 


Data Consistency in Microservice Using Sagas

April 6, 2021

Here is the link. 

Chris Richardson discusses messaging, durability, and reliability in microservice architectures leveraging the Saga Pattern. He shows how sagas work and how they differ from traditional transactions, and describes how to use sagas to develop business logic in a microservices application. He also describes the design of a saga framework for Java and shows a sample application. This presentation was recorded at QCon San Francisco 2017.

Rollback using compensating transactions

  • ACID transactions can simply rollback
  • But
  • Developer must write application logic to "rollback" eventually consistent transactions
  • Careful design required!
Compensating transactions
Sage: Every Ti has a Ci - Transaction T, Compensation C

Sages complicate API design
  • Synchronous API vs Asynchronous Saga
  • Request initiates the saga. When to send back the response?
  • Option #1: Send response when saga completes!

Revised Create Order API

Sagas are ACD

Lack of I => anomalies
  • Lost update
    • Ti reads => other transaction writes -> Tj (or Ci) writes
    • Dirty reads
    • Ti writes -> other transaction reads -> Ci writes
Countermeasures for reducing impact of isolation anomalies...
  • Commutative updates
    • e.g. debt account can compensate for a credit account
    • Version file
      • Record history of changes
      • use them to make updates commutative
      • e.g. record cancel reservation so that create/cancel = cancel/create