Skip to content

Commit

Permalink
doc: Reference docs for edge Replicated Event Sourcing
Browse files Browse the repository at this point in the history
  • Loading branch information
patriknw committed Dec 5, 2023
1 parent fd3e131 commit e8c8f43
Show file tree
Hide file tree
Showing 9 changed files with 431 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Replicated Event Sourcing gives:

* redundancy to tolerate failures in one location and still be operational
* serve requests from a location near the user to provide better responsiveness
* allow updates to an entity from several locations
* balance the load over many servers

The replicas of the entities are running in separate Akka Clusters for the reasons described in
Expand Down
48 changes: 37 additions & 11 deletions akka-edge-docs/src/main/paradox/feature-summary.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Feature Summary

The main feature of Akka Edge is Projections over gRPC - asynchronous brokerless service-to-service communication.
Akka Edge has two main features:

1. Projections over gRPC - asynchronous brokerless service-to-service communication
1. Replicated Event Sourcing over gRPC - active-active entities

## Projections over gRPC

Expand Down Expand Up @@ -111,16 +114,39 @@ H2 database should not be used when the service is an Akka Cluster with more tha
* @extref[Reference documentation of Akka Projection gRPC](akka-projection:grpc.html)
* @extref[Reference documentation of Akka Projection gRPC with producer push](akka-projection:grpc-producer-push.html)

## Replicated Event Sourcing is not for Edge
## Replicated Event Sourcing over gRPC

You would use Replicated Event Sourcing over gRPC for entities that can be updated in more than one geographical
location, such as edge Point-of-Presence (PoP) and different cloud regions. This makes it possible to implement
patterns such as active-active and hot standby.

![Diagram showing services using Replicated Event Sourcing over gRPC between cloud and edge services](images/edge-res.svg)

Replicated Event Sourcing gives:

* redundancy to tolerate failures in one location and still be operational
* serve requests from a location near the user to provide better responsiveness
* allow updates to an entity from several locations
* balance the load over many servers

