...
Code Block | ||
---|---|---|
| ||
{ "type": "data", "name": "AddVoterRecord", "validVersions": "0", "flexibleVersions": "0+", "fields": [ { "name": "Version", "type": "int16", "versions": "0+", "about": "The version of the add voter record" }, { "name": "VoterId", "type": "int32", "versions": "0+", "entityType": "brokerId", "about": "The IDreplica id of the voter getting added to the topic partition" }, { "name": "VoterUuid", "type": "uuid", "versions": "0+", "about": "The replicadirectory generated UUIDid of the replicavoter getting added as a voter to the topic partition" }, { "name": "EndPoints", "type": "[]Endpoint", "versions": "0+", "about": "The endpoint that can be used to communicate with the voter", "fields": [ { "name": "Name", "type": "string", "versions": "0+", "mapKey": true, "about": "The name of the endpoint." }, { "name": "Host", "type": "string", "versions": "0+", "about": "The hostname." }, { "name": "Port", "type": "uint16", "versions": "0+", "about": "The port." }, { "name": "SecurityProtocol", "type": "int16", "versions": "0+", "about": "The security protocol." } ]}, { "name": "KRaftFeatureKRaftVersionFeature", "type": "KRaftVersionFeature", "versions": KRaftFeature"0+", "about": "The range of versions of the protocol that the replica supports", "fields": [ { "name": "MinSupportedVersion", "type": "int16", "versions": "0+", "fieldsabout": [ ] } |
Handling
"The minimum supported KRaft protocol version" },
{ "name": "MaxSupportedVersion", "type": "int16", "versions": "0+",
"about": "The maximum supported KRaft protocol version" }
]}
]
} |
Handling
KRaft replicas will KRaft replicas will read all of the control records in the snapshot and the log irrespective of the commit state and HWM. When a replica encounters an AddVoterRecord it will add the replica ID and UUID to its voter set. If the replica getting added is itself then it will allow the transition to prospective candidate when the fetch timer expires. The fetch timer is reset whenever it receives a successful Fetch or FetchSnapshot response.
...
A control record for instructing the voters to remove a new voter to from the topic partition. This record can exist in the log but not the snapshot of a topic partition.
...
Code Block | ||
---|---|---|
| ||
{ "type": "data", "name": "RemoveVoterRecord", "validVersions": "0", "flexibleVersions": "0+", "fields": [ { "name": "Version", "type": "int16", "versions": "0+", "about": "The version of the addremove voter record"}, { "name": "VoterId", "type": "int32", "versions": "0+", "entityType": "brokerId", "about": "The replica IDid of the voter getting removed from the topic partition"}, { "name": "VoterUuid", "type": "uuid", "versions": "0+", "about": "The replicadirectory generated UUIDid of the replicavoter getting removed as a voter from the topic partition"} ] } |
...
Each KRaft topic partition has a quorum state (QuorumStateData) that gets persisted in the qurorumquorum-state
.json file in the directory for the topic partition.
A new field called ReplicaUuid will get added to QuorumStateData . Each KRaft replica will store a locally generated UUID in this field. The replica will generate and persist an UUID when it reads a version 0 of the QuorumStateData or if the QuorumStateData hasn't been persistent in the past.
The following changes will be made to this state:
- ClusterId will get removed in version 1. This field is not used because the cluster id is persisted in
<metadata.log.dir>/meta.properties
. - AppliedOffset will get removed in version 1. This field is not used in version 0. The field will get removed because it implied an inclusive offset. This is not correct because the default value is 0.
- VoterUuid will get added in version 1. The voting replica will persist both the voter ID and UUID of the candidate for which it voted.
- AppliedRecord will get added in version 1. This is the newest record that the KRaft client has read and applied to update the current set of voters. EndOffset is exclusive and represents the next offset that the KRaft client should read if available.
- CurrentVoters will get extended in version 1 to include the voter's directory id or UUID.
Version 0 of this data will get written if the kraft.version
is 0. Version 1 of this data will get written if the kraft.version
is 1Remove the CurrentVoters field from QuorumStateData . This information will instead be persisted in the log and snapshot using the AddVoterRecord and RemoveVoterRecord.
Code Block | ||
---|---|---|
| ||
{ "type": "data", git diff upstream/trunk raft/src/main/resources/common/message/QuorumStateData.json diff --git a/raft/src/main/resources/common/message/QuorumStateData.json b/raft/src/main/resources/common/message/QuorumStateData.json index d71a32c75d..34881f05ff 100644 --- a/raft/src/main/resources/common/message/QuorumStateData.json +++ b/raft/src/main/resources/common/message/QuorumStateData.json @@ -16,19 +16,25 @@ { "type": "data", "name": "QuorumStateData", - "validVersions": "0", + "validVersions": "0-1", "flexibleVersions": "0+", "fields": [ - {"name": "ClusterId", "type": "string", "versions": "0+"}, - {"name": "LeaderId", "type": "int32", "versions": "0+", "default": "-1"}, - {"name": "LeaderEpoch", "type": "int32", "versions": "0+", "default": "-1"}, - {"name": "VotedId", "type": "int32", "versions": "0+", "default": "-1"}, - {"name": "AppliedOffset", "type": "int64", "versions": "0+"}, - {"name": "CurrentVoters", "type": "[]Voter", "versions": "0+", "nullableVersions": "0+"} + { "name": "ClusterId", "type": "string", "versions": "0" }, + { "name": "QuorumStateDataLeaderId", "type": "int32", "validVersionsversions": "0+", "default": "-1" }, + { "name": "LeaderEpoch", "type": "int32", "flexibleVersionsversions": "0+", "default": "fields-1": [}, + { "name": "ClusterIdVotedId", "type": "stringint32", "versions": "0+", "default": "-1" }, + { "name": "ReplicaUuidVotedUuid", "type": "uuid", "versions": "1+" }, + { "aboutname": "The locally generated UUID for this replica.", AppliedOffset", "type": "int64", "versions": "0" }, + { "name": "LeaderIdAppliedRecord", "type": "int32AppliedRecord", "versions": "01+", "default": "-1"}, fields": [ + { "name": "LeaderEpochEndOffset", "type": "int32int64", "versions": "01+", "default": "-1"}, + { "name": "VotedIdEpoch", "type": "int32", "versions": "01+", "default": "-1" } + ]}, + { "name": "VotedUuidCurrentVoters", "type": "uuid[]Voter", "versions": "10+", "nullableVersions": "10+" } ], "defaultcommonStructs": "null" }, [ { "name": "AppliedOffsetVoter", "typeversions": "int640+", "versionsfields": "0+"}, [ - { "name": "CurrentVotersVoterId", "type": "[]Voterint32", "versions": "0", "nullableVersions": "0+"} + ], "commonStructs": [ { "name": "VoterVoterId", "versionstype": "0int32", "fieldsversions": [ "0+" }, + { "name": "VoterIdVoterUuid", "type": "int32uuid", "versions": "01+" } ]} ] } |
RPCs
AddVoter
Request
This RPC can be sent by an administrative client to add a voter to the set of voters. This RPC can be sent to a broker or controller. The broker will forward the request to the controller.
...