storage: mark cluster-sensitive reads for caching backends - #401
storage: mark cluster-sensitive reads for caching backends#401mbardelmeijer wants to merge 1 commit into
Conversation
Add WithStrongStorageConsistency so Storage implementations that cache locally can bypass the cache on renew/obtain pre-checks and reloads, while handshake Loads may still use a local cache.
|
This is interesting and I like that it's pretty thin, but it puts a lot of burden on the storage implementation and doesn't generalize well IMO. I still want to explore the LRU-style eviction we discussed via email. Which I hope to look into more today. But if we are going to do something like this, what about a design like... a Give me a little bit to research LRU "hacks" to gain some efficiency for your case and I'll have more thoughts! |
|
LRU could definitely help, although for our use case a local disk cache would be even more valuable for our use-case. With 100k+ certificates across a fairly large anycast deployment, keeping a large cache in RAM on every edge instance gets expensive quickly. Ideally we'd have a relatively small in-memory cache for the hottest certificates, potentially with LRU eviction, backed by a much larger local disk cache, with the remote Storage remaining the ground truth. So I do like the LocalCache Storage option you suggested. Being able to use something like FileStorage would be even better. We can periodically enumerate the certificates in our remote store and pre-warm the local cache, so most handshake-time loads should never need to hit the remote backend in the first place. I think just calling GetCertificate would then warm it up. I do also like having the option to implement this in our own storage layer like this PR supports, as that gives us a bit more control over the caching behavior. But I understand that a more generalized solution in CertMagic itself would probably be preferable. Or perhaps making the current cache layer pluggable by a user-provided design. |
|
Ok, one other idea we could entertain, is a hook (if one doesn't exist already, I'd have to double-check) for your own code to try to prefetch a cert from a local cache. Before trying to load a cert from It sounds like what you're describing is a 3-tier storage system:
|
|
Yes, 3-tier is exactly what we're looking for! Small in-memory cache for the hottest certs, local disk for the semi-hot tail, remote storage as ground truth for the 100k+ rest. Sketched Happy to open it as a PR if you want to take it further. |
|
Sure, would love to see a PR for that since you've already got a draft working I guess! |
|
Done! See #402 |
Why
We run many edge instances that terminate TLS with CertMagic against a shared remote Storage, and want a local disk (or similar) cache in front of it so handshake
Loads do not pay remote latency on every in-memory cache miss.That breaks multi-instance renew coordination today: the renew pre-check (
managedCertInStorageNeedsRenewal) and related loads use the sameLoadpath. If they hit a stale local cache, peers queue unnecessary renewals (issue-lock storms) instead of taking the cheap reload-from-storage path—even though shared storage already has the new cert.Handshake can tolerate a slightly stale-but-valid cert. Cluster decisions (already renewed? already obtained?) cannot.
What
WithStrongStorageConsistency/StrongStorageConsistencyoncontextStoreshould always write throughOther approaches considered
LoadConsistent/ExistsConsistentinterface (likeLockLeaseRenewer): more explicit, also non-breaking; happy to switch if preferred over context.Consistent(fn)mode on Storage: possible, but easy to get wrong under concurrentLoads.Storage.Loadsignatures: breaking for all implementers.Happy to rename (e.g.
StorageCacheBypass) if that reads better.