SSW Foursquare

Rules to Better Microservices - 3 Rules

A microservice architecture is an application architecture where an application consists of many loosely-coupled services. The communications between services are kept lightweight, and the API interfaces between them need to be carefully managed. They are designed to allow different teams to work on different parts of the application completely independently.

  1. Microservices - Do you break down your apps?

    There are two common types of application architecture:

    • Monoliths (aka N-Tier applications)
    • Microservices

    Monoliths have their place. They are easy to get going and often make a lot of sense when you are starting out. However, sometimes your app may grow in size and become difficult to maintain. Then you might want to consider Microservices...

    Microservices let you break down your app into little pieces to make them more manageable, replaceable and maintainable. You can also scale out different parts of your app at a granular level.

    .NET 6 and Azure have heaps of great tools for developing simple APIs and worker services in a Microservices pattern.

    Watch the below video from 35:40 - 46:50

    The tools of the trade

    • .NET Worker Services make it easier to implement dependency injection, configuration and other syntactic sugar using the same patterns you are familiar with in other types of .NET applications
    • Azure Container Apps give you a way to host different little subsections of the application
    • Azure Functions gives you a great way to build applications in small, modular, scalable and easy to manage chunks. It provides triggers other than http to handle other common microservice patterns
    • Minimal APIs give you a way to write APIs in just a few short lines of code

    What's the point?

    • Cost - Provides separation of scalability, keep the hot parts of your app hot and the cold parts of your app cold to achieve maximum pricing efficiency
    • Maintainability - Keep code more manageable by making it bite sized chunks
    • Simplify code - Write minimal APIs
    • Deployment - Standardize deployment with containers
    • Testing - Easier to find problems since they are isolated to a specific part of the app
    • Cognitive Complexity - Devs can focus on one aspect of the app at a time
    • Data - You can use the best way of storing data for each service
    • Language - You can use the best language for each service

    What's the downside?

    • Upfront Cost - More upfront work is required
    • Cognitive Complexity - While individual apps are simpler, the architecture of the app can become more complex
    • Health Check - It's harder to know if all parts are alive
    • Domain boundaries - You need to define the separation of concerns between different services. Avoid adding dependencies between services because you can create a domino of failures...a house of cards.
    • Performance normally suffers as calls are made between services
    • Without adequate testing it's harder to maintain
    • Using multiple languages and datastores can be both more expensive to host and require more developers

    What new techniques are required

    • Contract Testing - To mitigate the risk of changes in one service breaking another, comprehensive tests that check the behaviour of services is required
  2. Do you know the key components of a Microservice solution?

    Microservice architectures consist of a number of components

    These often include:

    • An API Gateway (think APIM, Ocelot, YARP, Azure Front Door)
    • Support different types of frontends: Web, Desktop, Mobile
    • Flexible deployment model in subsequent microservices
    • Each microservice is in charge of its own data store
    • Event driven
    • VNet integration
    • Messaging system (used to decouple services, think Azure SendGrid or ServiceBus)
  3. Do you use MassTransit to build reliable distributed applications?

    When building distributed applications messaging is a common pattern to use. Often we might take a hard dependency on a specific messaging technology, such as Azure Service Bus or RabbitMQ. This can make it difficult to change messaging technologies in the future. Good architecture is about making decisions that make things easy to change in future. This is where MassTransit comes in.

    MassTransit is a popular open-source .NET library that makes it easy to build distributed applications using messaging without tying you to one specific messaging technology.

    .NET Messaging Libraries

    There are several .NET messaging libraries that all abstract the underlying transport. These include:

    There are also the service bus specific libraries:

    Advantages of using MassTransit

    ✅ Open-source and free to use

    ✅ Enables swapping of messaging transports by providing a common abstraction layer

    ✅ Supports multiple messaging concepts:

    • Point-to-Point
    • Publish/Subscribe
    • Request/Response

    ✅ Supports multiple messaging transports:

    • In-Memory
    • RabbitMQ
    • Azure Service Bus
    • Amazon SQS
    • ActiveMQ
    • Kafka
    • gRPC
    • SQL/DB

    ✅ Supports complex messaging patterns such as Sagas

    Scenarios

    Scenario 1 - Modular Monolith

    A Modular Monolith architecture requires all modules to be running in a single process. MassTransit can be used to facilitate in-memory communication between modules in the same process.

    This allows us to send events between modules and also request data from other modules.

    Scenario 2 - Azure Hosted Microservices

    When building microservices in Azure, it's common to use Azure Service Bus as the messaging transport. With minimal changes, MassTransit can be used to send messages to and from Azure Service Bus instead of using the In-Memory transport.

    Scenario 3 - Locally Developing Microservices

    When developing microservices locally, it's common to use containers for each service. However, some of the cloud based messaging services (e.g. Azure Service Bus) are not able to be run in a container locally. In this scenario, we can easily switch from using the Azure Service Bus transport to Containerized RabbitMQ transport

    Demo Code

    If you're interested in seeing MassTransit in action, check out github.com/danielmackay/dotnet-mass-transit

We open source. Powered by GitHub