Replies: 4 comments 3 replies
|
Cassandr uses a peer-to-peer architecture with no dedicated controller nodes. We may borrow some ideas from them.
|
|
Simple notes before going to work.
|
|
I found that we have to fix the update_member logic. Our implementation currently makes state with higher incarnation number as the winner, but the paper states that This is due to the fact that |
|
Example case of what could happen when we make
If our update logic prefers higher incarnation over state, those nodes would revert B from Dead → Alive, resurrecting a node that the cluster already decided to remove. By making Dead absolute:
This guarantees that failure information propagates permanently, even in the presence of message reordering and delays. |
Uh oh!
There was an error while loading. Please reload this page.
Maintaining separate metadata store will introduce:
And this is not only when we develop the project but also for those who would potentially tab into the project.
Assigning a dedicated controller role to some node(or group of) can be an option, and in fact that's a strategy taken by Kafka 4.0
That has two issues:
So, In this discussion, I suggest the followings:
Scalable Weakly-consistent Infection-style Membership(SWIM)Dynamically-Sharded Replicated State Machine(DS-RSM)SWIM
SWIM was created to solve the scaling limitations of traditional "heartbeat" protocols (where every node checks on every other node, which causes network congestion as the cluster grows).
SWIM has two main components, and this is where the distinction lies:
This part is unique to SWIM and is not standard gossip.
Direct Ping: Node A picks a random Node B and pings it.Indirect Ping: If Node B doesn't reply, Node A asks specific other nodes (C and D) to ping B on its behalf (this is called ping-req).This mechanism prevents false positives (marking a node dead just because the link between A and B is slow).
Once Node A confirms that Node B is dead (via the Failure Detection phase), it needs to tell everyone else.
Instead of broadcasting to the whole cluster "B IS DEAD!", Node A piggybacks this information onto its future messages to other nodes(e.g., when it probes).
This information spreads "infection-style" (gossip) through the cluster until everyone updates their membership list.
Scenario: Node A knows that Node C is dead.Action: When Node A sends its regular Ping to Node B, it adds a tiny footer to the message: "By the way, C is dead."Cost: This adds a few bytes to a packet that was going to be sent anyway. It does not create a new packet.In essence, SWIM is to maintain the membership list in the cluster.
We can consider handling the following event types:
Alive(Join/Heartbeat)Incarnation Number(more on in the next subsection).Suspect(Failure detection)Confirm(Dead)Suspectstate. All nodes remove the node in question from their ring calculations.And as "Piggybacking", we can introduce the following event types as well:
ShardLeader(Metadata Routing)Preventing "Zombie Loop" Using Incarnation Number
Without
Incarnation Numbers, distributed failure detection is impossible to stabilize.Node Bcan’t reachNode A.Node Bgossips: "Node Ais Suspect!"Node Ahears this. It shouts back: "No! I am Alive!"Node Chears both messages. Which one is true?Node Akeeps getting kicked out of the cluster even though it is healthy.The
Incarnation Numberacts as a timestamp. The cluster follows a strict logic hierarchy when comparing two messages about the same node.It follows the simple rule:
For more on SWIM, read this paper.
Dynamically-Sharded Replicated State Machine(DS-RSM)
Rather than maintaining a monolithic metadata store (like a global Etcd/Zookeeper) or a single heavy Controller Quorum (like Kafka KRaft), we distribute the state management responsibility across the nodes themselves.
How it achieves that is as follows:
Dynamic Sharding: Metadata is partitioned (sharded) based on resource keys (e.g., Topic ID). These shards are distributed among the compute nodes.
Localized Consensus: Instead of one global Raft group reaching consensus for every operation in the system, it forms small, dynamic Raft groups (state machines) only for the nodes involved in a specific shard.
Elimination of External Dependencies: This removes the need for an external KV store. The application nodes are the data store for their own metadata.
Linear Scalability: As you add nodes, you automatically add more CPU/Disk capacity for metadata processing. The "Controller" capacity scales linearly with the "Data" capacity.
How it interplays
Decision
Shard #45(The Raft Group) decides: "Topic-Blue is assigned to Node-Y."Shard #45.Propagation
The worker node (say,
Node-Y) needs to know it has work to do. It does not "poll" the shard.It's the Shard Leader that dictates it.
Shard #45sends a direct RPC command toNode-Y.OpenTopic(Topic-Blue, Epoch=1)Node-Yspins up the resources for that topic and replies OK.Node-Ynow has a local in-memory flag: "I own Topic-Blue."Propagation Clients (The "Pull + Cache")
This is where the scaling magic can happen.
We do not broadcast topic assignments to all brokers. (Broadcasting 1 million topic assignments would kill the network).
Instead, it can be implemented as "need-to-know" basis(lazy loading)
Node-B: "Connect me to Topic-Blue."Node-Bchecks its Cache: Empty.Node-Bcalculates hash (Hash(Topic) = 123). It consults its local SWIM-maintained Ring Map to see that hash 123 belongs toShard #45(Leader IP: 10.0.0.5).Shard #45replies: "Node-Y."Node-Bcaches this: Topic-Blue -> Node-Y.Node-Broutes the data to Node-Y.Handling Stale Cache
This is the most important part. What happens if
Shard #45changes its mind and moves the topic toNode-Z,but other nodes still think it is on
Node-Y?This is called a stale cache, and it is resolved via error handling:
The Move:
Shard #45moves the topic to Node-Z. Node-Y is told to close it (or crashes).The Mistake:
Node-B(using stale cache) tries to send data to Node-Y.The Rejection:
The Fix:
Node-Breceives the error.Node-Binvalidates its cache entry for Topic-Blue.Node-BasksShard #45again: "Who owns Topic-Blue?"Shard #45replies: "Node-Z."Node-Bupdates cache and retries.All reactions