Skip to content

Commit ae9f862

Browse files
authored
doc: reduce db connections with SliceRangeShardAllocationStrategy (#582)
1 parent cc4aa83 commit ae9f862

File tree

9 files changed

+108
-28
lines changed

9 files changed

+108
-28
lines changed

core/src/test/scala/akka/persistence/r2dbc/CborSerializable.scala

-7
This file was deleted.

core/src/test/scala/akka/persistence/r2dbc/JsonSerializable.scala

-7
This file was deleted.

core/src/test/scala/akka/persistence/r2dbc/PayloadSpec.scala

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import akka.persistence.r2dbc.TestActors.DurableStatePersister
1717
import akka.persistence.r2dbc.TestActors.Persister
1818
import akka.persistence.r2dbc.internal.codec.PayloadCodec
1919
import akka.persistence.r2dbc.internal.codec.PayloadCodec.RichRow
20+
import akka.serialization.jackson.JsonSerializable
2021

2122
/**
2223
* The purpose of this test is to verify JSONB payloads, but it can also be run with ordinary BYTEA payloads. To test

core/src/test/scala/akka/persistence/r2dbc/TestConfig.scala

-6
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,6 @@ object TestConfig {
4444
refresh-interval = 1s
4545
}
4646
}
47-
akka.actor {
48-
serialization-bindings {
49-
"akka.persistence.r2dbc.CborSerializable" = jackson-cbor
50-
"akka.persistence.r2dbc.JsonSerializable" = jackson-json
51-
}
52-
}
5347
akka.actor.testkit.typed.default-timeout = 10s
5448
"""))
5549
.withFallback(defaultConfig)

docs/src/main/paradox/data-partition.md

+26
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,32 @@ Each data partition corresponds to a table. You can copy the DDL statements for
7979
data partition suffix. For example `event_journal_0`, `event_journal_0_slice_idx`, `event_journal_1`, `event_journal_1_slice_idx`.
8080
Note that the index must also reference the parent table with same data partition suffix.
8181

82+
## Reducing number of database connections
83+
84+
When using the @extref:[default allocation strategy for Akka Cluster Sharding](akka:typed/cluster-sharding.html#shard-allocation)
85+
the there is no correlation between the slice of the entity and to which node the entity will be allocated. That means
86+
that there will be database connections from an Akka node to each of the databases. With a large Akka cluster each
87+
database would have to handle many connections, maybe more than its connection limit. That would be an inefficient
88+
use of resources on both the Akka side and the databases.
89+
90+
To reduce number of connections you can change the allocation strategy to @apidoc[SliceRangeShardAllocationStrategy].
91+
It will collocate entities with the same slice and contiguous range of slices to the same Akka node. Thereby
92+
the connections from one Akka node will go to one or a few databases since the database sharding is based on
93+
slice ranges.
94+
95+
Java
96+
: @@snip [ShardingDocExample](/docs/src/test/java/jdocs/home/sharding/ShardingDocExample.java) { #sharding-init }
97+
98+
Scala
99+
: @@snip [ShardingDocExample](/docs/src/test/scala/docs/home/sharding/ShardingDocExample.scala) { #sharding-init }
100+
101+
102+
Note that `SliceRangeShardAllocationStrategy` also requires change of the message extractor to
103+
@apidoc[SliceRangeShardAllocationStrategy.ShardBySliceMessageExtractor].
104+
105+
Do not change shard allocation strategy in a rolling update. The cluster must be fully stopped and then started again
106+
when changing to a different allocation strategy.
107+
82108
## Changing data partitions
83109

84110
The configuration of data partitions and databases **must not** be changed in a rolling update, since the data must
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (C) 2024 Lightbend Inc. <https://www.lightbend.com>
3+
*/
4+
package jdocs.home.sharding;
5+
6+
//#sharding-init
7+
import akka.actor.typed.ActorSystem;
8+
import akka.actor.typed.Behavior;
9+
import akka.cluster.sharding.typed.SliceRangeShardAllocationStrategy;
10+
import akka.cluster.sharding.typed.javadsl.ClusterSharding;
11+
import akka.cluster.sharding.typed.javadsl.Entity;
12+
import akka.cluster.sharding.typed.javadsl.EntityTypeKey;
13+
import akka.persistence.Persistence;
14+
15+
//#sharding-init
16+
17+
public class ShardingDocExample {
18+
public static class DeviceEntity {
19+
public interface Command {
20+
}
21+
22+
public static final EntityTypeKey<Command> ENTITY_TYPE_KEY =
23+
EntityTypeKey.create(Command.class, "device");
24+
25+
public static Behavior<Command> create(String deviceId) {
26+
return null;
27+
}
28+
}
29+
30+
public static void example() {
31+
ActorSystem<?> system = null;
32+
33+
//#sharding-init
34+
ClusterSharding.get(system).init(Entity.of(DeviceEntity.ENTITY_TYPE_KEY, entityContext ->
35+
DeviceEntity.create(entityContext.getEntityId()))
36+
.withMessageExtractor(new SliceRangeShardAllocationStrategy.ShardBySliceMessageExtractor<>(
37+
DeviceEntity.ENTITY_TYPE_KEY.name(), Persistence.get(system)))
38+
.withAllocationStrategy(new SliceRangeShardAllocationStrategy(10, 0.1)));
39+
//#sharding-init
40+
}
41+
}

docs/src/test/scala/docs/home/CborSerializable.scala

-7
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (C) 2024 Lightbend Inc. <https://www.lightbend.com>
3+
*/
4+
package docs.home.sharding
5+
6+
//#sharding-init
7+
import akka.actor.typed.ActorSystem
8+
import akka.actor.typed.Behavior
9+
import akka.cluster.sharding.typed.SliceRangeShardAllocationStrategy
10+
import akka.cluster.sharding.typed.SliceRangeShardAllocationStrategy.ShardBySliceMessageExtractor
11+
import akka.cluster.sharding.typed.scaladsl.ClusterSharding
12+
import akka.cluster.sharding.typed.scaladsl.Entity
13+
import akka.cluster.sharding.typed.scaladsl.EntityTypeKey
14+
import akka.persistence.Persistence
15+
16+
//#sharding-init
17+
18+
object ShardingDocExample {
19+
object DeviceEntity {
20+
sealed trait Command
21+
22+
val EntityKey: EntityTypeKey[Command] =
23+
EntityTypeKey[Command]("DeviceEntity")
24+
25+
def apply(deviceId: String): Behavior[Command] = ???
26+
}
27+
28+
val system: ActorSystem[_] = ???
29+
30+
//#sharding-init
31+
ClusterSharding(system).init(
32+
Entity(DeviceEntity.EntityKey)(entityContext => DeviceEntity(entityContext.entityId))
33+
.withMessageExtractor(
34+
new ShardBySliceMessageExtractor[DeviceEntity.Command](DeviceEntity.EntityKey.name, Persistence(system)))
35+
.withAllocationStrategy(new SliceRangeShardAllocationStrategy(10, 0.1)))
36+
//#sharding-init
37+
38+
}

project/Dependencies.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,6 @@ object Dependencies {
8888
// r2dbcPostgres is already a transitive dependency from core, but
8989
// sometimes sbt doesn't understand that ¯\_(ツ)_/¯
9090
r2dbcPostgres,
91-
TestDeps.akkaPersistenceTyped)
91+
TestDeps.akkaPersistenceTyped,
92+
"com.typesafe.akka" %% "akka-cluster-sharding-typed" % AkkaVersion)
9293
}

0 commit comments

Comments
 (0)