apache / apache/incubator-pegasus
add 'feature flags' rcp interface for version compatability between server and client
- Dominant language
- C++
- Stars
- 2.1k
- Forks
- 328
- PR merge metrics
- No merged PRs in 30d
Description
## Feature Request
**Is your feature request related to a problem? Please describe:**
We have optimized an interface implementation of the pegasus java client. The specific way is to define a new 'task_code' 、bind it to a new read interface function implemented by the server side and then reimplement the interface of the java client by calling the new read rpc interface represented by the new 'task_code'; but this will cause the problem of version matching between the client side and the server side: the new version client can not visit old version server because old version server cannot recognize the new task-code in the request-struct;
Since my company is a "to b" company, we can not upgrade all the deployed pegasus-server cluster in a comparatively short time;
We don't want to influence the usage of the old client interface either, so we implement a new java client interface instead with the same functionality and make it compatible with the new and old version server at the same time.
How to implement the client interface in compatible with the new and old version server at the same time ?
We have once used an unconsidered method:
we added a 'version' field which represents server code version to the 'configuration_query_by_index_response' structure returned from the metaserver in the rpc-call represented by the task-code 'RPC_CM_QUERY_PARTITION_CONFIG_BY_INDEX' and then the java client interface implementation can do the corresponding logic based by this fetched 'version' field: if ‘version' is higher than some pre-specified number, the remain logic will execute new optimized code and call the new rpc read interface ; otherwise, it will be the same with the old logic
This 'unconsidered' method is called 'unconsidered' because it has the following problems:
(1) 'version' field can only represents metaserver's version, not all the servers' version in the same pegasus cluster, especially when upgrading is in progress
(2) it is unreasonble to use an unrelated rpc-call and semantically unrelated thrift structure 'configuration_query_by_index_response' to fetch 'version' field
(3) It is very inflexible to judge the features supported by the server simply by comparing the 'code version'
**Describe the feature you'd like:**
So later we realized that the version matching problem is a general problem, we thought of a more general method which we call it 'feature flags method', and the idea is inspired from 'kudu', the method is as following:
1、we can define new features as enums coded in the client side and server side at the same time
```
enum rpc_feature_flag {
UNKNOWN = 0,
FEATURE_1 = 1,
}
```
2、we can also define a new 'task_code', for example 'RPC_CM_FEATURE_NEGOTIATE' and corresponding rpc related definitions:
```
struct negotiate_request {
}
struct negotiate_response {
1:list supported_features;
}
service rrdb {
negotiate_response negotiate(1:negotiate_request request);
}
```
3、we can then define a new class inherited from 'serverlet' , implement the real "negotiate" rpc handler function and register it to 'rpc_engine' in this class when related 'service_app' start
4、when a java or other language's client establishing connection with each instance of the server side, it also do the 'negotiate' rpc call to each of them, then it can 'know' the features each server supported, thus can make next decisions
The above 'feature flags method' is not particularly detailed, for example it have not described what the client would do when one of a 'negotiate' rpc fails
I put it forward here, because I want to hear the opinions of the great gods here!
**Describe alternatives you've considered:**
**Teachability, Documentation, Adoption, Migration Strategy:**
I think the server side code change will not be so hard, as the following pr
https://github.com/cauchy1988/incubator-pegasus/pull/1/files
Hower the client side may be a little difficult, and even for me it’s a bit vague to what extent the function needs to be implemented, the following pdf is the java client side design I have thought of
[feature negotiation client side simple design.pdf](https://github.com/apache/incubator-pegasus/files/7656247/feature.negotiation.client.side.simple.design.pdf)
In the content of above pdf, 'batchGet3' is the client interface we newly implemented which is a read-optimized client interface. The main logic is: a new BATCH_GET rpc interface is added in the server side; when the client calls batchGet3, if the client finds that the server supports BATCH_GET rpc Then send a BATCH_GET rpc request to the server, if it is found that the server does not support, then transfer to batchGet2 logic
Contributor guide
Research direction
Start by reviewing the proposed server-side changes in the referenced pull request and the feature-negotiation client design PDF. Then inspect the serverlet, rpc_engine, service_app, RPC_CM_FEATURE_NEGOTIATE, and BATCH_GET entry points mentioned in the issue. Done should include an agreed negotiation and failure-handling design that lets batchGet3 use BATCH_GET when supported and fall back to batchGet2 otherwise.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, java
- Domain
- backend-api-design, distributed-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100