-
Notifications
You must be signed in to change notification settings - Fork 955
[Bug Fix] Optimize RDB Load Performance and Fix Cluster Mode Resizing #1199
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
Conversation
This commit is meant to fix performance degradation caused by the replica having to rehash many times during RDB load. Testing locally we were able to reproduce up to 50% degredation in BGSAVE time. Signed-off-by: naglera <[email protected]>
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## unstable #1199 +/- ##
=========================================
Coverage 70.69% 70.70%
=========================================
Files 114 115 +1
Lines 63076 63159 +83
=========================================
+ Hits 44594 44657 +63
- Misses 18482 18502 +20
|
zuiderkwast
left 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.
Good findings. Too bad we didn't fix this before 8.0. :)
|
Reviewed the code from github.dev, it posted the comments twice 😂 |
Co-authored-by: Harkrishn Patro <[email protected]> Signed-off-by: Amit Nagler <[email protected]>
Signed-off-by: naglera <[email protected]>
enjoy-binbin
left 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.
We have this approximate thing, do you mean it is not working in this case? sorry i did not look at the discusstion deeply, just a quick look.
static int dbExpandGeneric(kvstore *kvs, uint64_t db_size, int try_expand) {
int ret;
if (server.cluster_enabled) {
/* We don't know exact number of keys that would fall into each slot, but we can
* approximate it, assuming even distribution, divide it by the number of slots. */
int slots = getMyShardSlotCount();
if (slots == 0) return C_OK;
db_size = db_size / slots;
ret = kvstoreExpand(kvs, db_size, try_expand, dbExpandSkipSlot);
} else {
ret = kvstoreExpand(kvs, db_size, try_expand, NULL);
}
return ret ? C_OK : C_ERR;
}
@enjoy-binbin you're right that there's an approximation in place, but in this specific case, it's not working as intended. Let me explain why: The issue arises when an 8.0 replica syncs from a 7.0 primary. In a scenario where the primary owns only a few slots, the replica's This PR creates dictionaries upon kvstore expand when the dictionary is missing. Impleanting only the first part of the PR will reveal this bug, so we might end up allocating space for all slots during expansion, including the unowned ones. |
Signed-off-by: naglera <[email protected]>
ok, thanks, now i see the point, does this means the approximate thing now is no longer needed and we can remove the dead code? |
|
i re-read the code.
The kvs->num_dicts is indeed 16384, but we have a getMyShardSlotCount, so the 8.0-replica know the slot info, and it will use it, see getMyShardSlotCount
i think this fails becuase two reasons
/* CB passed to kvstoreExpand.
* The purpose is to skip expansion of unused dicts in cluster mode (all
* dicts not mapped to *my* slots) */
static int dbExpandSkipSlot(int slot) {
- return !clusterNodeCoversSlot(getMyClusterNode(), slot);
+ return !clusterNodeCoversSlot(clusterNodeGetPrimary(getMyClusterNode()), slot);
}can this slove your problem? int kvstoreExpand(kvstore *kvs, uint64_t newsize, int try_expand, kvstoreExpandShouldSkipDictIndex *skip_cb) {
+ if (newsize == 0) return 1;
+
for (int i = 0; i < kvs->num_dicts; i++) {
- dict *d = kvstoreGetDict(kvs, i);
- if (!d || (skip_cb && skip_cb(i))) continue;
+ if (skip_cb && skip_cb(i)) continue;
+
+ dict *d = createDictIfNeeded(kvs, i);
int result = try_expand ? dictTryExpand(d, newsize) : dictExpand(d, newsize);
if (try_expand && result == DICT_ERR) return 0;
}
|
…d be determained by master node info Signed-off-by: naglera <[email protected]>
zuiderkwast
left 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.
Great! This new fix is much better!
I think we shall backport it to 8.0, that is include it in 8.0.2.
For the description:
- Valkey is spelled with a lowercase "k".
- "CME" (AWS terminology) => "cluster mode".
enjoy-binbin
left 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.
Good, the new code LGTM (i like my code), please also update the top comment and title, i guess it might be a little outdated (not good at wording). And also i see you have measured the efficiency before, can you measure it again?
|
I've conducted additional performance tests, and the results show that the fix from the 8.0 branch yields a significant improvement of over 30%. Here are the detailed results:
Test environment details:
Redis configuration settings: Both tests loaded 25,310,000 keys from an RDB file of about 1.92 GB. LogsUnstable replica (before fix)Replica after applying the fix |
…a side (valkey-io#1199) This PR addresses two issues: 1. Performance Degradation Fix - Resolves a significant performance issue during RDB load on replica nodes. - The problem was causing replicas to rehash multiple times during the load process. Local testing demonstrated up to 50% degradation in BGSAVE time. - The problem occurs when the replica tries to expand pre-created slot dictionaries. This operation fails quietly, resulting in undetected performance issues. - This fix aims to optimize the RDB load process and restore expected performance levels. 2. Bug fix when reading `RDB_OPCODE_RESIZEDB` in Valkey 8.0 cluster mode- - Use the shard's master slots count when processing this opcode, as `clusterNodeCoversSlot` is not initialized for the currently syncing replica. - Previously, this problem went unnoticed because `RDB_OPCODE_RESIZEDB` had no practical impact (due to 1). These improvements will enhance overall system performance and ensure smoother upgrades to Valkey 8.0 in the future. Testing: - Conducted local tests to verify the performance improvement during RDB load. - Verified that ignoring `RDB_OPCODE_RESIZEDB` does not negatively impact functionality in the current version. Signed-off-by: naglera <[email protected]> Co-authored-by: Binbin <[email protected]>
…a side (valkey-io#1199) This PR addresses two issues: 1. Performance Degradation Fix - Resolves a significant performance issue during RDB load on replica nodes. - The problem was causing replicas to rehash multiple times during the load process. Local testing demonstrated up to 50% degradation in BGSAVE time. - The problem occurs when the replica tries to expand pre-created slot dictionaries. This operation fails quietly, resulting in undetected performance issues. - This fix aims to optimize the RDB load process and restore expected performance levels. 2. Bug fix when reading `RDB_OPCODE_RESIZEDB` in Valkey 8.0 cluster mode- - Use the shard's master slots count when processing this opcode, as `clusterNodeCoversSlot` is not initialized for the currently syncing replica. - Previously, this problem went unnoticed because `RDB_OPCODE_RESIZEDB` had no practical impact (due to 1). These improvements will enhance overall system performance and ensure smoother upgrades to Valkey 8.0 in the future. Testing: - Conducted local tests to verify the performance improvement during RDB load. - Verified that ignoring `RDB_OPCODE_RESIZEDB` does not negatively impact functionality in the current version. Signed-off-by: naglera <[email protected]> Co-authored-by: Binbin <[email protected]> (cherry picked from commit c5012cc) Signed-off-by: naglera <[email protected]>
…a side (valkey-io#1199) This PR addresses two issues: 1. Performance Degradation Fix - Resolves a significant performance issue during RDB load on replica nodes. - The problem was causing replicas to rehash multiple times during the load process. Local testing demonstrated up to 50% degradation in BGSAVE time. - The problem occurs when the replica tries to expand pre-created slot dictionaries. This operation fails quietly, resulting in undetected performance issues. - This fix aims to optimize the RDB load process and restore expected performance levels. 2. Bug fix when reading `RDB_OPCODE_RESIZEDB` in Valkey 8.0 cluster mode- - Use the shard's master slots count when processing this opcode, as `clusterNodeCoversSlot` is not initialized for the currently syncing replica. - Previously, this problem went unnoticed because `RDB_OPCODE_RESIZEDB` had no practical impact (due to 1). These improvements will enhance overall system performance and ensure smoother upgrades to Valkey 8.0 in the future. Testing: - Conducted local tests to verify the performance improvement during RDB load. - Verified that ignoring `RDB_OPCODE_RESIZEDB` does not negatively impact functionality in the current version. Signed-off-by: naglera <[email protected]> Co-authored-by: Binbin <[email protected]>
…a side (valkey-io#1199) This PR addresses two issues: 1. Performance Degradation Fix - Resolves a significant performance issue during RDB load on replica nodes. - The problem was causing replicas to rehash multiple times during the load process. Local testing demonstrated up to 50% degradation in BGSAVE time. - The problem occurs when the replica tries to expand pre-created slot dictionaries. This operation fails quietly, resulting in undetected performance issues. - This fix aims to optimize the RDB load process and restore expected performance levels. 2. Bug fix when reading `RDB_OPCODE_RESIZEDB` in Valkey 8.0 cluster mode- - Use the shard's master slots count when processing this opcode, as `clusterNodeCoversSlot` is not initialized for the currently syncing replica. - Previously, this problem went unnoticed because `RDB_OPCODE_RESIZEDB` had no practical impact (due to 1). These improvements will enhance overall system performance and ensure smoother upgrades to Valkey 8.0 in the future. Testing: - Conducted local tests to verify the performance improvement during RDB load. - Verified that ignoring `RDB_OPCODE_RESIZEDB` does not negatively impact functionality in the current version. Signed-off-by: naglera <[email protected]> Co-authored-by: Binbin <[email protected]>
…a side (#1199) This PR addresses two issues: 1. Performance Degradation Fix - Resolves a significant performance issue during RDB load on replica nodes. - The problem was causing replicas to rehash multiple times during the load process. Local testing demonstrated up to 50% degradation in BGSAVE time. - The problem occurs when the replica tries to expand pre-created slot dictionaries. This operation fails quietly, resulting in undetected performance issues. - This fix aims to optimize the RDB load process and restore expected performance levels. 2. Bug fix when reading `RDB_OPCODE_RESIZEDB` in Valkey 8.0 cluster mode- - Use the shard's master slots count when processing this opcode, as `clusterNodeCoversSlot` is not initialized for the currently syncing replica. - Previously, this problem went unnoticed because `RDB_OPCODE_RESIZEDB` had no practical impact (due to 1). These improvements will enhance overall system performance and ensure smoother upgrades to Valkey 8.0 in the future. Testing: - Conducted local tests to verify the performance improvement during RDB load. - Verified that ignoring `RDB_OPCODE_RESIZEDB` does not negatively impact functionality in the current version. Signed-off-by: naglera <[email protected]> Co-authored-by: Binbin <[email protected]>
… on replica side (#1199) (#1328) This PR addresses two issues: 1. Performance Degradation Fix - Resolves a significant performance issue during RDB load on replica nodes. - The problem was causing replicas to rehash multiple times during the load process. Local testing demonstrated up to 50% degradation in BGSAVE time. - The problem occurs when the replica tries to expand pre-created slot dictionaries. This operation fails quietly, resulting in undetected performance issues. - This fix aims to optimize the RDB load process and restore expected performance levels. 2. Bug fix when reading `RDB_OPCODE_RESIZEDB` in Valkey 8.0 cluster mode- - Use the shard's master slots count when processing this opcode, as `clusterNodeCoversSlot` is not initialized for the currently syncing replica. - Previously, this problem went unnoticed because `RDB_OPCODE_RESIZEDB` had no practical impact (due to 1). These improvements will enhance overall system performance and ensure smoother upgrades to Valkey 8.0 in the future. Testing: - Conducted local tests to verify the performance improvement during RDB load. - Verified that ignoring `RDB_OPCODE_RESIZEDB` does not negatively impact functionality in the current version. (cherry picked from commit c5012cc) Signed-off-by: naglera <[email protected]> Co-authored-by: Binbin <[email protected]>
#2466) If we want to expand kvstoreHashtableExpand, we need to make sure the hashtable exists. Currently, when processing RDB slot-info, our expand has no effect because the hashtable does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreHashtableExpand to make sure there is only one code path. Also see #1199 for more details. Signed-off-by: Binbin <[email protected]>
valkey-io#2466) If we want to expand kvstoreHashtableExpand, we need to make sure the hashtable exists. Currently, when processing RDB slot-info, our expand has no effect because the hashtable does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreHashtableExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
valkey-io#2466) If we want to expand kvstoreHashtableExpand, we need to make sure the hashtable exists. Currently, when processing RDB slot-info, our expand has no effect because the hashtable does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreHashtableExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
When reading RDB files with information about the number of keys per cluster slot, we need to create the dicts if they don't exist. Currently, when processing RDB slot-info, our expand has no effect because the dict does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreDictExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
When reading RDB files with information about the number of keys per cluster slot, we need to create the dicts if they don't exist. Currently, when processing RDB slot-info, our expand has no effect because the dict does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreDictExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
When reading RDB files with information about the number of keys per cluster slot, we need to create the dicts if they don't exist. Currently, when processing RDB slot-info, our expand has no effect because the dict does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreDictExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
When reading RDB files with information about the number of keys per cluster slot, we need to create the dicts if they don't exist. Currently, when processing RDB slot-info, our expand has no effect because the dict does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreDictExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
When reading RDB files with information about the number of keys per cluster slot, we need to create the dicts if they don't exist. Currently, when processing RDB slot-info, our expand has no effect because the dict does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreDictExpand to make sure there is only one code path. Also see #1199 for more details. Signed-off-by: Binbin <[email protected]>
When reading RDB files with information about the number of keys per cluster slot, we need to create the dicts if they don't exist. Currently, when processing RDB slot-info, our expand has no effect because the dict does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreDictExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
valkey-io#2466) If we want to expand kvstoreHashtableExpand, we need to make sure the hashtable exists. Currently, when processing RDB slot-info, our expand has no effect because the hashtable does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreHashtableExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
#2466) If we want to expand kvstoreHashtableExpand, we need to make sure the hashtable exists. Currently, when processing RDB slot-info, our expand has no effect because the hashtable does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreHashtableExpand to make sure there is only one code path. Also see #1199 for more details. Signed-off-by: Binbin <[email protected]>
valkey-io#2466) If we want to expand kvstoreHashtableExpand, we need to make sure the hashtable exists. Currently, when processing RDB slot-info, our expand has no effect because the hashtable does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreHashtableExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
valkey-io#2466) If we want to expand kvstoreHashtableExpand, we need to make sure the hashtable exists. Currently, when processing RDB slot-info, our expand has no effect because the hashtable does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreHashtableExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]>
#2466) If we want to expand kvstoreHashtableExpand, we need to make sure the hashtable exists. Currently, when processing RDB slot-info, our expand has no effect because the hashtable does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreHashtableExpand to make sure there is only one code path. Also see #1199 for more details. Signed-off-by: Binbin <[email protected]>
valkey-io#2466) If we want to expand kvstoreHashtableExpand, we need to make sure the hashtable exists. Currently, when processing RDB slot-info, our expand has no effect because the hashtable does not exist (we initialize it only when we need it). We also update kvstoreExpand to use the kvstoreHashtableExpand to make sure there is only one code path. Also see valkey-io#1199 for more details. Signed-off-by: Binbin <[email protected]> Signed-off-by: Harkrishn Patro <[email protected]>
This PR addresses two issues:
Performance Degradation Fix - Resolves a significant performance issue during RDB load on replica nodes.
Bug fix when reading
RDB_OPCODE_RESIZEDBin Valkey 8.0 cluster mode-clusterNodeCoversSlotis not initialized for the currently syncing replica.RDB_OPCODE_RESIZEDBhad no practical impact (due to 1).These improvements will enhance overall system performance and ensure smoother upgrades to Valkey 8.0 in the future.
Testing:
RDB_OPCODE_RESIZEDBdoes not negatively impact functionality in the current version.