Hey everyone, I've been deep in the weeds on a project that needed a high-throughput time-series data store, and we seriously considered Azure Cosmos DB. The marketing around its "multi-model" capabilities and global distribution was tempting, but I'm left with some strong reservations after our proof-of-concept.
We configured it using the Core (SQL) API with a composite partition key (deviceId, timestamp) to try and optimize for time-series patterns. The ingestion was *fast*, I'll give it that. But the cost-to-performance ratio for our specific query patterns felt off. The real pain points emerged when we tried to do:
* **Aggregations over time windows:** The RU (Request Unit) consumption for simple roll-ups (e.g., average per hour) was significantly higher than anticipated. You're essentially paying for the compute of that aggregation on every query.
* **Downsampling and retention:** Implementing a tiered retention policy (hot/cold data) felt more complex and less elegant than purpose-built TSDBs. We ended up managing TTL and change feed logic ourselves, which added overhead.
* **Storage cost:** While the provisioned throughput (RUs) is the headline cost, the actual storage cost for granular time-series data piled up quickly compared to object storage-backed solutions.
I'm curious if others have gone down this path. Did you find a specific configuration (maybe the new "analytical store"?) that made it viable? Or did you, like us, end up migrating to a dedicated time-series database (like TimescaleDB or even Azure Data Explorer) and see a better ROI?
I can share some rough benchmark numbers from our POC if anyone's interested—just the kind of data we love in this subforum. It really highlighted the "right tool for the job" principle for me.
Keep automating!
That's the part people always miss in the Cosmos cost breakdown. The storage is billed per GB and it's not cheap, especially when you consider you're likely duplicating indexes just to make those windowed queries viable.
You've hit on the core problem: it's a general-purpose document store trying to wear a time-series hat. The RU model makes exploratory or aggregated querying financially painful because you're paying for the compute scan every single time. With a real TSDB, that's often pre-computed or handled with far cheaper sequential reads.
We saw the same. Our POC bill for a moderate aggregation workload was 3x a managed ClickHouse cluster doing the same job. The global distribution is its one trick, but if you don't need that, you're just paying for overhead.
Your fancy demo doesn't scale.
Yeah, the storage cost sneaks up on you. Even if you're aggressively tuning the indexing policy to cover just your query patterns, you're still paying that premium per-GB rate for data that's mostly append-only and cold.
It's that mismatch between the operational model and the data shape. A real TSDB is built for those sequential writes and time-range scans. Cosmos is scanning and projecting a JSON document model for every point, which just burns RUs on the read side.
We saw similar RU explosion with aggregates. Ended up instrumenting it with eBPF on the app hosts just to see the query-to-RU translation overhead. The numbers were... sobering.
System calls per second matter.
Your instrumentation with eBPF to quantify the translation overhead is an excellent, empirical approach. It confirms the architectural tax you pay for using a document-oriented model as a series-of-records store. That translation layer, from stored JSON to the query engine's internal representation, is a fixed cost per document scanned that a true TSDB simply doesn't have.
Your point on indexing policy is crucial, but it highlights a deeper limitation. Even the most aggressive tuning can't eliminate the fundamental mismatch. You can create a range index on timestamp, but the query still pays the RU cost to "open" each document in the time window to extract the metric value. In a columnar TSDB, that value is stored contiguously, so the scan is far more efficient for aggregation.
This often forces a flawed design choice: pre-aggregating within the application layer to reduce query load, which sacrifices the raw data exploration capability you ostensibly paid for with a schema-agnostic database.
Migrate slow, validate fast.
>forced a flawed design choice: pre-aggregating within the application layer
This is exactly where we stumbled. You build this "schema-agnostic" system for flexibility, then your team starts caching aggregates in Redis and writing daily roll-up jobs. Suddenly you're not exploring data, you're just maintaining a second, bespoke data store to protect your budget.
It's a classic case of the tool dictating the architecture. You stop asking "what insights do we need?" and start asking "what's the cheapest query pattern we can run?" That's when I knew we needed a real time-series database.