Skip to main content

dsa-system-design

Scalability fundamentals, data partitioning, caching strategies, rate limiting, distributed systems patterns, and microservices data design — bridging classical DSA concepts to real production architecture decisions. Use when: designing or reviewing distributed system components, selecting a Cosmos DB partition key, implementing rate limiting or throttling policies, choosing caching strategies, analysing microservice communication patterns, or explaining CAP theorem trade-offs in the context of the Biotrackr architecture.

Datos de origen

Repositorio
willvelida/biotrackr
Última actividad en el origen
18 de abril de 2026 a las 23:31
Idioma detectado de SKILL.md
inglés
Estrellas
6
Forks
3

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
dsa-system-design
description
Scalability fundamentals, data partitioning, caching strategies, rate limiting, distributed systems patterns, and microservices data design — bridging classical DSA concepts to real production architecture decisions. Use when: designing or reviewing distributed system components, selecting a Cosmos DB partition key, implementing rate limiting or throttling policies, choosing caching strategies, analysing microservice communication patterns, or explaining CAP theorem trade-offs in the context of the Biotrackr architecture.
# DSA System Design ## When to Use - Selecting a partition key strategy for Cosmos DB containers - Designing or reviewing rate limiting and throttling policies - Explaining horizontal vs vertical scaling decisions - Analysing caching strategies (in-memory, distributed, CDN) - Reviewing microservice communication topology for bottlenecks - Teaching CAP theorem and consistency trade-offs in the context of production systems - Connecting classical data structure choices (heap, hash map) to distributed systems decisions ## Scalability Fundamentals ### Vertical vs Horizontal Scaling | Approach | Mechanism | Limit | |---|---|---| | Vertical | Add CPU/RAM to one machine | Hardware ceiling | | Horizontal | Add more machines / replicas | Near-unlimited with stateless design | **Biotrackr context:** Azure Container Apps scales horizontally — new container replicas are spun up under load. Services must be **stateless** (no local in-memory state that needs to be shared) for horizontal scaling to work correctly. Cosmos DB handles horizontal scaling via partitioning. ### Latency Reference Numbers | Operation | Approximate Latency | |---|---| | L1 cache read | ~1 ns | | Memory (RAM) read | ~100 ns | | SSD read | ~100 µs | | Network round-trip (same region) | ~1 ms | | Cosmos DB query (indexed, right partition) | ~5–10 ms | | Cross-region replication lag | ~50–150 ms | **Teaching angle:** A cache hit that avoids a Cosmos DB query saves ~5–10 ms per call. At 100 calls/sec, that is 500–1000 ms of latency removed from the system per second. ## Data Partitioning (Cosmos DB Context) ### Why Partitioning Matters Cosmos DB distributes data across physical partitions by hash of the partition key. All requests for a given key are routed to the same physical partition — O(1) dispatch. ### Partition Key Selection Criteria | Criterion | Goal | |---|---| | High cardinality | Spread data evenly across partitions | | Even access distribution | Avoid hot partitions (one partition gets all traffic) | | Aligns with query patterns | Most queries filter by the partition key | | Does not change after write | Partition key is immutable once written | ### Biotrackr Partition Key Examples | Container | Partition Key | Rationale | |---|---|---| | Records | `/documentType` | Biotrackr services share one `records` container; partitioning by document type groups related documents and matches the current container design | | Conversations | `/sessionId` | Each chat session is isolated; session-scoped reads and deletes naturally target a single partition | **Teaching angle:** In Biotrackr, the shared `records` container is partitioned by `/documentType`, not `/date`. That reflects the current service design, where activity, sleep, food, and vitals documents are separated by type inside one container. For conversations, `/sessionId` is the right partition key because history is loaded, appended, and deleted per session. If query patterns or tenant boundaries change in the future, re-evaluate the partition key against actual access patterns and hot-partition risk rather than assuming a date-based strategy. ### Hot Partition Anti-Pattern A hot partition occurs when a large fraction of requests target one partition key value. Symptoms: throttling on one partition key despite low overall RU consumption. **Fix:** Increase partition key cardinality by appending a suffix (synthetic sharding): `date_shard` where shard = `hash(record_id) % N`. ## Caching Strategies ### Cache Patterns | Pattern | Description | Use Case | |---|---|---| | Cache-aside (lazy) | App checks cache first; on miss, loads DB and populates cache | Read-heavy, tolerable staleness | | Write-through | Write to cache and DB simultaneously | Read-heavy, strong consistency needed | | Write-behind | Write to cache; async flush to DB | Write-heavy, eventual consistency acceptable | | Read-through | Cache handles DB load on miss transparently | Simpler app logic | ### Biotrackr Anchor — CachingMcpToolWrapper `CachingMcpToolWrapper` in `Biotrackr.Chat.Api` implements **cache-aside** for MCP tool calls. Cache key = tool name + parameter hash; TTL varies by tool type. **Teaching angle:** The cache is a hash map with expiry. Cache-aside is the most common pattern because it is simple and degrades gracefully: on cache miss, the application falls back to the source of truth. Write-through and write-behind add complexity only when write performance is the bottleneck. ### Cache Invalidation Strategies - **TTL (time-to-live):** simplest — data expires after a fixed duration - **Event-driven invalidation:** write to DB triggers cache eviction (more complex) - **Versioned keys:** append a version/hash to the key; old entries become unreachable ## Rate Limiting and Throttling ### Rate Limiting Algorithms | Algorithm | Description | Burst Handling | |---|---|---| | Token bucket | Bucket refills at rate r; each request consumes 1 token | Allows bursts up to bucket size | | Leaky bucket | Requests exit at fixed rate regardless of input rate | Smooths bursts | | Fixed window counter | Count requests per time window; reset at window boundary | Boundary burst problem | | Sliding window log | Track request timestamps; evict expired | Accurate, memory-intensive | ### Biotrackr Anchor — MCP Server Rate Limiting `Biotrackr.Mcp.Server` enforces **100 requests/minute per IP, queue size 10** using ASP.NET Core rate limiting middleware. The service configures a **global partitioned rate limiter** with a **fixed window counter** per client IP: each IP can make up to 100 requests in a one-minute window, the counter resets at the next window boundary, and up to 10 additional requests can wait in the queue. ```csharp // Global fixed-window limiter partitioned by client IP options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext => { var ipAddress = httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown"; return RateLimitPartition.GetFixedWindowLimiter( partitionKey: ipAddress, factory: _ => new FixedWindowRateLimiterOptions { PermitLimit = 100, Window = TimeSpan.FromMinutes(1), QueueProcessingOrder = QueueProcessingOrder.OldestFirst, QueueLimit = 10 }); }); ``` ### Biotrackr Anchor — APIM Throttling Policies Azure API Management applies quota and rate limit policies at the gateway layer before requests reach the backend services. This is a distributed rate limiter: APIM counts requests centrally and rejects early, protecting backend services from overload. **Teaching angle:** A rate limiter is a **leaky bucket or token bucket** implemented as a counter with a TTL. In a distributed system, the counter must be stored in a shared store (Redis, APIM internal store) rather than in-process memory. ## Microservices Data Patterns ### Database-per-Service Biotrackr follows a modified database-per-service pattern: Activity, Sleep, Food, and Vitals share a single **Cosmos DB `records` container** within a shared account rather than provisioning one container per domain. The container is partitioned by **`/documentType`**, and each domain writes and queries its own document types. This gives logical domain isolation within the shared container. **Trade-offs:** - Reduces infrastructure overhead by reusing one container for multiple domains - Keeps domain records separated logically through `documentType`-based partitioning - Cross-domain queries require explicit filtering because unrelated document types coexist in the same container - Domains share container-level throughput and storage characteristics instead of scaling completely independently ### Eventual Consistency and the CAP Theorem CAP theorem: a distributed system can guarantee at most two of: - **Consistency** — every read sees the most recent write - **Availability** — every request gets a response (possibly stale) - **Partition tolerance** — the system continues despite network splits Cosmos DB supports multiple consistency levels, from **strong** through **eventual**, letting systems choose the trade-off between read freshness, latency, and availability characteristics. Biotrackr is configured to use **session consistency** — reads see writes from the same logical session, providing a practical balance of performance and correctness for user-scoped workloads. ### Event-Driven Data Flow Biotrackr's ingest services (Activity.Svc, Sleep.Svc, Food.Svc, Vitals.Svc) write to Cosmos DB asynchronously. Downstream APIs read from these containers. This is an **event-sourcing-lite** pattern: the service writes the fact, and readers query when needed. ### API Gateway Pattern (APIM) APIM acts as the single entry point for all external requests. From a DSA perspective, APIM is a **routing table** — an O(1) lookup from request path to backend service — plus a policy pipeline (a linked list of processing steps: auth → rate-limit → transform → route). ## Container Apps Scaling Triggers Azure Container Apps scales on: - **HTTP concurrency** — scale out when concurrent requests exceed threshold - **CPU/memory** — scale out on resource saturation - **KEDA-based** — scale on queue depth, Cosmos DB change feed lag, custom metrics **Teaching angle:** Scaling triggers are **threshold functions** — binary decisions based on a measured value crossing a boundary. The correct threshold depends on the latency target and per-replica capacity, which requires profiling (load testing) rather than guessing.
Ver en GitHub