The replicas of the entities are running in separate Akka Clusters in the cloud and edge.
A reliable event replication transport over gRPC is used between the Akka Clusters. The replica entities belong
to the same logical Microservice, i.e. same [Bounded Context](https://martinfowler.com/bliki/BoundedContext.html)
in Domain-Driven Design (DDD) terminology.

@extref[Replicated Event Sourcing over gRPC](akka-distributed-cluster:feature-summary.html#replicated-event-sourcing-over-grpc)
is a useful feature in Akka Distributed Cluster, but it is not recommended for edge use cases. The reasons why it is currently
not supported for Akka Edge are:
Note that the connection is established from the edge service. For this you need to setup @extref[Akka Replicated Event Sourcing gRPC with edge topology](akka-projection:grpc-replicated-event-sourcing-transport.html#edge-topology).

* It requires gRPC connectivity in both directions between the replicas.
* The overhead of CRDT metadata may become too large when there are many 100s of replicas, or if the replicas dynamically change over time.
Filters can be used to define that a subset of the entities should be replicated to certain locations.
The filters can be changed at runtime.

@@@ note
Events are stored in a database for each replica. There is no direct database access between a replica and
the database of another replica, which means different databases, and even different database products, can
be used for the replicas. For example, Postgres in the Cloud and H2 at the edge.
@@@

### Learn more

That said, if you can overcome these restrictions it can be a good fit also for edge use cases. You might have
a network topology that allows establishing connections in both directions (e.g. VPN solution) and you might not have
that many edge services. The latter can also be mitigated by strict filters so that not all entities are replicated
everywhere.
* FIXME link to guide
* @extref[Reference documentation of Akka Replicated Event Sourcing](akka:typed/replicated-eventsourcing.html)
* @extref[Reference documentation of Akka Replicated Event Sourcing over gRPC](akka-projection:grpc-replicated-event-sourcing-transport.html)
352 changes: 352 additions & 0 deletions akka-edge-docs/src/main/paradox/images/edge-res.drawio

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions akka-edge-docs/src/main/paradox/images/edge-res.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions akka-edge-docs/src/main/paradox/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ active-active entities or one-way event replication as provided by @extref[Akka
The edge services connect to the cloud services and can use event replication in both directions to communicate with
cloud services. An edge service can be a single node or form a small Akka Cluster.

The cloud and edge services may use active-active entities or one-way event replication between cloud and edge.

The edge service can be fully autonomous and continue working when there are network disruptions, or if the
edge service chooses to not always be connected. It will catch up on pending events when the communication is
established again.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ class EdgeReplicationIntegrationSpec(testContainerConf: TestContainerConf)
10.seconds,
8,
R2dbcReplication())
.withEdgeReplication(true)
}

selfReplicaId match {
Expand Down
3 changes: 3 additions & 0 deletions akka-projection-grpc/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ akka.projection.grpc {

replication {

# Allow edge replicas to connect and replicate updates
accept-edge-replication = off

# Replicated event sourcing from edge sends each event over sharding, in case that delivery
# fails or times out, retry this number of times, with an increasing backoff conntrolled by
# the min and max backoff settings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ object ReplicationSettings {
parallelUpdates = config.getInt("parallel-updates"),
projectionProvider = replicationProjectionProvider,
eventProducerInterceptor = None,
acceptEdgeReplication = false,
acceptEdgeReplication = replicationConfig.getBoolean("accept-edge-replication"),
configureEntity = identity,
producerFilter = _ => true,
initialConsumerFilter = Vector.empty,
Expand Down
40 changes: 32 additions & 8 deletions docs/src/main/paradox/grpc-replicated-event-sourcing-transport.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,12 @@ and other connection options as when using Akka gRPC directly. For more details
It is also possible to set up @apidoc[akka.projection.grpc.replication.*.ReplicationSettings] through APIs only and not rely
on the configuration file at all.

### Binding the publisher
### Fully connected topology

In a network topology where each replica cluster can connect to each other replica cluster the configuration should
list all replicas and gRPC server must be started in each replica.

#### Binding the publisher

Binding the publisher is a manual step to allow arbitrary customization of the Akka HTTP server and combining the endpoint
with other HTTP and gRPC routes.
Expand Down Expand Up @@ -172,7 +177,28 @@ Scala
Java
: @@snip [ShoppingCartServer.java](/samples/grpc/shopping-cart-service-java/src/main/resources/grpc.conf) { #http2 }

### Serialization of events
### Edge topology

In some use cases it is not possible to use a @ref[fully connected topology](#fully-connected-topology), for example because of firewalls or NAT in front of each producer. The consumer may also not know about all producers up front.

This is typical when using @extref:[Replicated Event Sourcing at the edge](akka-edge:feature-summary.html#replicated-event-sourcing-over-grpc).
where the connection can only be established from the edge service to the cloud service.

For this purpose, Akka Replicated Event Sourcing gRPC has a mode where the replication streams for both consuming
and producing events are initiated by one side. In this way a star topology can be defined, and it's possible
to combine with replicas that are fully connected.

You would still define how to connect to other replicas as described above, but it's only needed on the edge side, and
it would typically only define one or a few cloud replicas that it will connect to. A gRPC server is not needed on the
edge side, because there are no incoming connections.

On the edge side you start with `Replication.grpcEdgeReplication`.

On the cloud side you would start with `Replication.grpcReplication` as described above, but with the addition
`withEdgeReplication(true)` in the @apidoc[ReplicationSettings] or enable `akka.projection.grpc.replication.accept-edge-replication`
configuration.

## Serialization of events

The events are serialized for being passed over the wire using the same Akka serializer as configured for serializing
the events for storage.
Expand All @@ -192,26 +218,24 @@ By default, events from all Replicated Event Sourced entities are replicated.
The same kind of filters as described in @ref:[Akka Projection gRPC Filters](grpc.md#filters) can be used for
Replicated Event Sourcing.

The producer defined filter:
The producer filter is defined with `withProducerFilter` or `withProducerFilterTopicExpression` in @apidoc[ReplicationSettings]:

Scala
: @@snip [ShoppingCart.scala](/samples/replicated/shopping-cart-service-scala/src/main/scala/shopping/cart/ShoppingCart.scala) { #init-producerFilter }

Java
: @@snip [ShoppingCart.java](/samples/replicated/shopping-cart-service-java/src/main/java/shopping/cart/ShoppingCart.java) { #init-producerFilter }

Consumer defined filters are updated as described in @ref:[Akka Projection gRPC Consumer defined filter](grpc.md#consumer-defined-filter)
The initial consumer filter is defined with `withInitialConsumerFilter` in @apidoc[ReplicationSettings].
Consumer defined filters can be updated in runtime as described in @ref:[Akka Projection gRPC Consumer defined filter](grpc.md#consumer-defined-filter)

One thing to note is that `streamId` is always the same as the `entityType` when using Replicated Event Sourcing.

The entity id based filter criteria must include the replica id as suffix to the entity id, with `|` separator.

Replicated Event Sourcing is bidirectional replication, and therefore you would typically have to define the same
filters on both sides. That is not handled automatically.

## Sample projects

Source code and build files for complete sample projects can be found in the @extref:[Akka Distributed Cluster Guide](akka-distributed-cluster:guide/3-active-active.html).
Source code and build files for complete sample projects can be found in the @extref:[Akka Distributed Cluster Guide](akka-distributed-cluster:guide/3-active-active.html) and @extref:[Akka Edge Guide](akka-edge:guide.html).

## Security

Expand Down

0 comments on commit e8c8f43

Please sign in to comment.