Chunked caches, shard groups and noisy neighbours · Morning Gist
Sunday, October 255 stories · 16 min
Chunked caches, shard groups and noisy neighbours
Today's posts mostly answer one question: where data and workloads should live. Cloudflare caches, PlanetScale shards, HPTS talks and Netflix's platform teams each take a turn.
Picked from 63 new articles across 34 sources · arrow keys for other days
Today in 30 seconds
30s left
Cloudflare now caches range requests in fixed chunks instead of tunable sizes, halving R2 p99 time to first byte and cutting inter-tier traffic about 6%. story 1 ↓
PlanetScale's Neki groups related Postgres rows with hashed keys, reference tables and global indexes. That placement decides which transactions stay single-shard and ACID. story 2 ↓
Notes from HPTS 2026 question old assumptions on data movement, S3's disk-era design and coordination. Apple cut Cassandra's storage ratio from 6.2x to 1.6x. story 3 ↓
Netflix's Titus can now move noisy stream processors onto dedicated, right-sized EC2 VMs. For this threat model, plain VMs beat microVMs and gVisor. story 4 ↓
Netflix's Quasar indexes symbols across its repos, so pull requests show which consumers call a changed or removed library method, and on which versions. story 5 ↓
1/5Cloudflare· Matthew Gumport· Oct 23
Cloudflare drops tunable range sizes, caching partial file requests in chunks
Cloudflare stopped making customers choose a fixed range size for caching partial-file requests. It now fetches the cache's own fixed disk chunks from the origin. For its R2 storage, slow-case latency roughly halved.
Why it matters · It shows a cache design flaw that customers had to tune around being fixed by matching the protocol feature to the storage layout, and the article measures the result.
Know this first
Context from the editor, not the article · 31 sec
1 · HTTP range requests
A client sends a Range: bytes=start-end header to get part of a file. The server replies 206 Partial Content, with Content-Range saying which bytes it returned. Video seeking, resumed downloads and reading a file's trailing metadata all depend on this.
2 · Origin, edge and tiers
A CDN caches content from the customer's origin server in many data centers. Tiered caching sends misses through upper-tier data centers before reaching the origin. That cuts origin load, but every byte fetched may travel several internal hops.
3 · Cache slicing
2/5PlanetScale· Rohit Nayak· Oct 23
PlanetScale explains how Neki's "shard groups" keep related Postgres rows together
PlanetScale's Rohit Nayak shows how Neki, its sharding layer for Postgres, groups tables that share a hashed key so related rows sit on one shard and keep normal Postgres transaction guarantees.
Why it matters · Choosing what to put on the same shard decides both your latency and which transactions keep ACID guarantees, and the same reasoning applies to Vitess, Citus and similar systems.
Know this first
Context from the editor, not the article · 35 sec
1 · Why sharding hurts joins
Sharding spreads a table's rows across separate database servers. A query whose rows all live on one server runs as usual. If the rows are spread out, a router has to send the query to several servers and merge the results, and any join or transaction across servers gets slower and weaker.
2 · What Neki is
Neki is PlanetScale's sharding system for Postgres. A router sits in front of several ordinary Postgres clusters, called shards. A JSON "data topology" tells it which shard each row belongs on. PlanetScale earlier built Vitess, which does the same job for MySQL.
3 · Hash-based placement
3/5Murat Demirbas (Metadata)· Murat· Oct 23
HPTS 2026: data movement costs, S3's hard-disk legacy and cutting Cassandra replica storage
Murat Demirbas's notes from days two and three of HPTS, an invitation-only systems workshop. Recurring themes: moving data now costs more than computing on it, and S3's design reflects the hard disks underneath it.
Why it matters · Several talks challenge rules engineers often treat as fixed: compute is scarce, object storage must be cached, coordination is unavoidable, and full replicas are required for durability.
Know this first
Context from the editor, not the article · 31 sec
1 · What HPTS is
High Performance Transaction Systems (HPTS) is a small, invitation-only workshop held every two years at Asilomar, California. Database and distributed-systems researchers and practitioners give short, opinionated talks. Many are position statements rather than finished papers.
2 · Lakehouses and object storage
A lakehouse keeps analytical tables as files, usually Parquet, in object storage such as Amazon S3. An open table format such as Apache Iceberg or Delta Lake adds metadata that tracks which files make up each table version. Multiple query engines can read the same data.
3 · Metastability
4/5Netflix Tech Blog· Netflix Technology Blog· Oct 22
Netflix gives noisy container workloads their own VMs inside Titus
Netflix added a single-tenant mode to Titus, its shared container platform. Selected workloads each get a dedicated EC2 instance, which cuts noisy-neighbor interference, makes patching simpler and, Netflix says, lets the shared hosts pack more densely.
Why it matters · It is a clear account of where kernel-level container isolation stops working, and of why a plain VM beat microVMs and gVisor for this particular threat model.
Know this first
Context from the editor, not the article · 35 sec
1 · What Titus is
Titus is Netflix's internal container platform, built on Kubernetes. It launches millions of containers a week across tens of thousands of EC2 instances. A central Compute/Platform team owns and patches the hosts, so application teams never manage machines, clusters or kernels.
2 · How containers share a host
Containers on one host share a single Linux kernel. Kernel features fence them off from each other: cgroups cap CPU, memory and disk, and namespaces give each container its own view of the system. Hardware such as CPU caches and the memory bus stays shared, and no cgroup can divide it.
3 · The noisy-neighbor problem
5/5Netflix Tech Blog· Netflix Technology Blog· Oct 23
Netflix builds Quasar to show which repositories a library change would break
Netflix's Java Platform team built Quasar, an internal tool that indexes code across all of the company's repositories. When a shared library's API changes, it reports which repositories call the changed method, which library versions they use, and where the calls are.
Why it matters · If you own a shared library, the usual choice is between shipping a breaking change blind and keeping dead APIs forever. Netflix's pattern replaces that guesswork with usage data you can check.
Know this first
Context from the editor, not the article · 34 sec
1 · The library producer's dilemma
Teams that publish shared libraries can see their own API diff, but not who calls each method. In a company with thousands of independently versioned repositories, consumers run many library versions at once, so removing an old method can break callers nobody knew existed.
2 · Compatibility checkers
Tools such as binary or source compatibility checkers compare two versions of a library and flag changes that break its contract, like a removed method. They say what broke but nothing about who it affects, so every flagged change looks equally risky.
A common way to cache ranges, described by nginx, splits each file into fixed-size slices. Each slice is cached separately and fetched whole on a miss. The slice size is a setting, and it is part of the cache key.
How the coordinator assembles one range response from cached, in-flight and newly fetched bytes.
The news
Cloudflare rebuilt how its 1 (content delivery network) cache handles HTTP range requests, which ask for part of a file through a Range: bytes=… header. The result is now Origin Range Requests, a self-service feature on all plans that is turned on with a Cache Rule and has no settings to tune. On 2, Cloudflare's object storage service, 3 roughly halved.
The old problem
The previous cache was built on nginx. It split each file into fixed-size ranges, and customers chose the size per zone. Small ranges turned one request into many small origin fetches that all waited in memory. Large ranges pulled far more data than the client wanted, and the waste repeated on every hop between Cloudflare's cache tiers. Changing the size invalidated the cache, because the size was part of the cache key. R2 used 64 MiB ranges, so a small read that crossed a boundary could move 128 MiB between data centers. Concurrent requests landing in the same range blocked each other, and range caching couldn't run alongside 4, which lets clients read a file while it is still being cached.
The fix
The new cache server is built on 5, Cloudflare's Rust proxy framework, and it already stores files on disk in fixed-size chunks. So the range size became the chunk size. On a request, the cache serves the bytes it already holds. For the missing bytes, it fetches chunk-aligned ranges from the origin and stores them as ordinary chunks. The client gets only the bytes it asked for. A request smaller than a chunk still costs a whole chunk, but Cloudflare argues that overhead is now bounded and predictable. The article doesn't give the chunk size.
A coordinator puts each response together. It can join a cached prefix, a download already in flight and a newly fetched suffix, and requests whose bytes are already being fetched attach to that download. Before stitching pieces together, it checks that the total size and 6 (a version tag) match across all of them. If the client's If-Range validator no longer matches, it returns the full file. It won't compose ranges over content it is about to decompress, because compressed byte offsets don't line up with decompressed ones.
Results and limits
Besides the halved p99 latency, a recent change lets one response combine bytes from disk with bytes from upstream. Before, a request came entirely from cache or entirely from upstream. That cut 7 traffic for R2-like workloads by about 6%, petabytes a day. The feature doesn't make uncacheable content cacheable, and the origin must support byte ranges.
What changed
Cloudflare has rebuilt how its 1 (content delivery network) cache handles HTTP range requests. It is releasing the result as Origin Range Requests, a self-service feature on all plans that you turn on with a Cache Rule. The old design made customers choose a fixed range size for each zone. The new one has no size to tune. On 2, Cloudflare's object storage service and the biggest internal user of range caching, 3 fell by roughly half on both cache hits and misses. A later improvement cut 4 traffic for R2 and similar workloads by about 6% week over week. Cloudflare says that adds up to petabytes per day.
The range-size trade-off
A range request asks for part of a resource, for example Range: bytes=1048576-2097151 on a 500 MB MP4 file. The server answers 206 Partial Content and gives the exact span in Content-Range: bytes 1048576-2097151/524288000. Clients use this to seek within video, resume downloads, fetch parts of package artifacts, or read the end of a file without downloading what comes before it. Cloudflare never alters what the client asks for. The work is in how the cache satisfies the request.
The previous implementation, built on nginx, worked like the cache slicing nginx describes. Each request was mapped onto fixed-size ranges of the file, and the range size and eligible file extensions were configured per zone. Every possible size had a cost:
Small ranges turned one request into many small origin requests. All of them were coalesced in memory, which put pressure on Cloudflare's memory.
Large ranges made Cloudflare download far more than the client wanted. That waste repeated on each hop: origin to the first data center, between cache tiers, then toward the client.
Changing the size invalidated cached entries, because the size was part of the cache key.
Configured sizes ranged from tens of kilobytes to tens of gigabytes. The article puts it this way: a request smaller than a floppy disk could pull "a few DVDs' worth" from the origin, sometimes after the viewer had already left. R2 used 64 MiB ranges, so a small read that crossed a boundary cost 128 MiB of transfer between data centers. Cloudflare says both failure modes caused real operational incidents.
There were also problems for users. Concurrent requests that landed in the same range blocked each other, even when the byte spans they wanted were far apart. Range caching also could not be combined with 5, a feature that lets several clients read a file from cache while it is still being written. With both enabled, responses were cut short. So every range had to finish downloading before anyone could read it, and a popular file needed a separate origin fetch for each range.
The fix: use the chunk the cache already has
Cloudflare's move from nginx to a cache server built on 6, its Rust-based proxy framework, opened a simpler path. Pingora already stores every cached file on disk in fixed-size chunks so that interrupted downloads can resume. Gumport's point is that if the cache already works in chunks, the range size doesn't need to be a setting. It can simply be the chunk size. The article does not say how big the chunks are.
For a request, the cache checks which of the requested bytes it already holds and serves those. For the missing bytes, it fetches origin ranges aligned to chunk boundaries, stores them in the same chunks used for ordinary caching, and returns only the bytes the client asked for. A request for bytes 150–250 may trigger a fetch of the whole chunk that contains them, but the client receives exactly 150–250.
This does not remove over-fetching. A request smaller than a chunk still costs a full chunk, and ranges that don't line up with chunk boundaries add work. The difference, according to Cloudflare, is that the extra work is now bounded and predictable, not set by a customer-chosen number.
A coordinator, not a lookup
Parsing the header is the easy part. The hard part is building one correct response when the bytes are spread across disk, origin responses, and downloads already in flight. For each request the edge:
Looks up the asset's headers and range-coverage metadata.
Reads what it can from disk, or from a stream already arriving in memory.
Fetches the missing coverage from the origin using aligned ranges.
Writes the new bytes and records the completed range in metadata.
Joins the pieces and sets Content-Range and Content-Length for the client.
One response might combine a cached prefix, an in-flight download and a newly fetched suffix. If a download already under way covers another request's bytes, the second request attaches to it instead of starting a new origin fetch. That shares work during traffic bursts on popular files. The data model stays the same as before: headers identify the asset version, the body sits in bounded chunks, and metadata records which ranges were written successfully.
Correctness checks
Stitching bytes together is only valid if they all come from the same representation, meaning the same version and encoding of the file. Before combining pieces, the coordinator checks three things: each origin response matches the range requested, the total size stays the same, and the 7 (entity tag, a version identifier) is consistent across subrequests. If a client sends If-Range with a validator that no longer matches, Cloudflare returns the full file rather than mixing bytes from two versions. Cloudflare also skips range composition when it is about to decompress a response, because byte offsets in compressed data don't correspond to offsets in the decompressed output. The visible behaviour is standard HTTP: 206 for a range that can be satisfied, 416 Range Not Satisfiable for one that can't, and the full response when ranging isn't safe.
Results and rollout
Cloudflare moved existing range-caching users first, starting with the most painful workloads: many concurrent range requests on very large files with spiky traffic. R2's p99 time to first byte roughly halved across its storage regions. The 6% traffic drop came from the most recent change. Before it, a request was served either entirely from cache or entirely from upstream. Now the coordinator can combine bytes on disk with bytes fetched from upstream in a single response.
Caveats
Enabling the feature does not make uncacheable responses cacheable, and partial origin fetches only help if the origin supports byte ranges. The article gives no figures for small-object or misaligned-range overhead, and no chunk size. Cloudflare plans to make this the default for certain file types. Users can opt in now with origin_range_requests: { "mode": "on" } in the API, or under Caching > Cache Rules in the dashboard.
Remember
Making a cache's internal chunk size a customer setting pushes the system's limits onto users. Matching ranges to storage chunks removed the setting.
Over-fetching remains for small or misaligned ranges, but now it is capped at one chunk on each end.
Combining cached and fetched bytes requires checking that size and ETag agree, and not composing ranges over content that will be decompressed.
Most sharded systems hash a row's shard-key value into a fixed numeric space, then give each shard a contiguous slice of that space. Similar keys end up scattered evenly, and to split a shard you just cut its slice in two.
Image: PlanetScale
PlanetScale's Rohit Nayak has published a design guide for 1 in 2, PlanetScale's sharding layer for Postgres. A shard group is a set of tables that hash a shared key the same way. Rows with the same key value therefore always land on the same shard, which is one of several Postgres clusters behind Neki's router.
Why it matters
Single-shard queries avoid sending work to every shard and merging the results. The bigger stake is correctness. A transaction that stays on one shard keeps full Postgres semantics. One that touches two shards does not: Neki commits each shard separately, with no 3 and no shared snapshot. Co-location decides which operations stay 4.
How a group works
A JSON "data topology" defines each group. The storefront example has a customer_data group whose default index hashes customer_id with 5, a fast hash, into a 64-bit keyspace. Key ranges then split that space: gets the lower half and the upper. , and inherit the index. overrides it to hash its own column. Everything about one customer ends up on one shard.
Handling the rest
Reference tables. Lookup tables like countries and currencies are copied in full to every shard in the listed groups. The router sends every write to all copies, so joins against them stay local.
Multiple groups. A catalog group shards products by SKU and can reuse the same shards or get its own. A single-shard main group holds metadata such as sequences.
Expression keys. Hashing lower(sku) puts mixed-case SKUs together. left(order_id, 4) groups orders by an embedded store ID.
Other algorithms.range maps ID ranges directly to shards, for example by geography. modulo is predictable, but changing the modulus moves nearly every row, so Nayak advises against it at scale.
Global secondary indexes. A lookup by order id alone would otherwise go to every shard. A Neki-maintained lookup table maps id to customer_id, which turns the query into two single-shard reads. Neki writes the lookup row along with the order. The post doesn't say how this stays consistent across shards, given that cross-shard commits aren't atomic.
Not permanent
The 6 workflow imports and shards existing Postgres databases. 7 changes a table's shard key or shard count later. The post gives no timings or performance numbers.
Nayak's rule: shard design starts from your queries, not your tables. Find the key your most important queries and transactions share, and put every table that carries it in one group.
PlanetScale's Rohit Nayak has written a design guide for 1 in 2, PlanetScale's sharding layer for Postgres. A shard group is Neki's unit of co-location. When two tables are in the same shard group and hash their shard keys the same way, rows with the same key value always land on the same shard. The post follows an earlier one in which a storefront's customers and orders tables were each sharded by their own ID. That forced the Neki router to perform the join itself. The fix was to shard orders by customer_id, hashed and mapped the same way as customers. Shard groups turn that fix into a general mechanism.
Why co-location matters beyond speed
The goal is for most queries to touch one shard, so the router never has to send them to every shard and merge the results. Nayak makes a sharper point about correctness. A transaction confined to one shard keeps full Postgres semantics. A transaction that touches two shards does not. Neki commits each shard separately, with no 3 (nothing like two-phase commit) and no shared snapshot. A cross-shard transaction can therefore commit on one shard and fail on the other, and a reader can see one half without the other. Shard group design decides which business operations keep 4 guarantees. It is a correctness decision as much as a performance one.
How a shard group is defined
Placement lives in a JSON document called the data topology. A shard group has two parts:
Tables in the group (customers, orders, items, addresses) inherit the index. customers gets an override: it uses the same index but with its own id column, because that column holds the customer ID there. As a result, a customer's row, orders, items and addresses all hash to the same point. Per-customer and per-order queries and transactions never leave that shard.
Reference tables
Lookup tables such as countries, currencies and tax_rates appear in joins everywhere but belong to no customer. Putting them on any single shard would make most joins cross-shard. Neki lets you declare them as 6, listing the shard groups that need them. Every shard in those groups then holds a full copy. The 7 workflow loads the initial copies. After that, the router sends every insert, update and delete to all copies. A join between a sharded table and a reference table stays local. The post doesn't cover what happens if a write to one copy fails partway through. Given the per-shard commit model above, that is worth asking about.
Several groups, one fleet
A product catalog (products, inventory, prices) is naturally keyed by SKU, not customer. Nayak adds a catalog group whose index by_sku hashes lower(sku). It uses the same two shards as customer_data, but only to save money; groups don't have to share shards. If customer data grows, Nayak suggests the catalog could stay on two small shards while customer data moves to eight large ones. A third group, main, is a single-shard home for database-wide metadata such as sequences and schema information. Every topology names one group as its authoritative shard group.
SQL expressions as shard keys
Shard indexes can hash an expression instead of a raw column. lower(sku) sends AB-1042 and ab-1042, which vendors often send in mixed case, to the same shard. If an application embeds a store ID in its order IDs, left(order_id, 4) routes 4711-00093821 by store 4711, so all of one store's orders sit together.
Other placement algorithms
xxhash is the recommended choice because it spreads keys evenly. Neki also supports two other types, mainly so applications that already shard this way can migrate without changes:
range maps integer key ranges directly to shards. In the example, merchant IDs 0–10,000 (hex 0000–2710) go to eu-1 and 10,000–20,000 (2710–4e20) go to us-1. This is useful when IDs were assigned by geography.
modulo computes value % modulus, for example 4 buckets with buckets 0–1 on store-1 and 2–3 on store-2. Placement is easy to predict, but changing the modulus moves nearly every row. Going from 4 to 5 buckets, for instance, changes the bucket of about 80% of keys. Nayak advises against it for most systems at scale.
Queries that lack the shard key
Support staff look up an order by ID: SELECT * FROM orders WHERE id = 84213. Because orders is sharded by , this query would go to every shard. Neki's answer is a : a Neki-maintained lookup table that maps to . The lookup table is an ordinary Postgres table, sharded by its own xxhash index on order . With the GSI enabled on , the query becomes two single-shard reads. The first fetches the lookup row to get . The second fetches the order from the shard that owns that customer.
orders is the GSI's owner: only 9 on orders changes the lookup table. Neki writes the lookup row "in the same request" as the order row. The lookup row usually lives on a different shard from the order. Given the earlier statement that cross-shard commits aren't atomic, the post leaves open what happens if one of the two writes fails. For existing tables, a workflow backfills the lookup table before the GSI is enabled.
Changing your mind later
Nayak stresses that placement is not permanent. MoveTables imports external Postgres databases into Neki and can shard them along the way. 10 changes a table's shard key or shard count, and shards in a group can be split or merged. The post describes these workflows but gives no performance figures or timings.
The design rule
Nayak's conclusion: shard group design starts from your queries, not your tables. Find the key that your most important queries and transactions share, and put every table that carries that key in one group. Then use reference tables, expression keys and GSIs for the rest. The post ends with a pitch for PlanetScale tools that analyse live schemas and query logs and suggest a topology.
Remember
In Neki, transactions across shards lose atomicity and snapshot isolation, so co-location decides which operations keep ACID guarantees.
Hashing an SQL expression, such as lower(sku), fixes messy keys without changing the schema.
Modulo sharding is easy to predict but moves nearly every row when the bucket count changes; prefer hashing into key ranges.
A metastable failure keeps going after its trigger is gone. A typical case: a brief slowdown causes timeouts, clients retry, and the retries add load that keeps the system overloaded. Retry storms are a frequent cause of large outages.
Murat Demirbas has posted his notes from days two and three of 1 2026 (High Performance Transaction Systems), an invitation-only workshop for database and distributed-systems people. He skipped several talks. Among the ones he covered, one theme kept coming back: moving data now costs more than computing on it.
The data-movement tax
Devashish Purandare (Microsoft) said 60–80% of datacenter execution cycles go to "tax": compression, cryptography, RPC handling, memory allocation, checksums and similar work. No single category dominates, so one big accelerator can't fix it. His answer is a 2 (data processing unit, a network card with its own cores and hardware engines) that gives each kind of task its own small accelerator. Natassa Ailamaki (EPFL) found that data movement dominates both time and energy. She proposes keeping the query plan fixed and choosing the data-movement strategy at runtime.
S3 is hard disks
Viktor Leis (TU Munich) argued that S3 is essentially a million magnetic disks. Each request sees about 10 ms of latency and 80 MB/s of throughput, and high throughput requires many large requests in parallel. In his view, caching, log structuring and large objects are all rules about hard disks. SSD-based object storage would remove them, but flash now costs 5x as much as disk, up from 3x. Iceberg on S3 manages about 1 transaction per second, so every team that wants transactions on object storage builds its own flash layer.
Colin Breck (Tesla) moved a clustered time-series database onto S3 anyway. Data sits in 3 files, and 4 queries them in place, using file footers and min/max statistics to fetch only the byte ranges it needs. There are no external indexes. He said weeks-long repartitioning and fragile replication went away.
Cheaper replication
Scott Andreas (Apple) cut Cassandra's physical-to-logical storage ratio step by step:
5, which store only a journal but still vote: 6.2x to 4.2x
Splittable "tablets" that reduce reserved headroom: 3.6x
Better compression: 2.4x
A lightweight satellite datacenter: 1.6x
Failures and consensus
Peter Alvaro called retry storms an open problem: postmortem fixes are each locally right and none settles it. Aleksey Charapko presented MESSI, a simulator for metastable failures. Alex Miller (Oracle) checked about 20 leaderless consensus protocols against real database needs. Cassandra's Accord passed, while EPaxos did not. Joe Hellerstein argued that specs need a notion of "sealing", the moment an input becomes final, because that is what makes coordination-free execution possible.
Lakehouse vs 6
Goldman Sachs described needing fast joins over fresh data, which neither lakehouses nor operational databases deliver today. Databricks pitched sub-100 ms queries on live tables. SAP's title argued that cloud HTAP, one system for both transactions and analytics, remains unsolved.
Murat Demirbas has published his notes from the second and third days of 1 2026. HPTS (High Performance Transaction Systems) is an invitation-only workshop for database and distributed-systems people. Day one was mostly about AI and specifications. Days two and three covered hardware, object storage, failures, consensus and lakehouses. He took no notes on several talks, so this is a partial record. Several talks arrived independently at the same point: moving data now costs more than computing on it.
Data movement is the bill
Devashish Purandare (Microsoft) said power is now what limits datacenter construction. He also said 60–80% of execution cycles go to "tax". Datacenter tax covers compression, cryptography, data movement, memory allocation and RPC handling. System tax covers checksums, error handling, filesystems, the kernel and networking. No single category dominates, so 2 (the speedup from optimizing one part is capped by that part's share of the total) defeats any single accelerator. Accelerators on the CPU chip are limited to what the vendor chose to include. Accelerators off the chip charge you to move data there and back.
His answer is many small accelerators. He pointed to the 3 (data processing unit, a network card with its own CPU cores and hardware engines) that Microsoft got when it bought Fungible, which now ships as the Azure Boost DPU. It has six cores with four threads each, and every task gets a dedicated accelerator. If the tax is spread across a dozen categories, you need a dozen accelerators.
Phil Bernstein (Microsoft Research) described the same hardware in more detail. A DPU pairs a multicore CPU (low latency, weaker throughput) with an ASIC for data-path work such as DMA, compression, encryption and regex (high throughput, high latency). Fungible, AMD Pensando, NVIDIA BlueField and AWS Nitro all ship them, perhaps in the millions. The natural database job is the pipeline from storage to compute: decrypt, decompress, filter. His group's DDS work (VLDB'24) gives storage a page interface: "get page at 4", where an LSN (log sequence number) names a point in the write-ahead log.
Natassa Ailamaki (EPFL) reached the same conclusion from the database side. Processors outrun memory, and data movement dominates both time and energy. The best data-movement strategy, such as pushdown or staging, depends on interactions between the query and the hardware that are too complex to model ahead of time. Her proposal keeps the query plan fixed and switches the data-movement strategy at runtime, based on how much downstream operators actually consume. In her words, "a system is only as efficient as its least adaptive component."
Bobbi Yogatama (NVIDIA) presented Sirius, a GPU analytics engine that plugs into 5 (an embedded analytical database) without changing DuckDB. Her design lesson reverses the usual trade-off: on a GPU, compute is plentiful and memory is scarce, so compress data everywhere and operate on it while it is still compressed.
S3 is a million hard disks
Viktor Leis (TU Munich) argued that S3 is essentially a million magnetic disks. Objects are hash-partitioned across them and protected with 6 (parity data spread over many disks, cheaper than full copies). Each request sees about 10 ms of latency and about 80 MB/s of throughput. High aggregate throughput, 100 Gbps in his group's experiments, comes only from issuing many large requests in parallel.
His claim is that every rule we derived from S3 is really a rule about hard disks. Seek times make caching necessary. Wide erasure coding rules out in-place writes, which forces log structuring and large objects. An SSD-based object store would remove the need for tiering, caching, batching and large sequential reads. The obstacle is cost: flash costs 5x as much as disk per byte, up from 3x a year earlier, though NAND capacity is growing faster than disk capacity. He dismissed S3 Express at 3 ms as nowhere near what an SSD can do.
The consequence for transactional (OLTP) workloads is severe. Iceberg on S3 manages about 1 transaction per second (Ginter and Leis, VLDB'26). So every team that wants OLTP on object storage builds its own flash layer. Leis argued that a local SSD cache in front of an HDD store wears out the drives quickly, and that the right fix is an SSD-based object store.
Colin Breck (Tesla) showed the operational case for object storage anyway. His team's clustered time-series database, which serves Megapack batteries, solar and charging, needed weeks of repartitioning to scale. Replication could fail catastrophically, deletes required expensive recompaction, and migrations needed custom tools. They rebuilt it as a log-structured store, with L0 and L1 in 7 on S3 and DuckDB used only for queries. DuckDB reads each file's footer for the schema and min/max statistics, then fetches only the byte ranges it needs. There are no B-trees or secondary indexes to keep in sync. S3 handles durability, and Breck argued most of the old problems came from running the cluster themselves. It also runs on on-prem S3-compatible storage.
On table formats, Chris Douglas (UC Berkeley) argued that concurrent writers rewriting metadata trees create bottlenecks. Vendors respond with centralized commit catalogs, which pull lakehouses back toward single-owner warehouses. He proposes an append-only shared log of compact "intention records". Catalog state and governance rules live in the same log as declarative logic, so each engine checks transactions itself without a central coordinator. Sergey Melnik (Databricks) asked OLTP databases for a diff API, "what changed since this LSN", which he calls Differential Change Discovery (DCD). If a row changed 40 times, change data capture (CDC, a stream of every row change) delivers 40 events for you to replay. DCD returns only the net result, in partitionable units.
Cutting replication cost
Scott Andreas (Apple) runs Apache Cassandra at dozens of petabytes. He measures physical storage provisioned per logical byte. Replication factor, LSM-tree overhead, the commit log and maintenance headroom all add to it. A default deployment has 3x replication and 30% reserved space. The notes don't fully derive his 6.2x starting figure. The steps:
8 (an idea from Pâris, 1986) store only a journal but still vote in quorums. Cassandra's Merkle-tree repair cannot work on a node that holds no data, so they replaced it with mutation tracking and reconciliation. 6.2x → 4.2x.
Tablets, splittable and reassignable key ranges, make moves and compactions cheaper and reduce reserved headroom. → 3.6x.
Better compression. → 2.4x.
A satellite datacenter: two durable replicas in two regions plus a lightweight satellite. → 1.6x.
Failures and consensus
Peter Alvaro (UC Santa Cruz, AWS) called retry an open problem. Postmortems blame aggressive timeouts, queue bounds, token buckets or FIFO queuing. Each is partly true, and none fixes the problem. Simulations are hard to calibrate, so he wants to reason about real code, citing Rupak Majumdar's Descartes. Aleksey Charapko (UNH) presented MESSI, a metastability simulator that models what closed-form queueing theory cannot. He applied it to MongoDB Atlas workload management, which uses separate queues for short and long tasks to avoid convoys.
Alex Miller (Oracle) toured about 20 leaderless consensus protocols against one test: "can it CashDB?", meaning run a real database workload. A usable one must handle contention, give a consistent local snapshot and catch up incrementally. EPaxos: no. RIOT: probably, though it uses 10x Raft's bandwidth. Cassandra's Accord (CEP-15) and high-throughput escrow transactions: yes. QuePaxa needs 7 round trips. Cloudflare is trying to put it into production, and SurrealDB is doing the same with TAPIR.
Joe Hellerstein (UC Berkeley, AWS) argued that specs need a notion of "sealing", the moment an input set becomes final. 9 (Consistency As Logical Monotonicity) says a program can be consistent without coordination exactly when it is monotone, meaning new inputs never retract earlier outputs. Sealing turns a non-monotone problem into a monotone one, which is why he argues it belongs in the spec. Demirbas isn't convinced a refined spec couldn't already express it. Johann Schleier-Smith (Temporal) noted that durable execution puts recovery in the runtime, which seems to go against the end-to-end principle.
Lakehouse vs 10
Stefano Stefani (Goldman Sachs) described a trader who needs a fast join over fresh position and risk data while a client is on the phone. Lakehouses, federation and OLTP each fail one of those requirements. Ippokratis Pandis (Databricks) noted that in-datacenter bandwidth went from 10 Gbps in 2015 to 6.4 Tbps today. He pitched Lakehouse/RT for sub-100 ms queries directly on live Delta and Iceberg tables, plus OLTP reads at an LSN straight from storage. These are vendor claims with no numbers behind them in the notes. Daniel Ritter (SAP) argued in his title alone that cloud HTAP (one system serving both transactions and analytics) is not solved.
Remember
Separate talks found that data movement, not computation, dominates datacenter time and energy, much of it in a 60–80% cycle 'tax'.
Leis argues caching, log structuring and large objects on S3 are hard-disk artifacts; Iceberg on S3 manages about 1 transaction per second.
Witness replicas, tablets, compression and satellite datacenters took Apple's Cassandra storage ratio from 6.2x to 1.6x.
A noisy neighbor is a co-located workload that degrades others by hogging a shared resource. It can do this while staying inside its own quota, so the slowdown shows up as unexplained tail latency on the victim and not as a limit being broken.
Two containers each stay within their limits but contend for shared cache and memory bandwidth, which no cgroup fences.1 / 4
Netflix has added a single-tenant mode to 1, its internal Kubernetes-based container platform. Titus normally packs many teams' containers onto large shared EC2 hosts. Now an allowlisted task can get its own right-sized EC2 instance with nothing else on it. It keeps the same API and deploy path, and the platform team still patches and scales the host. Moving in or out of the mode is a label change.
Why shared hosts weren't enough
Kernel tools like 2 and namespaces can cap a container's CPU and memory, but not the shared hardware underneath. A neighbor streaming data from RAM evicts your last-level cache lines and eats memory bandwidth while staying inside its own quota. Netflix says the network hurt most. Per-container shaping uses 3 (hierarchical token bucket), a Linux queueing discipline that takes a global lock, and a flood of small packets from one container can burn kernel CPU on that lock and starve its neighbors. For stateful stream processors such as Apache Flink jobs, a few seconds of starvation can mean restoring from a checkpoint and minutes of catch-up.
Why a plain VM
Netflix rejected the alternatives:
microVMs (4, Kata): these need bare metal or nested virtualization, which wasn't ready on Netflix's instance types. They would also have meant running a hypervisor in-house, and they don't support GPUs.
5: a user-space kernel that intercepts system calls, which adds overhead on the I/O-heavy jobs that needed protecting.
Raw EC2: gives full isolation, but hands host operations back to the application teams.
The authors argue that sandboxes solve the wrong problem. Internal teams need performance isolation, not protection from hostile tenants.
Mechanism
The 6, which decides where a job runs, checks the allowlist and records which instance families the task may use. The autoscaler launches the smallest instance that fits, just in time. The scheduler keeps the node exclusive with pod anti-affinity, a 7 that repels other pods, no preemption, and no defragmentation.
Costs and claimed wins
A fresh instance takes tens of seconds to boot before the image pull even starts. Warm pools help less than usual because right-sizing spreads demand across many instance shapes, so Netflix keeps only a small one and focuses on lazy image pulling and checkpoint/restore. Fixed host overhead can take tens of percent of a small node but only a couple of percent of a large one. So the mode suits large, long-running, disruption-sensitive workloads.
The post publishes no benchmark scores. Its claims are qualitative. Streaming teams report stable operation. The shared fleet packs more densely once spread rules for sensitive workloads are no longer needed. Patching a dedicated host means moving only one task.
Netflix has added a single-tenant mode to 1, its internal Kubernetes-based container platform. Titus normally packs many teams' containers onto large shared EC2 hosts. In the new mode an allowlisted task gets a dedicated EC2 instance, sized to fit it, with nothing else scheduled beside it. The API, the deployment pipeline and the managed model all stay the same: the Compute/Platform team still picks, patches and scales the host. Moving a workload in or out of the mode is a label change.
Where shared-kernel isolation runs out
Titus already isolates co-located containers with the usual kernel tools. 2 cap CPU, memory and disk. Namespaces give each container its own view of the system. 3 and AppArmor restrict which system calls a container can make. The Completely Fair Scheduler (Linux's CPU-time scheduler) splits CPU, the iocost controller meters disk I/O, and traffic shaping meters network. All of these work on resources the kernel can divide up. Hardware is another matter. A container that streams a lot of data from RAM evicts its neighbors' lines from the shared last-level cache and saturates memory bandwidth, and neither container breaks its CPU quota while doing it. Linux has no cgroup for cache residency or memory bandwidth.
The authors list a whole family of these channels. Scheduler run queues get contended. Receive-side packet processing runs in 4 context, a kernel interrupt-handling mode that charges one container's packet work to whichever CPU is handy, so a flood of small packets can exhaust a core's softirq budget well before any bandwidth cap applies. Storage device queues and cloud volume throughput limits are shared. Further down the list come page-cache reclaim, NUMA (non-uniform memory access) cross-socket traffic, TLB-shootdown interrupts, power throttling and global kernel locks.
Netflix says the network has caused it the most trouble. Per-container bandwidth shaping uses 5 (hierarchical token bucket), a Linux queueing discipline that accounts for traffic under a global lock. If one container sends a flood of small packets, contention on that lock burns kernel CPU and starves innocent neighbors, which then see TCP retransmits and tail-latency spikes. In the post's words, "the mechanism meant to prevent noisy neighbors becomes one."
The workloads hit hardest were stateful streaming jobs such as Apache Flink stream processors. When one of these falls behind, it may have to restore from a checkpoint and spend minutes catching up. The authors describe this as a stop-the-world event that pages someone, not a slowdown that averages out. The same teams said they never saw it on plain EC2. Netflix has worked on this before: predictive CPU pinning to reduce cache interference, eBPF probes that surface per-container run-queue latency, and an investigation of a global kernel lock. Each helped, but none removed the shared hardware.
Four options, and why a VM won
More shared-kernel tuning. Netflix is still doing this and it helps everyone, but each round narrows the gap without closing it.
The authors also argue that the threat model was wrong for the sandboxes. microVMs and gVisor are built to contain hostile tenants. Netflix's internal teams need resource and performance isolation, not protection from each other. A dedicated EC2 VM provides that with no extra virtualization layer.
How it works
The placement logic lives in the 8, the part of Titus that chooses a cell (an independent control-plane partition within a region) and capacity before scheduling. Teams opt in by targeting a single-tenant workload group, and the platform team controls an allowlist. Federation tags the task and records which instance families it may run on. The autoscaler then launches, just in time, the smallest instance from those families that fits the requested CPU, memory and GPU. The scheduler keeps the node exclusive in three ways: pod anti-affinity against all other pods, a 9 (a Kubernetes node marker that repels pods unless they explicitly tolerate it), and a priority class that exempts the task from preemption. Defragmentation and repacking are switched off for these nodes, so the task is never moved to compact the fleet.
When a task exits, its node is drained in two stages, so a pending deploy can reuse it before termination. New host images (AMIs) roll out either in place without touching the running container, or only to newly created nodes.
The costs
Launch latency. On a shared host, a task usually lands on a machine that is already booted and has its image layers cached, so it starts in seconds. A single-tenant task waits for a fresh instance, tens of seconds before the image pull even starts, plus the image pull and application startup. Warm pools of pre-booted instances work less well here. Right-sizing spreads demand across many instance shapes, and a warm r7i.2xlarge does nothing for a task that needs an m7a.8xlarge. Netflix keeps only a small warm pool and narrows the menu to a curated set of sizes, giving up some fit for a better hit rate. It is putting most of its effort into making launches cheaper:
lazy-pulling image snapshotters (stargz, SOCI) that fetch only the bytes a container actually reads at startup
CRIU checkpoint/restore of warmed-up processes
non-metal instances, which boot faster
disabling Kubernetes preemption logic, which stress tests showed was leaving fresh nodes idle while pods waited to be scheduled
Fixed overhead. Every host runs sidecars, the kubelet and system services, which take a roughly fixed slice of CPU and a few GB of memory. On a small dedicated node that can be tens of percent of the machine. On the largest shapes it is about a couple of percent. Add the gap between what the task requested and the next instance size up, and the guidance follows: single tenancy suits large, long-running, disruption-sensitive workloads sized close to an instance shape. It is a poor fit for small, bursty or elastic ones. This is also why the mode is allowlisted and not self-serve.
Control-plane load. Many small nodes mean more for Titus to track and more EC2 launch calls, which matters most during a regional failover. Netflix migrates in stages and runs scheduled stress tests of the launch path.
Results, and their limits
Netflix measures isolation with a differential benchmark. A reference app runs alone, then again next to a "havoc" container that throws an XDP UDP flood, cache-polluting pointer-chasing, STREAM memory-bandwidth load, fsync storms, stress-ng and GPU-burn at it. Runs only count once Linux 10 shows tasks actually stalling. Results are medians with bootstrapped confidence intervals, combined into a score where 100% means perfect isolation. The post publishes no actual scores. Its worked example uses placeholders.
The qualitative claims are these. Flink, connector and telemetry teams report stable operation and are no longer moved around by repacking. Some GraphQL and edge services have followed. On efficiency, Netflix argues that moving the few perpetrators and the sensitive victims off shared hosts removes the anti-affinity spreading and the pods that block defragmentation, both of which stranded capacity, so the remaining hosts pack more densely. It also says right-sizing captured more efficiency in practice than multi-tenant bin-packing, whose higher theoretical ceiling is lost to holes left by discrete instance sizes. Patching is simpler too: draining a dedicated host means moving one task.
Next steps on the shared fleet: replacing HTB with eBPF-based Earliest Departure Time pacing, which rate-limits by timestamping packets, and evaluating Intel RDT and AMD PQoS cache and memory-bandwidth partitioning plus NVIDIA MIG for GPUs. Longer term, Netflix wants a single Compute API where teams state intent, such as how much isolation they need and how fast a task must launch, and the platform chooses between VMs and containers.
Remember
cgroups can't divide cache, memory bandwidth or kernel locks, so some noisy-neighbor interference never shows up as a quota breach.
Netflix's own network shaping (HTB's global lock) became a noisy-neighbor channel under floods of small packets.
Fixed host overhead makes dedicated small nodes wasteful; single tenancy pays off only for large, long-running workloads.
Plain text search treats code as strings. It misses overloads, inheritance and generated code. Semantic indexers run the compiler's analysis and record every definition and reference under a stable, unique symbol name. Two repositories that use the same method then refer to the same identifier.
blast radius
The set of downstream systems a change could affect or break.
Overview: Quasar links a proposed API change to observed references in consumer repositories.1 / 4
Netflix's Java Platform team has built Quasar, an internal tool that tells a library owner who would be affected by a change to a public API before the change ships.
The gap
A team publishing a shared Java library can see its own API diff. A compatibility checker can flag that removing a deprecated method is a breaking change. Neither tells the team whether anyone still calls that method, which library versions those callers use, or whether another library wraps it. Dependency graphs show who declares the library, not who calls a given method. Text search misses overloads and inheritance. Building every consumer is too expensive at fleet scale. So owners either ship and find out from failures, or keep dead APIs forever.
How it works
Quasar uses 1 (SCIP Code Intelligence Protocol), an open format in which language-specific indexers record every definition and reference under a stable symbol identifier. A method defined in a library and a call to it in another repository share the same ID.
On each enrolled 2 (continuous integration) build, indexes go to Quasar, which stores definitions and references as 3 files in Amazon S3. API definitions are snapshotted per commit. On a pull request, Quasar diffs the base and head snapshots into added, removed and modified symbols. It then uses 4, which runs SQL over S3, to join changed symbols against consumer references. For JVM code it can also follow implementations and calls made through them.
An example
In the article's illustrative case, removing Client#getLegacyValue(Request) turns up 137 repositories still calling it: 86 on version 4.2.1, 38 on 4.1.7, 13 on 3.9.4. The report includes sample file paths and line numbers. With that, the owner deprecates the method, publishes a migration path and tracks the long tail, instead of merging and waiting for failures.
Being honest about evidence
The team says "no references observed" doesn't mean safe. Reflection, dynamic loading, stale branches and gaps in indexing can hide callers. Reports therefore show whether the exact commits were indexed, how fresh consumer indexes are, and whether results were truncated. If a commit snapshot is missing, Quasar refuses to compare rather than falling back to the main branch. It reports; it doesn't enforce release policy.
Limits
Usage queries cover JVM, Go, Python, JavaScript/TypeScript and Rust. Breaking-change detection covers only JVM APIs and 5 schemas traced through their generated Java. The article gives no fleet-wide numbers on coverage, freshness or how often findings changed a release. The authors argue the pattern carries over to other organisations: index semantically, compare APIs at the point of change, query consumers, and report how good the evidence is.
Netflix's Java Platform team has described Quasar, an internal tool that answers a question library owners usually can't: if I change this public method, who breaks? Quasar indexes symbol definitions and references across Netflix's repositories. When a pull request removes or changes an API, it reports how many repositories use that exact symbol, which library versions they're on, and where the calls are.
The problem: compatibility isn't the same as reach
Take a common case: removing a deprecated method. Deprecated entry points enlarge the surface a library team has to test, document and support, and they can block new designs. Suppose a replacement has existed for several releases and the old signature can't express options the new behaviour needs. The library's tests pass, and a compatibility checker flags the removal as breaking. The producer (Netflix's term for the team that owns the library) still doesn't know:
whether any consumer still calls the method;
whether consumers sit on one library version or are spread across several generations;
whether another library implements or wraps the API, which multiplies its impact;
whether a direct conversation with a few teams is enough, or a full deprecation and migration campaign is needed.
Each existing technique sees only part of the answer, the article notes. Compatibility tools find contract changes but not users. Dependency graphs show who declares the library, not who calls a given method. Text search misses overloads, inheritance and the version behind a call. Building every consumer against the new version is strong evidence but costs too much across the whole fleet. Without usage data, producers either ship and learn from consumer failures, or keep the old API forever because the risk is unknown.
How Quasar works
Quasar is built on 1 (SCIP Code Intelligence Protocol), an open interchange format for semantic code intelligence. Language-specific indexers emit definitions, references and relationships, each keyed by a stable symbol identifier. A method defined in a library repository and a call to it in a service repository get the same identifier, even when the two repositories were indexed separately.
The pipeline:
Ingest. On each enrolled 2 (continuous integration) build, indexers send SCIP indexes to Quasar's ingestion service. It writes API definitions and consumer references as 3, a columnar file format, into Amazon S3. Each record keeps the symbol identity, the dependency version and the source location.
SELECT c.change_id, 'DIRECT_REFERENCE' AS evidence_kind,
r.scm_type, r.org, r.repo, r.dep_version, r.file_path
FROM requested_changes c
JOIN quasar.symbol_refs r
ON r.symbol_canonical = c.target_canonical
A separate compatibility-impact path goes further. When a producer-side tool supplies a changed JVM method descriptor, Quasar also follows implementations of the interface and calls made through them. It then counts each affected repository once. Results are available through REST and GraphQL APIs and through an 5 (Model Context Protocol) server, with follow-up queries for version breakdowns and file locations.
A worked example
The article's simplified change replaces a method on an interface:
public interface Client {
- Result getLegacyValue(Request request);
+ Result getValue(Request request, Options options);
}
An illustrative report, which the article says combines several Quasar queries rather than one literal response, shows 137 repositories referencing Client#getLegacyValue(Request). By library version: 86 on 4.2.1, 38 on 4.1.7, 13 on 3.9.4. It includes sample file paths and line numbers, such as CheckoutClient.java lines 84 and 129 in checkout-service, and flags that one consumer is client-wrapper, a library that wraps the API. The library carries criticality Tier 1, inherited from its most critical downstream application. That doesn't mean all 137 callers are Tier 1.
That changes the plan. Rather than merging and waiting for failures, the producer can keep and deprecate the method, publish a migration path, and track the 13-repository long tail on 3.9.4 before removing it. The file locations become a concrete work list.
Treating "no usages found" with caution
The article stresses evidence quality. "No references observed" means only that none were found in the indexed population. Reflection, configuration-driven or dynamic loading, stale branches and incomplete indexing can all hide consumers. So reports state whether the base and head commits were found, how fresh the consumer indexes are, and whether results were truncated. If either commit's snapshot is missing, Quasar refuses to compare rather than falling back to the default branch, so a missing comparison never looks like a clean diff. The same removal with stale evidence should lead to a different next step: refresh the indexes first. Quasar reports and doesn't enforce. Release decisions stay with the producer.
Polyglot, with limits
Because SCIP is language-neutral, Quasar indexes JVM, Go, Python, JavaScript/TypeScript and Rust for usage queries. Relationships also let it trace generated code. A 6 definition (Protocol Buffers, Google's schema language for serialized messages) can be followed through its generated Java members to consumers that never name the .proto element. But SCIP records references, not compatibility rules. Breaking-change detection today covers only JVM APIs and Protobuf-through-Java. For the other languages Quasar can find users but can't judge whether a change breaks them.
Lessons and open questions
The team lists four lessons. Treat compatibility and reach as separate signals. Make evidence inspectable with call sites, versions and freshness. Keep usage analysis apart from per-ecosystem compatibility rules. Deliver evidence while choices are still open. Next, they want coding assistants to query Quasar while code is being written, before a pull request exists, and to use found call sites to draft consumer migrations.
The article gives no fleet-scale figures: not how many repositories are enrolled, typical index freshness, query latency, or how often findings changed a release decision. It also doesn't quantify how many consumers the blind spots (reflection, unindexed repositories) miss. The authors argue the pattern carries over to other organisations: index semantically, keep API definitions, compare at the point of change, query consumers, and report evidence quality.
Remember
A compatibility verdict and a usage count are separate signals; a breaking change with zero observed callers may still be risky.
Quasar refuses to diff when an exact commit snapshot is missing, so it never falls back to a misleading clean result.
Usage search works across five languages, but only JVM and Protobuf-through-Java get breaking-change detection.
A default shard index. In the example, by_customer is of type xxhash on column customer_id. 5 is a fast non-cryptographic hash. It maps each customer_id to a point in a 64-bit keyspace.
Key ranges. These divide the keyspace among physical Postgres clusters. store-1 gets everything below 80, and store-2 gets 80 and above. The values appear to be hex prefixes of the keyspace, so 80 is the midpoint and each shard gets half.
customer_id
8
id
customer_id
id
orders
customer_id
microVMs (6, Kata Containers). These are lightweight VMs that boot in about 150 ms. They need hardware virtualization, which means bare-metal instances or nested virtualization, and nested virtualization wasn't ready on Netflix's instance types. No managed microVM service existed, so Netflix would have had to run a hypervisor itself. They also add CPU and I/O overhead and don't support GPUs.
7. This is a user-space kernel that intercepts system calls. It avoids the need for bare metal but adds overhead on I/O-heavy paths, which are exactly the paths that needed protecting. The authors also note that the open-source version is effectively maintained by a single vendor and lags behind its internal counterpart.
Plain EC2. This gives full isolation, but the application team takes back instance selection, patching and scaling. Teams have historically treated moving from Titus to EC2 as a one-way door.
Snapshot by commit. API definitions are stored as snapshots keyed by commit. Given a pull request's base and head commits, Quasar classifies symbols as added, removed or signature-modified. Removals and modifications become candidates for impact analysis.
Query consumers. Quasar counts direct consumer references with 4, a service that runs SQL over files in S3. At its core, the query is a join on canonical symbol name: