Skip to content

Conversation

@ktoso
Copy link
Member

@ktoso ktoso commented Jun 16, 2020

Motivation:

The membership gossip is sent around "constantly", it should be as small as possible.
It should scale O(n) and NOT worse (like it did today) with number of nodes.

Modifications:

  • use protobuf all the way
  • encode the membership fully with unique nodes
  • the seen table and other fields never encode unique nodes, but refer to the ones present in membership by using their unique IDs saving a ton of repetition in the rendered data.
    • this is not fully generalized but could be if we need to -- it would also help CRDTs after all perhaps.

Result:

  • smaller messages and less load from the gossip subsystem on the system
  • more stable system

ActorAddress actorAddress = 1;
UniqueNode uniqueNode = 2;
uint32 uniqueNodeIdentifier = 3;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is new, we allow carrying just the node id

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

number ok? don't need to be string?

is this the same as ClusterMembershipSeenTableRow.uniqueNodeID? maybe use either *ID or *Identifier in all the names?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good point, I couldn't decide what to go with, I guess ID

// During deserialization the fields can be resolved against the membership to obtain full UniqueNode values if necessary.
uint32 ownerUniqueNodeID = 2;
ClusterMembershipSeenTable seenTable = 3;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments explain what we do here


public var node: Node
public let nid: NodeID
public let nid: UniqueNodeID
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that rename dawned on me during this work, much more correct i guess


/// Serialize using uniqueNodeIdentifier specifically (or crash);
/// Used in situations where an enclosing message already has the unique nodes serialized and we can save space by avoiding to serialize them again.
public func toCompactReplicaNodeIDProto(context: Serialization.Context) throws -> ProtoVersionVector {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a bit manual but good enough for now... we could generalize this

TODO: make a ticket for it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ticket #677

public func member(byUniqueNodeID nid: UniqueNode.ID) -> Cluster.Member? {
// TODO: make this O(1) by allowing wrapper type to equality check only on NodeID
self._members.first(where: { $0.key.nid == nid })?.value
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: make a ticket

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#678 Make Membership.member(byUniqueNodeID) O(1)

/// Base class to handle the repetitive setUp/tearDown code involved in most ActorSystem requiring tests.
// TODO: Document and API guarantees
open class ActorSystemTestBase: ClusteredNodesTestBase {
open class ActorSystemXCTestCase: ClusteredActorSystemsXCTestCase {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should have split this out into other changeset... can do tomorrow

let back = try system.serialization.deserialize(as: Cluster.Gossip.self, from: serialized)
"\(pretty: back)".shouldStartWith(prefix: "\(pretty: gossip)") // nicer human readable error
back.shouldEqual(gossip) // the actual sanity check
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the test showcasing the new thing. The "naive" impl ends up at 8000+ bytes here, and that's pretty bad; our new impl scales much better with cluster size as well.

Copy link
Member

@yim-lee yim-lee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of non-blocking suggestions/questions

ActorAddress actorAddress = 1;
UniqueNode uniqueNode = 2;
uint32 uniqueNodeIdentifier = 3;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

number ok? don't need to be string?

is this the same as ClusterMembershipSeenTableRow.uniqueNodeID? maybe use either *ID or *Identifier in all the names?

}

public struct NodeID: Hashable {
// TODO: move as UniqueNode.Identifier?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

case .uniqueNodeID(let nid):
replicaVersion.replicaID.uniqueNodeIdentifier = nid.value
case .actorAddress:
throw SerializationError.unableToSerialize(hint: "Can't serialize using unique node identifier as replica id! Was: \(replicaID)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the error message correct?

Suggested change
throw SerializationError.unableToSerialize(hint: "Can't serialize using unique node identifier as replica id! Was: \(replicaID)")
throw SerializationError.unableToSerialize(hint: "Can't serialize using actor address as replica id! Was: \(replicaID)")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

return data.stringDebugDescription()
case .nioByteBuffer(let bufffer):
return bufffer.stringDebugDescription()
case .nioByteBuffer(let buffer):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

@ktoso
Copy link
Member Author

ktoso commented Jun 17, 2020

Could not answer in line for some reason:

uint32 uniqueNodeIdentifier = 3;

number ok? don't need to be string?

is this the same as ClusterMembershipSeenTableRow.uniqueNodeID? maybe use either *ID or *Identifier in all the names?

Yes, that's integer, the same as the ClusterMembershipSeenTableRow.uniqueNodeID now using uniqueNodeID everywhere

@ktoso
Copy link
Member Author

ktoso commented Jun 17, 2020

Ci failure is a bit mysterious: #680 FAILED: weird build timeouts

@ktoso ktoso merged commit c6c137f into apple:master Jun 17, 2020
@ktoso ktoso deleted the wip-compression-wire-format-tables branch June 17, 2020 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants