Best practices

Akka Serverless is ideally suited to the creation of small, isolated services, sometimes called Microservices. There are some patterns of Microservice architecture that are also well-suited for Akka Serverless services. For a more detailed discussion, see The Reactive Principles new tab or the Reactive Architecture courses from Lightbend Academy.

Service design principles

As you build and deploy services, these design principles will be useful:

Defining service boundaries

We recommend use of Domain Driven Design (DDD) to determine the best way to divide responsibility and state between services. Lightbend provides a free course on Domain Driven Designnew tab. See the information on determining service boundaries in the "Decomposing the Domain" chapter, "Identifying Bounded Contexts" section.

Isolation

Each service you create should emphasise isolation--the service should be able to stand alone.

One Entity per service

It is best to have each service deal with a single Entity type. If you have more than one Entity type, it is not possible for Akka Serverless to route the data events optimally across the system.

Inter-service communications

Services that need to communicate with other services—​whether in the same Akka Serverless project or not—​should do so asynchronously, using messages (commands or events). You should avoid situations where one service calls another via its HTTP (or other synchronous) endpoint, as this tightly couples the two services and negates the advantages of event sourcing. Akka Serverless supports publishing and subscribing to broker topics.

Message migration

Plan for the evolution of your messages. Commands and events use data structures that often must evolve over time. Fields get added, fields get removed, the meaning of fields may change. How do you handle this over time as your system grows and evolves?

The Protocol Buffer language offers a number of facilities that support evolution and migration across versions, but it is something that must be planned and handled carefully, so new versions of services don’t have problems reading older event journals that they can’t understand.

Deployment units

While a container image can hold one or more services, it is typical to package one service per image. Akka Serverless scales the services in a container image together. When you couple multiple services by packaging them in the same image, you limit the ability of Akka Serverless to make most efficient use of cloud resources.

The advantages of right-sized services

When you design a series of small services that don’t share code and can be deployed independently, you reap these benefits:

  • It is faster and less complex to write and debug them because they focus on a small set of operations, usually around a single data Entity.

  • They simplify operational concerns and provide scalability because they can be deployed, stopped and started independently of the rest of the system, further simplifying operational concerns.

  • They handle variations in load gracefully. If properly designed, multiple instances of the service can be started up when necessary to support more load: For example, if your system runs on Black Friday and the shopping cart service gets super busy, you can spin up more shopping carts to handle that load without also having to start up more copies of the catalog service. When the load decreases, these extra instances can be removed again, minimizing resource usage.

  • They are message driven, interacting asynchronously with the rest of the world through messages and commands(, and for Event Sourced Entities, events)--all of which decouple a system’s components. If one instance, or even a whole service, fails, it is possible for the rest of the system to keep going with reduced capabilities, rather than creating a cascading failure that takes down the entire system.

  • A team can focus on features of a single service at a time, without worrying about what other services or teams are doing, or when they are releasing, allowing more parallel teams to focus on other services, allowing your development efforts to scale as needed.

  • You can upgrade services in a "rolling" fashion, where new instances are started before older instances are removed, allowing new versions to be deployed with no downtime or interruption.