-
Notifications
You must be signed in to change notification settings - Fork 542
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[design] Command/Query Asymmetry #290
Comments
Thanks for the great question. The current approach is all about avoiding memory allocation. When a proposal is applied, the proposal entry is already in memory. When an integer is all what you want to return, e.g. a status code indicating the outcome of applied proposal, such an uint64 value helps to avoid any extra memory allocation. Some users might want to return an arbitrary struct for his/her updates implemented using proposals, it not recommended (which is documented). I thus didn't pay much attention to that []byte slice returned in Result. For reads, according memory, dragonboat initially had a []byte slice as input to indicate what to be queried and it returns a []byte slice as the result. It was probably thought to be not that useful to return just an integer as the result. That worked for myself pretty well for quite long time until someone complained that his/her code is being forced to keep serializing/deserializing query inputs and results. At that time, returning an interface{} would guarantee an allocation, so when query input and result are converted to interface{}, NAReadLocalNode (NA means No Allocation) was added to use the existing []byte input and output to avoid allocations caused by having that interface{}. I think you are 100% right, when you put those APIs together, they look strange & confusing when exhibiting such mentioned asymmetry. Any recommendation on how to make it better & simple while still minimizing allocations? Will be great if I can get some feedbacks. |
Thanks for the response. Right now I'm developing an internal API which will allow any host in the cluster to receive a request for any shard and forward it internally to a host that has the necessary replica. syntax = "proto3";
option go_package = "github.com/logbn/zongzi/internal";
// MessageService provides a gRPC api for internal host communication
service MessageService {
// Propose provides unary request/response command forwarding
rpc Propose(Request) returns (Response) {}
// Stream provides streaming proposal forwarding
rpc Stream(stream Request) returns (stream Response) {}
// Query provides unary request/response query forwarding
rpc Query(Request) returns (Response) {}
// Watch provides streaming query response forwarding
rpc Watch(Request) returns (stream Response) {}
}
message Request {
uint64 shard_id = 1;
uint64 replica_id = 2;
bool linear = 3;
bytes data = 15;
}
message Response {
uint64 value = 1;
string error = 2;
bytes data = 15;
} Serialization is going to need to happen either way for queries forwarded across the internal API. The asymmetry is not that big a deal. The empty interface queries work fine for me because I can just define my own interface for what a statemachine should be and use a wrapper to hide the difference. I ask because having spent a long time using HTTP, I'm accustomed to receiving a status code response for both writes and reads. I imagine that a lot of developers might feel the same. I feel like a uniform Command/Query interface, while possibly less efficient, might make the interface more relatable and the query serialization overhead might not be a performance bottleneck if the query already has to be serialized across the network. I think I will include |
Closing as asked and answered. Maybe consider enabling Discussions for this repo to make conversations like this more discoverable. |
Sorry that I missed your reply above as the issue was closed and I was just looking at open issues.
agreed.
I am not worried about the cost of serialization, I am more concerned with allocation. depends on how serialization is done, sometimes more serializations lead to more allocations. if you look at the raftpb folder, there are some changes applied to protobuf generated code to avoid some unwanted allocations.
totally agreed. there is no cost of returning such an uint64, it is useful to quite a few users, makes the interface more consistent. please allow a few weeks (as I am busy with another consensus related project I am building), this change will definitely be in for v4.0. thanks again for raising and addressing this issue. |
Proposal
results include a uint64Value
and someData
in the form of a[]byte
.Query
results include anerror
and someData
in the form of aninterface{}
or[]byte
What is the purpose of
Value uint64
and why is it not included in query method responses?The text was updated successfully, but these errors were encountered: