Skip to content

add StorageMonitor to measure storage and virtual storage usage by segment cache#18742

Merged
clintropolis merged 7 commits into
apache:masterfrom
clintropolis:storage-monitor
Dec 2, 2025
Merged

add StorageMonitor to measure storage and virtual storage usage by segment cache#18742
clintropolis merged 7 commits into
apache:masterfrom
clintropolis:storage-monitor

Conversation

@clintropolis

@clintropolis clintropolis commented Nov 14, 2025

Copy link
Copy Markdown
Member

Description

To use, add org.apache.druid.server.metrics.StorageMonitor to druid.monitoring.monitors.

changes:

  • adds StorageLocationStats and VirtualStorageLocationStats to abstract measuring segment cache/virtual segment cache usage
  • adds StorageStats to collect StorageLocationStats and VirtualStorageLocationStats into maps between location label and the stats of that location
  • adds new method SegmentCacheManager.getStorageStats to expose stats collection for segment cache manager implementations
  • adds new StorageMonitor to emit metrics for values in StorageStats
  • metrics for StorageLocationStats:
    • storage/used/bytes
    • storage/load/count
    • storage/load/bytes
    • storage/drop/count
    • storage/drop/bytes
  • metrics for VirtualStorageLocationStats:
    • storage/virtual/used/bytes
    • storage/virtual/hit/count
    • storage/virtual/load/count
    • storage/virtual/load/bytes
    • storage/virtual/evict/count
    • storage/virtual/evict/bytes
    • storage/virtual/reject/count

…gment cache

changes:
* adds `StorageLocationStats` and `VirtualStorageLocationStats` to abstract measuring segment cache/virtual segment cache usage
* adds `StorageStats` to collect `StorageLocationStats` and `VirtualStorageLocationStats` into maps between location label and the stats of that location
* adds new method `SegmentCacheManager.getStorageStats` to expose stats collection for segment cache manager implementations
* adds new `StorageMonitor` to emit metrics for values in `StorageStats`
* metrics for `StorageLocationStats`:
  - storage/static/count
  - storage/static/bytes
  - storage/drop/count
  - storage/drop/bytes
* metrics for `VirtualStorageLocationStats`:
  - storage/virtual/hit/count
  - storage/virtual/load/count
  - storage/virtual/load/bytes
  - storage/virtual/evict/count
  - storage/virtual/evict/bytes
  - storage/virtual/reject/count

@kfaraz kfaraz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the metrics, @clintropolis !
Left some suggestions/queries, mostly for my understanding.

Comment on lines +91 to +92
builder.setMetric(VSF_HIT_COUNT, weakStats.getHitCount());
emitter.emit(builder);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Maybe combine these lines for brevity (unless you prefer the current syntax more)

Suggested change
builder.setMetric(VSF_HIT_COUNT, weakStats.getHitCount());
emitter.emit(builder);
emitter.emit(builder.setMetric(VSF_HIT_COUNT, weakStats.getHitCount()));


sleepForStorageMonitor();

emitter.waitForAnyEventWithMetricName(StorageMonitor.VSF_HIT_COUNT);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Do we need the new waitForAnyEventWithMetricName method?

Does the original syntax seem verbose?

Suggested change
emitter.waitForAnyEventWithMetricName(StorageMonitor.VSF_HIT_COUNT);
emitter.waitForEvent(event -> event.hasMetricName(StorageMonitor.VSF_HIT_COUNT));

Just wondering if we there is something we can do to make the syntax more dev-friendly for the general case too, since matching on just the metric name doesn't seem like a common use case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, i guess this method isn't necessary, i guess i was thinking it would be common for looking for things from monitors like i'm doing here, but i guess it doesn't save all that much

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think we can leave it out for now.

* returned by this method only includes the events which have happened since the previous call to this method.
*/
@Nullable
StorageStats getStorageStats();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename to getAndResetStorageStats() to align with behaviour?

return events.get(lastIndex).getValue().longValue();
}

private long getMetricTotal(LatchableEmitter emitter, String metricName)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this should be a utility method on StubServiceEmitter or MetricsVerifier itself. But we can do that later too.

