httpwg / http-core

Core HTTP Specifications
https://httpwg.org/http-core/
469 stars 43 forks source link

Caching: give caches more flexibility to calculate Age #1110

Open ethanresnick opened 1 year ago

ethanresnick commented 1 year ago

Imagine there's an origin with a chain of caches in front of it, and the caches' clocks are known to be well-synchronized with the origin's clock — perhaps because the caches and the origin are run by the same organization. In that case, the caches could compute a much more accurate Age value by not using the formulas in RFC 9111. However, in order to do so, they would have to exploit this knowledge about their clocks being synchronized, and the RFC doesn't seem to allow them to do that. So, I think giving caches a bit latitude for these cases, so they can compute a more accurate Age while remaining spec-compliant, would be nice.

Here's an example scenario to motivate this:

Now, assume the user agent requests GET /something-expensive and there's a cache miss at each cache, so the request gets forwarded all the way to the origin. When the origin receives the request from Cache C, it responds 5 seconds later. When that response reaches Cache C, it won't have an Age header, but Cache C will have observed a 5.1s response_delay (accounting for the 100ms round-trip time between Cache C and the origin). So, using the current_age formula, Cache C will return Age: 5. Then, Cache B sees an age_value of 5 from Cache C's response but it also measures a response_delay of 5.2s. So, the Age value it sends in its response to Cache A is 10s. Finally, Cache A repeats this process and concludes that the response is 15s old, which it returns to the user agent in the Age. In reality, the response is only ~5.15s old at this point, not 15s!

There's a mix here of "double counting" and counting some things that shouldn't be part of the age at all (e.g., the inbound latency from Cache A to the origin). But I think these are well-known limitations to using a response_delay-based age — and they're unavoidable if the servers can't trust each other's clocks.

The point of this issue, though, is about giving the cache more flexibility when the origin's clock is known to be reasonably synchronized with the cache's. In those cases, just using apparent_age will give better results. Right now, though, apparent_age can only be used to increase the computed current_age, via the formula:

corrected_initial_age = max(apparent_age, corrected_age_value);

If some conditions hold — and I'm not sure exactly how to formalize all the conditions where this would apply — it seems like caches ought to be able to use the apparent_age as the corrected_initial_age, or at least heavily bias the corrected_initial_age toward the apparent_age.