Skip to content

Commit 02ae136

Browse files
committed
docs(0028): extend shared subscription design description
1 parent bf8020d commit 02ae136

4 files changed

+74
-5
lines changed
Loading
25.1 KB
Loading

active/0028-assets/session-side-state.uml

+8
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ skinparam DefaultTextAlignment left
1414
(connecting) --> (replaying) :\
1515
lease_streams
1616

17+
(connecting) --> (disconnected) :\
18+
session induced disconnect
19+
1720
(replaying) --> (replaying): \
1821
renew_stream_lease(vsn)\n\
1922

@@ -28,6 +31,8 @@ renew_stream_lease(vsn)\n\
2831
(replaying) --> (updating) :\
2932
update_streams\n
3033

34+
(replaying) --> (disconnected) :\
35+
session induced disconnect
3136

3237
(updating) --> (updating) :\
3338
• update_streams\n\
@@ -42,4 +47,7 @@ renew_stream_lease(vsn_new)
4247
• invalidate\n\
4348
• update_streams(invalid vsns)
4449

50+
(updating) --> (disconnected) :\
51+
session induced disconnect
52+
4553
@enduml

active/0028-durable-shared-subscriptions.md

+66-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
## Changelog
44

55
* 2024-05-10: @savonarola Initial draft
6+
* 2024-06-28: @savonarola
7+
* Add the Agent abstraction
8+
* Describe thr two-side communication sequence between an Agent and the SGL
9+
* Describe the stream reassignment algorithm
610

711
## Abstract
812

@@ -28,11 +32,11 @@ SGL keeps track of topics belonging to the group, their streams, and stream stat
2832

2933
The groups' consumers are persistent sessions. They connect to the SGL, and the SGL leases them streams to consume. Sessions consume these streams together with their proper streams but do not persist the progress. Instead, they report the progress to the SGL.
3034

31-
SGL is responsible for reassigning streams to the other group consumers in case a consumer disconnects and for reassigning streams to the new consumers.
35+
SGL is responsible for reassigning streams to the other group of consumers in case a consumer disconnects and for reassigning streams to the new consumers.
3236

3337
![General Design](./0028-assets/general-design.png)
3438

35-
All communication between the consumers(sessions) and the SGL, SGLM, is done asynchronously because leaders may need to be spawned (this requires election) or may be running on a remote node.
39+
All communication between the consumers(sessions) and the SGL, SGLM is done asynchronously because leaders may need to be spawned (this requires election) or may be running on a remote node.
3640

3741
### Session Side
3842

@@ -43,12 +47,18 @@ The SSubHandler is passive, i.e., it does not contain any running processes. It
4347
A session is responsible for:
4448
* Initializing the SSubHandler data on session bootstrap.
4549
* Delivering Shared Sub-related messages (from timers, from other entities) to the SSubHandler.
46-
* Forwarding subscribe/unsubscribe `$shares/group/...` requests to the SSubHandler.
50+
* Forwarding subscribe/unsubscribe `$shared/group/...` requests to the SSubHandler.
4751
* Querying stream states (`stream_state()`) from SSubHandler for replay and reporting replay results to the SSubHandler.
4852

4953
### Shared Subscription Session Handler
5054

51-
SSubHandler data is a collection of Group Subscription FSMs (GSFSM) identified by the group ID.
55+
SSubHandler *lies in the domain of the session*. It knows the session's state, stores shared suscriptions and the related data in the session's state and uses **Agent** abstraction to communicate with the SGL. Agent provides the interface lying *outside* the session's domain.
56+
57+
### Agent
58+
59+
Agent is the entity that communicates with different SGLs. It speaks in the terms of streams and iterators, not knowing about sessions, subscriptions, etc.
60+
61+
Agent's data is a collection of Group Subscription FSMs (GSFSM) identified by the group ID.
5262

