-
Notifications
You must be signed in to change notification settings - Fork 1
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
RFC: Backward Compatibility of Stream Plan #43
base: main
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
feature: Backward Compatibility of Stream Plan | ||
authors: | ||
- "st1page" | ||
start_date: "2023/1/31" | ||
--- | ||
|
||
# Backward Compatibility of Stream Plan | ||
|
||
## Summary | ||
|
||
- distinguish the nightly and stable for SQL features and stream plan node protobuf. | ||
- use a Copy-on-Write style on changing the stable stream plan node protobuf. | ||
|
||
## Motivation | ||
|
||
In https://github.com/risingwavelabs/rfcs/issues/41, we discuss the backward compatibility. And the protobuf structure of stream plan nodes is a special part. | ||
- the plan node's structure usually modified more frequently than other protobuf structure such as catalog, especially when we are developing new SQL features and we even do not know how to do it right. The plan node's changes are not only adding some optional field(which can be solved by protobuf) but also of meaning and behaviors of the operator. For example, our state table information of streamAgg having breaking changed in 0.1.13 and in 0.1.16, the source executor is no longer responsible for generating row_id. And we do not confirm the sort and overAgg's format so far. | ||
- in other databases, the plan node is just used as a communicating protocol between frontend and compute node. So the compute node can only support the latest version's plan node format and reject all the requests with unknown plan node. But our stream plan should be persistent in meta store which means that a compute node must be compatible with all versions of old plans' protobuf format. | ||
|
||
In conclusion, we need find a way to achieve a balance between rapid development and backward compatibility, especially for stream plan node. | ||
|
||
## Design | ||
|
||
### Nightly and Stable SQL Features | ||
Distinguish the nightly and stable feature when publishing release version. RW will do not ensure compatibility for the streaming jobs with the nightly features in following releases. For example, if we release the "emit on close" as a nightly feature in the release v0.1.17 and user create a mv with that feature on a v0.1.17 cluster. The v0.1.18 and following version's RW can not ensure it can run successfully on the existing streaming jobs. User can drop the MVs with the nightly feature before they upgrade the cluster. For those nightly feature users really what to upgrade, we can write helper scripts too. And the stable features will be tested with new released compute node on old version streaming plans. Also, with the convinced stable feature list, we can test the backward compatibility more easily. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer the word "experimental" than "nightly" because it's more straightforward to common people. BTW, when delivering the delta join feature (by Dylan), we had discussed this and decided to mark it as "experimental", especially on the user docs. |
||
|
||
### Nightly and Stable Stream Plan Node | ||
How to know if a SQL Feature has been stable? Developer should comment the compatibility annotation on protobuf struct of every stream plan node(like annotation in java). the annotation contains: "nightly v0.1.14", "stable v0.1.15", "deprecated v0.1.16". A plan node will be with a nightly annotation firstly. When developer ensure that the plan node struct is stable enough, a stable annotation should be comments on the protobuf struct. When developer ensure that frontend will not generate the plan node, a deprecated annotation should be comments on the protobuf struct. A SQL feature is stable means that all the stream plan nodes generated by any version's optimizer should have been stable. | ||
|
||
To be discussed: what is the proper format of those comments in proto files and how to check all plan node should have one in CI check? | ||
|
||
### Copy-on-Write Style Changes on Stable Plan Node Protobuf | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So basically you mean immutable and versioned protobuf messages? 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BTW we can assume all fields to be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I think so. And I think our current stream execution expect that in fact(so many |
||
How to maintain the compatibility of the plan node's protobuf? If developer want to do any changes on a stable plan node, he should add a new plan node protobuf definition. For example, if he want to add a new field in `StreamHashAgg`, he must define a new protobuf struct `StreamHashAggV2` and add the field on that. Notice that there are multi versions protobuf but they can share the same implementation. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we keep all There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, because the any old meta store can store a stream plan with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm in this case, will add a version field in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is a special case that we just add a new field and I am not sure if it is general enough |
||
|
||
Why make it so complicated and why not just rely on the protobuf's compatibility? To achieve the compatibility, protobuf actually give the struct that all fields are optional. When a protobuf struct is used as a RPC interface, the caller will give a combination of those optional fields and the callee should try best to try all kinds of meaningful combinations or return an error. based on the following facts I think the Copy-on-Write Style Changes is better. | ||
- the changes of the stable plan node is limited. we can make breaking changes in the same release arbitrarily and a stable plan node will not be modified too much. So the duplicated plan node definition will not be too much. | ||
- here the “return error” is unacceptable for us because if we can not resolve the stored streaming plan, the cluster can not boot up anyway. So we must make sure that the compute node can accept any combination of the fields in historical versions. Store all these combination in different version's plannode definition will help to maintain the compatibility, or it will just exist in the compute node's code and easily be forgotten. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking if it is reasonable to force users rebuild the plan when incompatible🤣 Making CN compatible with all versions can be challenging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's what I want to do on MV with the nightly SQL features. But it is not good enough. consider some data have been consumed and despaired in the source. how to reuse these state data,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our batch can follow the same approach? Maybe we can discuss this issue together in this RFC for completeness and comparison 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the consideration is only for rolling-update. And we only want to reject old requests, does it mean that we don't even need protobuf compatibility for communication? (Just let gRPC report error for the client...)
One problem is the request from new client to old server. But we can avoid it by updating servers first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's on earth the requirements we need to meet for rolling-update? 🥵 cc @hzxa21 @arkbriar for a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, the rolling upgrade requires that the cluster finally works and breaks nothing (temporarily unavailable is fine for some services). Ideally, we should consider each version combination to prevent unexpected behaviors. But that would be too much. We could add constraints like the compute must be upgraded after the meta, proposed by @hzxa21 in another discussion. We can add these constraints by either updating the deployment tools (enforce the order) or the kernel (deny of service when mismatch). If upgrading compute nodes requires rebuilding the streaming plan and its states, we should ensure that's worth it and try to automate it, e.g., fixing a buggy operator and the states as well. Otherwise, we should keep it compatible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can understand the spirit "breaks nothing (but temporarily unavailable is fine)", but it's still a little big vague to me.
To be more specific, it is understandable that things need to be persisted (like stream plan) should be taken care of. But what confused me is that is it ok to break all other things, i.e., the communication protocol? 🤔 IMHO that would just make the service temporarily unavailable, and will come back to normal after upgrade finishes. Correct me if I'm wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, in production, the requirements are:
a. Ensure two versions of codes are compatible during the upgrade period so the number of out-of-service nodes are controllable.
b. Speed up the upgrade and the warm-up/recovery period after the upgrade.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It all depends on how fast the upgrade is and whether we allow rollback as I mentioned above. Sometimes fast upgrade contradicts with the ability to rollback, especially when breaking changes are introduced. Rolling out breaking changes as fast as possible can minimize unavailbiliy but hurt ability to rollback if we don't maintain compatibility because we won't be able to rollback after upgrade finishes. However, since we are in early production stage and in rapid development, I think it is okay to relax the requirement and introduce breaking changes without considering too much about ability to rollback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's ok in most cases. If you think of upgrading the simplest service, a stateless web service, there will be a time that users will get errors when the old services are shut down one by one, but it recovers quickly, thanks to the LB. This kind of outage is allowed and accepted when upgrading non-availability-critical applications by most users.
Besides, I totally agree with what @hzxa21 said, the ability to rollback and the downtime matter greatly. At least one of these two should be considered carefully if not both can be satisfied.