DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
| Table of Contents |
|---|
Ignite use a few protocols of inter-node message exchange:
All protocols have own serialization mechanisms and doesn't support message exchange with node of another version. For making Rolling upgrade feature possible we must make these protocols compatible between Ignite versions.
Goal is to design a communication protocol that supports messages exchange between nodes with different Ignite versions.
Prerequisites:
...
...
There is an additional serialization protocol between control.sh (thin client) and server nodes
This protocol is out of scope of this proposal.
The joining node version must be checked versus actual Ignite versions in a cluster (within OnDiscoveryNodeValidationProcessor):
There should be one serialization framework for communication and discovery protocol.
MessageWriter, MessageReader logic is depends on a remote IgniteProductVersion.Message#writeTo, Message#readFrom is auto-generated and stored separately from Message classes.Message#writeObject - for serializing Objects (java functions, and user objects) with BinaryMarshaller.Message fields may contain:Message.@Order annotation.@Since, @Until annotations for Message classes and fields.(curVer - 1).These possible improvements can be implemented later. Ignite message code generator will support this features:
Communication protocol consist of 2 parts:
Message classes, including ser/des algorithm.Messages to remote node.Message - is base class for all messages transported between nodes. Proposed changes:
Message#writeTo and Message#readFrom in favor generated MessageSerializer. MessageSerializer#writeTo consumes MessageWriter that stores IgniteProductVersion of a receiver Message#writeTo consumes IgniteProductVersion of destination node and use it for serializing data for this version (mostly, for ignoring some fields).Message#readFrom MessageSerializer#readFrom consumes MessageReader that stores IgniteProductVersion of source node and use it for deserializing data (mostly, for setting default values of new fields).
| Code Block | ||||
|---|---|---|---|---|
| ||||
public interface MessageMessageSerializer { public boolean writeTo(Message msg, ByteBuffer buf, MessageWriter writer, IgniteProductVersion destVer); public boolean readFrom(Message msg, ByteBuffer buf, MessageReader reader,); } public interface MessageWriter { public IgniteProductVersion srcVerreceiverVersion(); } public interface MessageReader { public shortIgniteProductVersion directTypesenderVersion(); } |
@Since and @Until for Message classes and Message fields, to use it for generating code for Message#writeTo and Message#readFrom:| Code Block | ||||
|---|---|---|---|---|
| ||||
// Package where the Message is defined. package org.apache.ignite.internal.my.message; @Since(version = "2.19.0") public class MyMessage implements Message { @Order(0) private int id; /** Remove field. */ @Until(version = "2.20.0") @Order(1) private String rmFld; /** New field. */ @Since(version = "2.20.0") @Order(2) private String newFld; // Message must have setters//getters for Generatedall code@Ordered fromfields. theMethods schema ^. @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer, IgniteProductVersion destVernames are equal to a corresponding field name. public void id(int id) { this.id = id; } public int id() if (destVer.lessThan(2, 19, 0)) throw new IgniteException("Must not send the message to destination node"); if (!writer.writeString(id)) { return id; } public void newFld(String newFld) { this.newFld = newFld; } public String newFld() { return newFld; } } // Generated code from the message ^ for Ignite version 2.20.0. // Use the same package as corresponding message. package org.apache.ignite.internal.my.message; class MyMessageSerializer { public boolean writeTo(Message m, ByteBuffer buf, MessageWriter writer) { MyMessage msg = (MyMessage)m; IgniteProductVersion rcvVer = writer.receiverVersion(); return false writer.writeString(msg.id()); if (destVerrcvVer.lessThan(2, 20, 0)) { if (!writer.writeString(msg.rmFld()) return false; } if (destVerrcvVer.greaterThanEqual(2, 20, 0)) { if (!writer.writeString(msg.newFld()) return false; } return true; } @Overridepublic publicstatic boolean readFrom(Message m, ByteBuffer buf, MessageReader reader, IgniteProductVersion srcVer) { ) { MyMessage msg = (MyMessage)m; IgniteProductVersion idsrcVer = reader.readStringsenderVersion(); msg.id(reader.readString()); if (srcVer.greaterThanEquallessThan(2, 20, 0)) newFld = msg.rmFld(reader.readString()); if (srcVer.greaterThanEqual(2, 20, else0)) newFld = nullmsg.newFld(reader.readString()); return true; } } |
Rules to describe Message (must be automated and validated):
Message class or Message fields, but annotate it with @Until. @Order of fields.@Since. All such fields must be optional, default value is null. Handling the nulls is care of Message consumer on the reader side.Removing annotated entities is allowed after current version is greater than (@Until + 1) or (@Since + 1).
In case of transport protocol should be changed, Ignite must support -1 Ignite version.
FeatureTable class that used to track changes in transport protocol. Each entry must be annotated with @Since version.(@Since - 1) version. @Since version and notify release manager to drop support of old versions.Handshake algorithm is extended on new step - validating TcpCommunicationConfiguration consistency. Settings that affects both communicating nodes must be same:
...
...
https://protobuf.dev/programming-guides/encoding/
...
https://kafka.apache.org/protocol.html
KIP-482: The Kafka Protocol should Support Optional Tagged Fields