-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
metrics: Internalize metric label sets
The major memory user in the metric subsystem is the per series label sets. This is for two reasons: - The labels are stored multiple times in different places: Twice as part of `registered_metric` (one current labels and one original one for relabeling - these are often just the same), one copy as the lookup key in the values map and another final copy in the metadata copy for scraping - Lots of the labels are actually duplicated across metric series. For example for one io-queue class/mountpoint/iogroup combination you get 15 series all with the same labels. Similar is true for other metrics like reactor or scheduler metrics. In Redpanda we have an even more extreme pattern where per partition metrics create more than 60 series with the same label set. One idea to improve this would be to intern the individual label strings. In theory this would give improvements on top of the duplication described above. Most label keys and values are duplicated even if not all labels are the same (e.g.: shard). On a more detailed look this however wouldn't be very effective. Most labels are fairly short, e.g. looking at some seastar and redpanda metrics: ``` io_queue...{class="raft",iogroup="0",mountpoint="none",shard="0"} redpanda...{namespace="kafka",partition="9985",shard="2",topic="foobar"} ``` Each of the label key and values are shorter than 16 bytes and hence fit into the seastar short string optimization. Hence, each string only takes 16 bytes. In the above example maybe one of the eight strings might leave the SSO length (e.g.: mountpoint and topic) but those are in the minority. Interning the string in less than 16 bytes is not trivial so the gain would actually not be that large (deletion needs to be thread safe as the metadata might be copied to different shards at scrape time). There is further hidden overhead. Labels are stored in a `std::map` for fast lookup. Each node in the map has a ~32 byte overhead for the node struct. So even at a zero overhead internalisation we could only save about 2x in the most likely case. Hence this patch takes the strategy of internalizing the whole labels set (`std::map`). This means that we also internalize map overhead and still get an overall reduction as described above. For the actual internalization we store the labels `std::map` in a `std::shared_ptr` (for cross shared safety). It's stored in a `std::set` for lookup when adding new metrics. In Redpanda this patch reduces the metrics memory usage by a factor of 3-4 and hence saving gigabytes of memory at high partition counts (yes we likey have too many metrics). This also makes `update_metrics_if_needed` faster as less copying is needed and also increases cache locality at scrape time making that cheaper as well (a yet to be committed microbench by Travis Downs shows a ~10% improvement). Once all other shared_ptr references have gone out of scope we need to delete the entry out of the internalization set. We do this scan in `update_metrics_if_needed`. The overhead is minimal as the set doesn't actually get super big and extra overhead is compensated by `update_metrics_if_needed` being cheaper as mentioned above. Ideally we could do some deleter tricks but this is being complicated by thread safety issues in case the last reference is not on the origin shard.
- Loading branch information
1 parent
665fed0
commit 3a8bcbe
Showing
5 changed files
with
105 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters