-
Notifications
You must be signed in to change notification settings - Fork 44
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
Performance optimization: create a new torrent repository using a SkipMap
instead of a BTreeMap
#778
Conversation
It will be used to create a new torrent repository implementation that allos adding torrents in parallel. That could be potencially faster than BTreeMap in a write intensive context.
SkipMap is an ordered map based on a lock-free skip list. It's al alternative to BTreeMap which supports concurrent access across multiple threads. One of the performance problems with the current solution is we can only add one torrent at the time because threads need to lock the whole BTreeMap. The SkipMap should avoid that problem. More info about SkiMap: https://docs.rs/crossbeam-skiplist/latest/crossbeam_skiplist/struct.SkipMap.html#method.remove The aquatic UDP load test was executed with the current implementation and the new one: Current Implementation: Requests out: 397287.37/second Responses in: 357549.15/second - Connect responses: 177073.94 - Announce responses: 176905.36 - Scrape responses: 3569.85 - Error responses: 0.00 Peers per announce response: 0.00 Announce responses per info hash: - p10: 1 - p25: 1 - p50: 1 - p75: 1 - p90: 2 - p95: 3 - p99: 104 - p99.9: 287 - p100: 371 New Implementation: Requests out: 396788.68/second Responses in: 357105.27/second - Connect responses: 176662.91 - Announce responses: 176863.44 - Scrape responses: 3578.91 - Error responses: 0.00 Peers per announce response: 0.00 Announce responses per info hash: - p10: 1 - p25: 1 - p50: 1 - p75: 1 - p90: 2 - p95: 3 - p99: 105 - p99.9: 287 - p100: 351 The result is pretty similar but the benchmarking for the repository using criterios shows that this implementations is a litle bit better than the current one.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## develop #778 +/- ##
===========================================
+ Coverage 77.71% 77.84% +0.12%
===========================================
Files 158 158
Lines 8711 8762 +51
===========================================
+ Hits 6770 6821 +51
Misses 1941 1941 ☔ View full report in Codecov by Sentry. |
It's been used in the src/packages/torrent-repository package.
There are now more implementations.
9d5d535
to
0989285
Compare
Looks good, but it would be good to hook it up to the integration tests as well. |
OK. I did not see that. |
ACK 12f54e7 |
Hi @da2ce7, I've added the new repo implementation to the tests. I will merge as it is, but since the new repo does not use a The current names are: pub(crate) enum Repo {
RwLockStd(TorrentsRwLockStd),
RwLockStdMutexStd(TorrentsRwLockStdMutexStd),
RwLockStdMutexTokio(TorrentsRwLockStdMutexTokio),
RwLockTokio(TorrentsRwLockTokio),
RwLockTokioMutexStd(TorrentsRwLockTokioMutexStd),
RwLockTokioMutexTokio(TorrentsRwLockTokioMutexTokio),
SkipMapMutexStd(TorrentsSkipMapMutexStd),
} Including the new implementation, we always have a pattern like this:
We could rename them to: pub(crate) enum Repo {
// Outer Inner
RwLockStd___BTreeMap__BTreeMap_None_________(TorrentsRwLockStd),
RwLockStd___BTreeMap__BTreeMap_ArcMutexStd__(TorrentsRwLockStdMutexStd),
RwLockStd___BTreeMap__BTreeMap_ArcMutexTokio(TorrentsRwLockStdMutexTokio),
RwLockTokio_BTreeMap__BTreeMap_None_________(TorrentsRwLockTokio),
RwLockTokio_BTreeMap__BTreeMap_ArcMutexStd__(TorrentsRwLockTokioMutexStd),
RwLockTokio_BTreeMap__BTreeMap_ArcMutexTokio(TorrentsRwLockTokioMutexTokio),
None________SkipMap___BTreeMap_ArcMutexStd__(TorrentsSkipMapMutexStd),
} Underscores and "None" are to highlight the pattern. Or just: pub(crate) enum Repo {
// Outer Inner
Impl1(TorrentsRwLockStd),
Impl2(TorrentsRwLockStdMutexStd),
Impl3(TorrentsRwLockStdMutexTokio),
Impl4(TorrentsRwLockTokio),
Impl5(TorrentsRwLockTokioMutexStd),
Impl6(TorrentsRwLockTokioMutexTokio),
Impl7(TorrentsSkipMapMutexStd),
} A generic name will be easier to maintain. An option in the middle could be: pub(crate) enum Repo {
// Outer and Inner Collections
DoubleBTreeMapImpl1(TorrentsRwLockStd),
DoubleBTreeMapImpl1(TorrentsRwLockStdMutexStd),
DoubleBTreeMapImpl1(TorrentsRwLockStdMutexTokio),
DoubleBTreeMapImpl1(TorrentsRwLockTokio),
DoubleBTreeMapImpl1(TorrentsRwLockTokioMutexStd),
DoubleBTreeMapImpl1(TorrentsRwLockTokioMutexTokio),
SkipMapBTreeMap(TorrentsSkipMapMutexStd),
} Just mention the collections types and remove the lock types. |
… using `DashMap` 4030fd1 fix: torrent repository tests. DashMap is not ordered (Jose Celano) 1e76c17 chore: add dashmap cargo dep to cargp machete (Jose Celano) 00ee9db feat: [#565] new torrent repository implementation usind DashMap (Jose Celano) 78b46c4 chore(deps): add cargo dependency: dashmap (Jose Celano) Pull request description: Relates to: - #778 - #567 (comment) This PR adds a new torrent repository implementation where the outer collection for torrents uses a [DashMap](https://docs.rs/dashmap/latest/dashmap/). This is something @mickvandijke was working on this [PR](#645). There have been many changes. @da2ce7 has extracted a [package for the repositories](https://github.com/torrust/torrust-tracker/tree/develop/packages/torrent-repository). This PR adds a new repo using DashMap to the new package. However, it does not implement some of the extra features @mickvandijke added to the other [PR](#645). For example, it does not limit memory consumption. None of the other repos have that feature, so I suggest merging this PR and implementing that feature in the future for all repos. ### Why The current repository used in production is the one using a [SkipMap](https://docs.rs/crossbeam-skiplist/latest/crossbeam_skiplist/struct.SkipMap.html) data structure. DashMap was the first type we considered to allow adding new torrents in parallels. The implementation with DashMap has not been merged because it does not guarantee the order when you iterate over the torrents. The tracker API returns torrents ordered by InfoHash. To avoid breaking the API that PR would need to add a new data structure (kind of Index) to keep the torrent list ordered. This implementation helps us run performance tests with this option without spending much time fixing its limitations. It looks like the performance is similar to the SkiMap, so we don't need to use it in production now. We only need to keep it for benchmarking in the future if other versions are better. ### Benchmarking Running the Aquatic UDP load test, the DashMap looks slightly better. SkipMap: ```output Requests out: 396788.68/second Responses in: 357105.27/second - Connect responses: 176662.91 - Announce responses: 176863.44 - Scrape responses: 3578.91 - Error responses: 0.00 Peers per announce response: 0.00 Announce responses per info hash: - p10: 1 - p25: 1 - p50: 1 - p75: 1 - p90: 2 - p95: 3 - p99: 105 - p99.9: 287 - p100: 351 ``` DashMap with initial capacity 0 (best result. On average is lower, similar to SkipMap): ```output Requests out: 410658.38/second Responses in: 365892.86/second - Connect responses: 181258.91 - Announce responses: 181005.95 - Scrape responses: 3628.00 - Error responses: 0.00 Peers per announce response: 0.00 Announce responses per info hash: - p10: 1 - p25: 1 - p50: 1 - p75: 1 - p90: 2 - p95: 3 - p99: 104 - p99.9: 295 - p100: 363 ``` With Criterion: ![image](https://github.com/torrust/torrust-tracker/assets/58816/1e1fca2d-821d-4e2c-adf8-49e055758bd0) ![image](https://github.com/torrust/torrust-tracker/assets/58816/fcb9a32f-c4f1-4ffd-9797-4a74fc000336) ![image](https://github.com/torrust/torrust-tracker/assets/58816/efe2d788-31ac-4997-82f6-d022aa8f79a0) ![image](https://github.com/torrust/torrust-tracker/assets/58816/f64a4e5a-a363-48cd-87d9-78162cda11d4) ### Conclusion From my point of view, other [performance optimisations](#774) have more potential than this, considering this implementation is not finished. The changes needed to finish this implementation will probably decrease the performance obtained in this benchmarking. In the future, we can review this option if we change the [tracker API behaviour to getting all torrents](#775). ACKs for top commit: josecelano: ACK 4030fd1 Tree-SHA512: 1a6c56f3aecb34fc40c401597efe1663c3cc66903f2d27bf8f2bbc6b058080d487a89b705c224657aaa6059f1c2a8597583e636e30727f9293bb43f460441415
This PR implements a new Torrent Repository replacing the outer BTreeMap for torrents with a SkipMap.
Why
Benchmarking
Running the Aquatic UDP load test gives the same results:
Current best implementation:
SkipMap:
However, benchmarking the repositories using Criterion shows better results in adding and updating multiple torrents in parallel.
Conclusion
I think we car merge it but I would also continue with the DashMap implementation to compare.