-
Notifications
You must be signed in to change notification settings - Fork 488
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
Make cluster meet reliable under link failures #461
base: unstable
Are you sure you want to change the base?
Conversation
Posting this for initial comments. I can migrate the test based on the new framework once #442 is merged. |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## unstable #461 +/- ##
============================================
- Coverage 70.22% 70.20% -0.02%
============================================
Files 109 109
Lines 59956 59967 +11
============================================
- Hits 42104 42102 -2
- Misses 17852 17865 +13
|
src/cluster_legacy.c
Outdated
* normal PING packets. */ | ||
node->flags &= ~CLUSTER_NODE_MEET; | ||
|
||
/* NOTE: We cannot clear the MEET flag from the node until we get a response |
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.
This makes sense to me, but I thought we briefly discussed just only sending the meet once, and on reconnect just not sending another meet. The previously logic was "We'll only send a single meet", I'm wondering if there was any logic somewhere that relied on that behavior.
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.
Are we getting into the territory that CLUSTER MEET
should only be sent when it was generated by the user/admin?
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.
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.
The initial MEET is still triggered by an admin/user command.
/* We can clear the flag after the first packet is sent.
* If we'll never receive a PONG, we'll never send new packets
* to this node. Instead after the PONG is received and we
* are no longer in meet/handshake status, we want to send
* normal PING packets. */
The previous code comment above doesn't restrict the MEET to be sent exactly once. I can't think of any scenario where sending multiple MEETs will break - this is similar to when an admin sends MEET multiple times. We send MEET only when the connection is established in clusterLinkConnectHandler
, so we still limit sending MEET when connection is newly setup and not in every cluster cron run.
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.
this is similar to when an admin sends MEET multiple times
I believe the cluster deduplicate multiple identical requests to the same IP/port.
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.
B isn't processing these right? It's just immediately dropping the first three and not processing them, it only ever processes the 4th one once correct?
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 am not concerned with sending multiple "MEET". It should be idempotent but agreed that we should add a test to validate it (not using the debug hook to fail the previous MEETs)
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.
B isn't processing these right? It's just immediately dropping the first three and not processing them, it only ever processes the 4th one once correct?
Correct. It starts processing when we drop the filter - which can be 4th or later.
agreed that we should add a test to validate it (not using the debug hook to fail the previous MEETs)
To test this scenario, the test has to send packets to the target node pretending to be a Valkey node. This way we can send multiple MEETs. Can you point me to any test that directly sends cluster messages to nodes, so I can write one with multiple MEETs?
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 think the test could look like:
- Node A is told to meet Node B. We drop all incoming packets on A, so although B get's the response it is never acknowledged.
- We force B to drop it's connection with A. We support
DEBUG CLUSTERLINK KILL <node id> all
. (I forgot about this till just now). - A will reconnect, and send another meet.
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.
Thanks! Added test to make sure multiple meets are handled just like a PING.
**MEET**
Node A -----------------> Node B
X <----------------
PONG
**MEET**
------------------>
X <----------------
PONG
PING
<------------------
------------------>
PONG
**MEET**
------------------>
X <----------------
PONG
...
[Remove DROP PONG]
**MEET**
------------------>
<------------------
PONG
PING
------------------>
<------------------
PONG
PING
<------------------
------------------>
PONG
src/cluster_legacy.c
Outdated
* normal PING packets. */ | ||
node->flags &= ~CLUSTER_NODE_MEET; | ||
|
||
/* NOTE: We cannot clear the MEET flag from the node until we get a response |
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.
Are we getting into the territory that CLUSTER MEET
should only be sent when it was generated by the user/admin?
I think it's worth investing on this redis/redis#11095 to avoid this issue altogether. |
Thanks, I wasn't aware of this linked issue. IMO these two issues can be solved independently. The linked issue tries to make the admin experience better for MEET command where as this PR tries to address a specific gap in MEET implementation.
The problem addressed in this PR (asymmetric cluster membership) can happen with SYNC MEET as well due to link failures. So, it is worth solving it. The handshake nodes will still be removed after the handshake timeout (same as node_timeout of 15s). Wdyt? |
Yeah, I still believe this a problem even with the #11095. |
Awesome material for our next release which will be full of cluster improvements. Is it worth mentioning in release notes? Btw @srgsanky you need to commit with -s. See the instructions on the DCO CI job's details page. |
I would also be inclined to backport it. |
When I tried to merge the new changes into my fork, I ended up with a merge commit
I want to signoff just 49a884c, but the rebase is adding a signoff to all commits 315b757..d52c8f3 which are not made by me. Do you have any recommendation to fix this? As an alternate option, I can start fresh and add a new commit from the tip of unstable. I am not sure if I will be able to reuse this PR. |
d8aa71c
to
2ff9879
Compare
I believe it's possible to undo a merge by If nothing works, then it's always possible to start from scratch with a new branch and cherry-pick all your commits into it. Then you can rename the branches and force-push to this PR's branch. |
@srgsanky |
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.
Just some minor nitpicks around the tests, it overall LGTM.
src/cluster_legacy.c
Outdated
* normal PING packets. */ | ||
node->flags &= ~CLUSTER_NODE_MEET; | ||
|
||
/* NOTE: We cannot clear the MEET flag from the node until we get a response |
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.
B isn't processing these right? It's just immediately dropping the first three and not processing them, it only ever processes the 4th one once correct?
When there is a link failure while an ongoing MEET request is sent the sending node stops sending anymore MEET and starts sending PINGs. Since every node responds to PINGs from unknown nodes with a PONG, the receiving node never adds the sending node. But the sending node adds the receiving node when it sees a PONG. This can lead to asymmetry in cluster membership. This changes makes the sender keep sending MEET until it sees a PONG, avoiding the asymmetry. Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
Correct. It starts processing when we drop the filter - which can be 4th or later. |
This worked. Thanks!
I tried this and all the commits in the other branch of the merge was also annotated with my signoff. So, I decided to ask you folks for the best approach. btw is there any reasoning behind the requirement for the signoff? |
Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
Technically we adopted it because it's an LF requirement, but it's also a good practice to force a trail of who committed what. |
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.
this change LGTM overall.
src/cluster_legacy.c
Outdated
* normal PING packets. */ | ||
node->flags &= ~CLUSTER_NODE_MEET; | ||
|
||
/* NOTE: We cannot clear the MEET flag from the node until we get a response |
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 am not concerned with sending multiple "MEET". It should be idempotent but agreed that we should add a test to validate it (not using the debug hook to fail the previous MEETs)
1. Reworked code comment 1. Added serverLogs 1. Renamed debug variable 1. Made close link filter to be directly coupled with drop filter Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
Multiple MEETs will be handled like a normal PING message. Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
The clang-format checker is currently failing due to changes introduced by another PR. Mentioned this in #118 (comment) |
sorry. maybe i missed some. fixed #570 |
ref: - #118 (my pervious change) - #461 (issuing that clang format checker fails due to my change) There was an issue that clang-format cheker failed. I don't know why I missed it and why it didn't catch. just running `clang-format -i bitops.c` was all. Signed-off-by: LiiNen <kjeonghoon065@gmail.com>
Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
src/server.h
Outdated
uint32_t | ||
debug_cluster_close_link_on_packet_drop : 1; /* Debug config that goes along with cluster_drop_packet_filter. | ||
When set, the link is closed on packet drop. */ |
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.
Did clang format do this automatically? This is such a weird format to split the type and the variable name on to to different lines.
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, clang did it. Agree..
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.
Yeah, this is why it's good that we don't run clang-format on merge. Now at least we have a chance to fix it manually. Just move the comment to it's own line.
uint32_t | |
debug_cluster_close_link_on_packet_drop : 1; /* Debug config that goes along with cluster_drop_packet_filter. | |
When set, the link is closed on packet drop. */ | |
/* Debug config that goes along with cluster_drop_packet_filter. | |
* When set, the link is closed on packet drop. */ | |
uint32_t debug_cluster_close_link_on_packet_drop : 1; |
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.
Btw, using one bit for this field will not save memory. We'd need to do it for some more fields and put them next to each other. Otherwise IMHO there's not point.
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.
Agree, there is no value now, but by keeping it to a bit, we can keep the intent clear and do a subsequent merge of such fields like you pointed out in the other comment (#461 (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.
OK. You're welcome to include this refactoring in this PR, but I won't insist. We'll open a follow-up issue for it otherwise.
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.
We'll open a follow-up issue for it otherwise.
We do have a hard problem to solve which is that the config system (as it is written) doesn't support bit fields since bit fields are not addressable. Most of the booleans we have are bit fields.
Signed-off-by: Sankar <1890648+srgsanky@users.noreply.github.com>
When there is a link failure while an ongoing MEET request is sent the sending node stops sending anymore MEET and starts sending PINGs. Since every node responds to PINGs from unknown nodes with a PONG, the receiving node never adds the sending node. But the sending node adds the receiving node when it sees a PONG. This can lead to asymmetry in cluster membership. This changes makes the sender keep sending MEET until it sees a PONG, avoiding the asymmetry.