Billede

Oliver Sturm had an interesting talk on day 3 of SDD Conference. He talked about the event sourcing architecture, that can be used for highly performing and error resilient communication in a software system (applicable to both SOA and Microservice applications).

Event sourcing

Event sourcing is an architectural pattern that records all changes to an application's state as a sequence of events. These events are then stored in an event store - usually a database that is optimized for storing and querying events.

Event store

When an event is created, it is assigned a unique identifier and a timestamp. The event also includes information about the entity that was changed, the type of change that was made, and the old and new values of the entity.

The event store is typically append-only, which means that events can only be added to the end of the log. This makes it very efficient to query the event store, as only the most recent events need to be scanned.

A normal pattern is to have an endpoint that receives all requests coming in to the system and saving them in the event store. This is a database that holds all the requests that comes in to the system, so that they can be inspected at a later time if neccesary. The event store will send a message to the event bus, when the request has been saved. Normally the data fra the request is not changed in anyway ie. the data saved to the event store database is exactly the same, that is sent to the event bus.

Read model

A read model is a representation of the current state of an application that is derived from the event stream coming from the event bus (ie. the messages that was forwarded from the event store service). The read model is used to provide a consistent view of the application state to clients, even if the application has been updated multiple times since the client last requested data.

A read model will usually be responsible for a subset of the data. This could be customers, the stock in the warehouse or something completely else. This means that there will be multiple read model, each responsible for handling queries regarding a subset of the data. The read model is populated by replaying the event stream - but only the events that relate to the entities that is relevant for that read model (eg. changes to customers). This means that the event store is read from start to finish, and each event is used to update the read model.

Using VAR for failure recovery 

The event stream provides the possiblity to replay everything that happend from a certain point in time (or from the beginning if needed). This means that there's always the option to use the event messages as VAR in football, where we can replay everything that has happend over and over again (and debug it if we need to). 

An error happend due to a bug in the code, can be fixed and when the fix has been deployed, the event stream can be replayed and the data can be verified. If everything looks to be in order, we can drop the old read model database, create a new database and replay the event stream to repopulate the new database with the correct data.

Event sourcing framework for C#

The best event sourcing framework for you will depend on your specific needs and requirements. Here's a few of the most popular frameworks for C#

Axon Framework

Axon Framework is a complete event sourcing framework that provides a number of features, including event sourcing, command bus, query bus, and event store. If you are looking for a complete framework with a lot of features, then Axon Framework is a good option. 

EventStore.NET

EventStore.NET is an event store that can be used with any event sourcing framework. It provides a number of features, including append-only storage, event compaction, and event replication. If you are looking for an event store that can be used with any event sourcing framework, then EventStore.NET is a good option.

SimpleCQRS

SimpleCQRS is a lightweight event sourcing framework that is easy to use. It provides a number of features, including command bus, query bus, and event store. If you are looking for a lightweight framework that is easy to use, then SimpleCQRS is a good option. 

 

SDD 2023 started out with a fullday workshop and I choose to attend Alan Holubs workshop on microservices. I have attended talks with Alan Holub before, and he is truly a great speaker. He is very good at getting the audience involved and he does have some opinions that can be a bit provocative. But I actually like the provocative opinions, because it really makes you take a step back and see the way we do things from another perspective and that is something that can be really rewarding in the long run.

So what is a microservice? 

  1. An application single, small and clear responsibility
    1.  A biproduct is that the code base is very small 
  2. Independently deployable
    1. Can be deployed without other applications needing to know and without other applications needing to be deployed simultaniously
  3. Decentralized
    1. Can be deployed anywhere and do not rely on other services or applications being deployed in the same datacenter or environment
    2. Cannot share a database with other applications or services
    3. Should enforce authentication and authorization
  4. Fully autonomous
    1. Can handle faults and spike loads. Will not let faults ripple to other services
  5. Highly observable
    1. There is a need for good logging and monitoring of a microservice in order for the team to react, analyze and solve problems very fast

One of the main differences from the monolithic architecture, is that microservices are completely independent. That means that they do not share a database with other microservices. They might have a database of their own, to support the work that they are doing, but they will never have access to a database that is shared between other microservices. This is a quite a big change, when you compare to the way a monolithic application works, where each service in the monolith have access to the same database.  

"You want to avoid a situation where one change results in deployment of multiple services" - Allan Holub

Notify the tiny titans

All data that the microservice need must be served when the microservice is invoked. This typically happens in one of two ways. Either the microservice has a subscriber that subscribes to messages on an event bus (ie. RabbitMQ, Azure Service Bus, ZeroMQ) - this is the most normal and effective approach. Some microservices have a requirement to be able to receive requests from "the outside world" and have a REST interface. This approach should be held to a minimum due to the performance hit of HTTP requests.

Microservices are hard

Microservices is not a silver bullet though. The architecture has to be well planned and implemented with good attention to detail - if it's not, it can be even more complex than the good old monolith architecture that we all (most of us anyway) are trying to get away from. But if you implement it with a solid plan and attention to detail, microservices can be a very liberating architecture to work with. But it is very important to understand that creating a microservice architecture will introduce complexity and will require you to handle problems that is not prevalent in a classic monolithic architecture.

Tiny footprints for tiny titans

In order to mitigate the complexity that is introduced to the overall architecture, when you start to implement microservices, it is recommended to keep the implementation of the individual microservice as simple as possible. For instance if you need to temporarily store some data, then save it in a file using JSON. File read and writes are plenty fast and as long as it is not holding thounds of rows of data, a file can fulfill the need. Do not be tempted to add a database unless you absolutely need it. It will only add to the complexity of the overall solution, because you need to set up the pipeline to maintain the databaes (and you have to pay for it as well!).

Conclusion

In the vast software kingdom, microservices have emerged as the rulers, dethroning the monolithic giants of the past. Their agility, decentralization, and scalability have paved the way for a new era in software development. As we conclude this exploration, it's clear that the tiny titans of microservices will continue to shape the software landscape, offering new possibilities and unleashing the potential for innovation. Long live the reign of microservices in the software kingdom!