5363
```erlang
5464
#{
@@ -63,6 +73,7 @@ Each GSFSM contains the following states:
6373
* `connecting` - the initial state, the GSFSM is looking for a Group Subscription Leader (SGL).
6474
* `replaying` - the GSFSM is connected to the SGL and provides stream states for replay.
6575
* `updating` - the GSFSM is connected to the SGL and is updating the set of streams.
76+
* `disconnected` - the GSFSM is disconnected from the SGL.
6677

6778
### Protocol between Session and SGL
6879

@@ -128,10 +139,60 @@ In the `updating` state, the GSFSM accepts replay requests from the session side
128139

129140
* `{update_stream_states, VersionNew, StreamsNew, VersionOld, StreamsOld, ...}` - to the SGL to update the stream states. Both for active streams and for taken-over streams. If taken-over streams are fully acked, the according flag is sent for them.
130141

131-
### State transitions
142+
#### `disconnected` state
143+
144+
GSFSM can pass to the `disconnected` state from any other state. It happens when the session disconnects. When entering the `disconnected` state, the GSFSM sends a `disconnect` message to the SGL with the latest stream states.
145+
146+
#### State transitions
132147

133148
![State transitions](./0028-assets/session-side-state.png)
134149

150+
### Leader(SGL) side
151+
152+
Agent may have many GroupSMs (one for each subscription), each GroupSM is connected to its own Leader. So a Leader may have many Agents connected (through GroupSMs) to it.
153+
154+
The Leader tracks the state of each agent connected to it and has its own state machine for each agent. The Leader's view of the GroupSM's state can be one of the following:
155+
156+
* waiting_replaing
157+
* replaying
158+
* waiting_updating
159+
* updating
160+
161+
The target state of GroupSM and its representation in Leader is `replaying`. That is, when the GroupSM and the Leader agree on the leased streams, the Leader sends lease confirmations to the GroupSM, and the GroupSM sends iteration updates.
162+
163+
Other states are used to gracefully reassign streams to the GroupSM.
164+
165+
## Communication sequence
166+
167+
Below is the sequence diagram of the interaction. The full cycle is shown, from replaying-replaying to replaying-replaying states.
168+
169+
![GroupSM and Leader communication](./0028-assets/groupsm_leader_communication.png)
170+
171+
## Stream reassignment (rebalance)
172+
173+
We want the streams of a Leader be evenly distributed among the agents. The periodical rebalancing algorithm is the following.
174+
175+
* We discover new streams from DS, and mark _unassigned_ if there are any.
176+
* We do any changes only to _stable_ agents (those which are not in the `replaying` state).
177+
* We check that replaying agents have the _desired_ number of streams. The desired number is calculated as the total number of streams divided by the number of agents (+1, if not divisible evenly):
178+
```erlang
179+
DesiredStreamCount = case
180+
TotalStreamCount rem AgentCount of
181+
0 -> TotalStreamCount div AgentCount;
182+
_ -> (TotalStreamCount div AgentCount) + 1
183+
end.
184+
```
185+
* If the agent has more streams than desired, we _select streams for revocation_ and mark them as _revoked_. The streams still belong to the agent, but the agent goes to the 'updating' cycle, finishes stream replay, and returns them to the Leader. As soon as a stream is returned, it becomes _unassigned_.
186+
* If the agent has fewer streams than desired, we _select streams for assignment_ and mark them as assigned to the agent. The agent goes to the `updating` cycle in which it confirms the reception of the streams and starts replaying them.
187+
188+
So, there is no "direct transfer" of streams between agents. When e.g., a new agent connects, a typical scenario is:
189+
190+
* The agent connects to the Leader.
191+
* It may be assigned 0 streams just now as there are no free ones.
192+
* On the next rebalance, we see that some agents became overpopulated (since the number of agents increased). So, we select streams for revocation. There are no free streams yet. We also still see that the recently connected agent is underpopulated.
193+
* Gradually, the streams are returned to the Leader and become unassigned. This happens outside the iterations of the rebalance.
194+
* On one of the next rebalances, we see again that the recently connected agent is underpopulated, but now there are some free streams. We assign them to the agent.
195+
135196
### Configuration Changes
136197

137198
### Backwards Compatibility

0 commit comments

Comments
 (0)