LatchableEmitter emitter = historical.latchableEmitter();
// sleep to clear out the pipe to get zerod out storage monitor metrics and then flush (which clears out the
// internal events stores in test emitter)
sleepForStorageMonitor();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid the sleep somehow? Maybe by waiting for some specific metric to be emitted?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i had some trouble getting waiting for events from the same monitor to work, looking into the code i think i see why, waitForEvent doesn't necessarily wait for the next event, it finds any processed matching event too, i believe i misunderstood what this method did, I think i need a version that skips any already emitted events and only waits for the next one

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think i need a version that skips any already emitted events and only waits for the next one

I see. That seems like a reasonable use case. I think you can add a method waitForNextEvent but we would need to call out that it would be susceptible to race conditions and may miss out on events and cause the test to wait forever.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is more or less exactly what i have done, just haven't got around to pushing up a commit yet tidying some other stuff up

Comment on lines +24 to +26
long getLoadCount();

long getLoadBytes();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this represent the load events that have occurred since the last emission period?
Or the number/bytes of segments currently loaded at a location?

The latter seems like a useful metric too. We already have the segment/used and segment/usedPercent metrics emitted by the HistoricalMetricsMonitor, but they are not keyed on the location as a dimension.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right now these metrics are all just for the emission period. I was aiming for these metrics to show like the activity during the period to give a good idea of segment cache activity rather than overall usage, the static load metrics showing churn in rebalancing, while the vsf metrics could be used as an indicator that there is a lot of churn from queries targeting different segments competing for disk space.

That said, it does feel useful to have some metrics like you are suggesting as well, especially later once we can have mixed disk usage from virtual loads via load rules... will think on it a bit.


package org.apache.druid.segment.loading;

public interface VirtualStorageLocationStats

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this extend StorageLocationStats?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they don't quite line up, there is not an explicit 'drop' in virtual storage, instead they are always evicted when something else needs the space, so i had them separate so the names are clearer to their function. I also didn't see a lot of usefulness in them being the same type, since they don't emit the same metrics, the only thing they both have in common is a location dimension and loads. I guess later when load rules would allow mixed usage of disk it might be nice to have one object per location, but it would also need to distinguish static loads from virtual loads, so need to think about it a bit.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

went ahead and added used bytes, which unlike the others is just the level at the time of emission

Comment on lines +42 to +43
this.stats = stats;
this.virtualStats = virtualStats;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we ever have a case where both maps are non-empty i.e. some static storage locations and some virtual on the same service?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not right now, we could in the future once we support defining virtual loads via load rules instead of the 'all or nothing' virtual storage mode we have right now

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, thanks for the clarification!

public Number getLatestMetricEventValue(String metricName)
{
final Deque<ServiceMetricEvent> metricEventQueue = metricEvents.get(metricName);
return metricEventQueue == null ? 0 : metricEventQueue.getLast().getValue();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: should we return null if there has been no event?

@divy-imply

Copy link
Copy Markdown

👋 Can we add a plain text mapping to metric name to meaning.
naive example:
storage/used/bytes : data stored in hot tier/cache

by reading the PR description, i understand these metrics are per segment usage. how does it translate to tier labeled as hot?

@clintropolis

clintropolis commented Dec 2, 2025

Copy link
Copy Markdown
Member Author

👋 Can we add a plain text mapping to metric name to meaning.
naive example:
storage/used/bytes : data stored in hot tier/cache

by reading the PR description, i understand these metrics are per segment usage. how does it translate to tier labeled as hot?

Well, there isn't a really clear way to do this since tiers are just labels, so there isn't really a concept of 'hot', that is something operators decide depending on configurations and such. Also, in the future I plan to support specifying virtual loads via load rules instead of a system level configuration, so at that point the same node could be emitting both regular and virtual metrics, so trying to frame these metrics in terms of tiers might be confusing.

@clintropolis
clintropolis merged commit 5626213 into apache:master Dec 2, 2025
57 checks passed
@clintropolis
clintropolis deleted the storage-monitor branch December 2, 2025 23:24
@kgyrtkirk kgyrtkirk added this to the 36.0.0 milestone Jan 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants