-
-
Notifications
You must be signed in to change notification settings - Fork 307
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
runtime: Replace DashMap
with a locked AHashMap
#785
Conversation
1f02e15
to
2e82d6c
Compare
The `kube_runtime::reflector` module pulls in `dashmap`, a concurrent hashmap implementation. This implementation necessarily uses `unsafe`, which can lead to safety/correctness/security issues (like [RUSTSEC-2022-02][sec]). This change replaces `dashmap` with a `RwLock<HashMap<...>>` using `parking_lot`. `parking_lot` currently has greater than 10x the usage (according to https://lib.rs) and is already used by existing dependencies. `dashmap` purports to be higher bandwidth and lower latency than a simple `parking_lot` lock, but most kubernetes controllers should not operate at the scale where these differences factor into application performance. On the other hand, all users may be impact by correctness issues. This change does not impact the public API in any way and it should not impact users. Fixes kube-rs#781 [sec]: https://rustsec.org/advisories/RUSTSEC-2022-0002.html Signed-off-by: Oliver Gould <ver@buoyant.io>
2e82d6c
to
fa2c09f
Compare
This comment has been minimized.
This comment has been minimized.
`kube_runtime`'s `reflector` and `controller` clones the entire resource data structure on each read. This may incur many allocations and add latency to reads. This change modifies the `kube_runtime::reflector` to store resources in an atomic, reference-counted `Arc` so that clones do not incur allocation. The goal of this change is to amortize costs so that these allocations are only incurred once--at update-time--making reads cheaper. This changes the public APIs of `kube_runtime`'s `controller`, `reflector`, and `finalizer` modules. Related to kube-rs#785 Signed-off-by: Oliver Gould <ver@buoyant.io>
`kube_runtime`'s `reflector` and `controller` clones the entire resource data structure on each read. This may incur many allocations and add latency to reads. This change modifies the `kube_runtime::reflector` to store resources in an atomic, reference-counted `Arc` so that clones do not incur allocation. The goal of this change is to amortize costs so that these allocations are only incurred once--at update-time--making reads cheaper. This changes the public APIs of `kube_runtime`'s `controller`, `reflector`, and `finalizer` modules. Related to kube-rs#785 Signed-off-by: Oliver Gould <ver@buoyant.io>
Signed-off-by: Oliver Gould <ver@buoyant.io>
Signed-off-by: Oliver Gould <ver@buoyant.io>
DashMap
with a locked HashMap
DashMap
with a locked AHashMap
.map(|obj| (ObjectRef::from_obj_with(obj, self.dyntype.clone()), obj.clone())) | ||
.collect::<AHashMap<_, _>>(); | ||
*self.store.write() = new_objs; |
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.
note that the old version would hash every resource 3x more. this should be notably faster when dealing with large sets of resources.
While looking into replacing `dashmap` in `kube-rs` (kube-rs/kube#785), I realized that we're probably better off using [`ahash`][ahash] in our indexing code. AHash pruports to the be "the fastest DoS-resistant hash currently available in Rust." According to <https://lib.rs/crates/ahash>, it has substantial usage. This change should help to minimize lock contention (i.e. by speeding up hashing while a lock is held). In general, this looks to be a superior default to `std::collections::HashMap`. Signed-off-by: Oliver Gould <ver@buoyant.io> [ahash]: https://github.com/tkaitchuck/aHash/blob/e77cab8c1e15bfc9f54dfd28bd8820c2a7bb27c4/compare/readme.md
While looking into replacing `dashmap` in `kube-rs` (kube-rs/kube#785), I realized that we're probably better off using [`ahash`][ahash] in our indexing code. AHash pruports to the be "the fastest DoS-resistant hash currently available in Rust." According to <https://lib.rs/crates/ahash>, it has substantial usage. This change should help to minimize lock contention (i.e. by speeding up hashing while a lock is held). In general, this looks to be a superior default to `std::collections::HashMap`. Signed-off-by: Oliver Gould <ver@buoyant.io> [ahash]: https://github.com/tkaitchuck/aHash/blob/e77cab8c1e15bfc9f54dfd28bd8820c2a7bb27c4/compare/readme.md
Thanks a lot for this implementation. I think this looks great. Agree with rationale for picking it over dashmap, it's also used by tokio: I will probably have some time to test this out on a decent sized reflector next week to see some performance comparisons - as it would be good to have some base numbers. But am 👍 on this. |
Did a quick benchmark on a tool that is iterating over a bunch of objects and is trying to cross-reference owning pods with a reflector store in a cluster with ~1200 pods with a pseudocode of benchmark: cache = pod reflector
for p in api.list<PrometheusRule> {
state = cache.state() // expensive step - time of this bench dominated by this
// look for a pod in state with matching annotations to the prometheusrule (iterate over `state` - cheap-ish)
} this only really checks the expensiveness of
real 3m40s - 3m55s
user 3m20s - 3m35s
sys 0m0.9s - 0m0.4s this branch with real 3m49s - 3m52s
user 3m27s - 3m33s
sys 0m0.4s - 0m0.5s results of 2 runs. to me this looks like it does not make any meaningful difference on the read side. |
While looking into replacing `dashmap` in `kube-rs` (kube-rs/kube#785), I realized that we're probably better off using [`ahash`][ahash] in our indexing code. AHash pruports to the be "the fastest DoS-resistant hash currently available in Rust." According to <https://lib.rs/crates/ahash>, it has substantial usage. This change should help to minimize lock contention (i.e. by speeding up hashing while a lock is held). In general, this looks to be a superior default to `std::collections::HashMap`. Signed-off-by: Oliver Gould <ver@buoyant.io> [ahash]: https://github.com/tkaitchuck/aHash/blob/e77cab8c1e15bfc9f54dfd28bd8820c2a7bb27c4/compare/readme.md
You mean regarding the |
I was thinking more about the 0.67.0 milestone. |
And if changelog/change isn't only for breaking changes then what's the plan for keeping track of breakage? |
The milestone I'm just using as an experimental way to group everything together (rather than having to construct a compare url) - it doesn't imply anything in particular atm. |
well, most it probably makes sense to mark especially breaking things worthy of highlighting in the manually written notes in CHANGELOG.md under UNRELEASED (which gets prepended to the release)? |
While looking into replacing `dashmap` in `kube-rs` (kube-rs/kube#785), I realized that we're probably better off using [`ahash`][ahash] in our indexing code. AHash pruports to the be "the fastest DoS-resistant hash currently available in Rust." According to <https://lib.rs/crates/ahash>, it has substantial usage. This change should help to minimize lock contention (i.e. by speeding up hashing while a lock is held). In general, this looks to be a superior default to `std::collections::HashMap`. Signed-off-by: Oliver Gould <ver@buoyant.io> [ahash]: https://github.com/tkaitchuck/aHash/blob/e77cab8c1e15bfc9f54dfd28bd8820c2a7bb27c4/compare/readme.md (cherry picked from commit d2a0fa0) Signed-off-by: Oliver Gould <ver@buoyant.io>
While looking into replacing `dashmap` in `kube-rs` (kube-rs/kube#785), I realized that we're probably better off using [`ahash`][ahash] in our indexing code. AHash pruports to the be "the fastest DoS-resistant hash currently available in Rust." According to <https://lib.rs/crates/ahash>, it has substantial usage. This change should help to minimize lock contention (i.e. by speeding up hashing while a lock is held). In general, this looks to be a superior default to `std::collections::HashMap`. Signed-off-by: Oliver Gould <ver@buoyant.io> [ahash]: https://github.com/tkaitchuck/aHash/blob/e77cab8c1e15bfc9f54dfd28bd8820c2a7bb27c4/compare/readme.md (cherry picked from commit d2a0fa0) Signed-off-by: Oliver Gould <ver@buoyant.io>
While looking into replacing `dashmap` in `kube-rs` (kube-rs/kube#785), I realized that we're probably better off using [`ahash`][ahash] in our indexing code. AHash pruports to the be "the fastest DoS-resistant hash currently available in Rust." According to <https://lib.rs/crates/ahash>, it has substantial usage. This change should help to minimize lock contention (i.e. by speeding up hashing while a lock is held). In general, this looks to be a superior default to `std::collections::HashMap`. Signed-off-by: Oliver Gould <ver@buoyant.io> [ahash]: https://github.com/tkaitchuck/aHash/blob/e77cab8c1e15bfc9f54dfd28bd8820c2a7bb27c4/compare/readme.md (cherry picked from commit d2a0fa0) Signed-off-by: Oliver Gould <ver@buoyant.io>
While looking into replacing `dashmap` in `kube-rs` (kube-rs/kube#785), I realized that we're probably better off using [`ahash`][ahash] in our indexing code. AHash pruports to the be "the fastest DoS-resistant hash currently available in Rust." According to <https://lib.rs/crates/ahash>, it has substantial usage. This change should help to minimize lock contention (i.e. by speeding up hashing while a lock is held). In general, this looks to be a superior default to `std::collections::HashMap`. Signed-off-by: Oliver Gould <ver@buoyant.io> [ahash]: https://github.com/tkaitchuck/aHash/blob/e77cab8c1e15bfc9f54dfd28bd8820c2a7bb27c4/compare/readme.md (cherry picked from commit d2a0fa0) Signed-off-by: Oliver Gould <ver@buoyant.io>
Motivation
The
kube_runtime::reflector
module pulls indashmap
, a concurrenthashmap implementation. This implementation necessarily uses
unsafe
,which can lead to safety/correctness/security issues (like
RUSTSEC-2022-02).
Solution
This change replaces
dashmap
with aRwLock<AHashMap<...>>
usingparking_lot
.parking_lot
currently has greater than 10x the usage(according to https://lib.rs) and is already used by existing
dependencies.
dashmap
purports to be higher bandwidth and lower latency than asimple
parking_lot
lock, but most kubernetes controllers should notoperate at the scale where these differences factor into application
performance. On the other hand, all users may be impacted by correctness
issues.
AHash
is used to reduce contention incurred by hash latency. AHashclaims to be ~10x faster than the default hasher, while preserving DoS
resistance.
This change does not impact the public API in any way and it should not
impact users.
Fixes #781