How to Reduce REST API Latency with Distributed Caching and Query Optimization
By Kevin Marcondes · Published on · Updated on · 7 min read
If you want to reduce REST API latency with distributed caching and better SQL, start by measuring where time is lost. Then apply the right tactics: HTTP caching, Redis for hot data, and efficient SQL. This practical guide shows signals to watch, decision criteria, and safe steps you can apply without breaking production.
Symptoms and an initial diagnosis (p95, TTFB and bottlenecks)
Before changing code, confirm the problem. Measure p95/p99 for the API, network time, application time and database time. The goal is to isolate the real bottleneck.
Use correlated logs, distributed tracing and APM. Compare p50 vs p95: a large gap indicates long tails. Evaluate TTFB and total payload size.
Typical latency patterns show up during peak times. Run controlled tests outside peak windows to validate hypotheses. Avoid blind optimization.
- High p95 with a slow DB: start with queries and indexes.
- High p95 with high CPU: review serialization, JSON handling and memory allocations.
- High p95 with network latency: compress responses and reduce payload.
- High variance across endpoints: focus on the top 20% most critical.
- Low cache hit rate on stable endpoints: clear caching opportunity.
Cache layers that actually reduce latency
Not all caches are the same. Combine layers to cut round trips and processing. Start with HTTP semantics, then add layers closer to the application.
Use Cache-Control, ETag and Vary to enable reuse in clients and CDNs. That can eliminate entire requests.
When responses depend on authentication or filters, consider caching at the gateway or in the service using keys that represent those parameters.
| Cache Layer | What it stores | When to use | Notes |
|---|---|---|---|
| Client (browser/app) | HTTP responses with ETag/Cache-Control | Public reads or rarely changing data | Simple and cheap; respect conditional validation. |
| CDN/Edge | Public content and aggregations | Assets and public GET APIs | Control TTL and invalidate by path. |
| API Gateway | Endpoint GET/HEAD responses | Predictable spikes and simple keying | Be careful with authentication and variable headers. |
| Service (Redis/Memcached) | Objects and query results | Hot data with heavy reads | Design keys and TTLs well; monitor hit rate. |
| Precomputation/Jobs | Snapshots, materializations | Expensive, predictable reports | Run periodic jobs; publish versions. |
Distributed cache in practice: keys, TTL and invalidation
Redis is a common choice for distributed caching. Define stable keys that express data variation: schema version, user, filters and locale.
TTLs prevent eternal data and simplify invalidation. Use different TTLs per data type. For critical data, expose a controlled invalidation endpoint.
Useful strategies include write-through, cache-aside and write-behind. Choose based on desired consistency and write impact.
- Key pattern: app:version:resource:params_hash.
- Use lightweight serialization (compact JSON or MsgPack).
- Apply TTL with jitter to avoid simultaneous expirations.
- Warm caches after high-traffic deploys.
- Monitor baseline metrics: hit rate per endpoint and p95 latency for hits vs misses.
Avoid cache storms and consistency issues
A cache stampede happens when many misses trigger expensive queries simultaneously. Implement request coalescing or lightweight locks so only one request recomputes the value.
Use soft TTL with background refresh to keep latency low without serving excessively stale data. Apply backoff and circuit breakers for cache failures.
Consistency: when the source of truth is the database, prefer cache-aside. For critical writes, avoid write-back. Track versions for safe batch invalidation.
- Mutex per key (e.g., Redlock used cautiously).
- Controlled stale-while-revalidate based on metrics.
- Redis outages must not take down the API: provide fallbacks.
- Monitor deserialization errors and value sizes.
SQL query optimization that unlocks the database
Many slow APIs have a SQL bottleneck. Start with EXPLAIN/EXPLAIN ANALYZE. Ensure filters and joins can use appropriate indexes.
Avoid N+1 queries with eager loading and controlled joins. Design composite indexes in the order of the most selective predicates.
Return fewer columns and prefer cursor (keyset) pagination for large lists. High OFFSET values degrade execution plans and latency.
For a deeper dive into SQL, consult PostgreSQL-focused material for slow-report queries.
- Covering indexes for frequent queries.
- Materialize expensive aggregations outside the online path.
- Avoid non-indexable functions in WHERE clauses.
- Keep statistics up to date and tune autovacuum settings.
Cache or optimize first? Decision criteria
Let the data guide you. If an endpoint is highly reused and rarely updated, caching yields quick wins. If the pattern is highly dynamic, optimize the queries.
When projected hit rate is low, prioritize the database model and queries. For massive read traffic with stable data, favor Redis with appropriate TTLs.
- High repetition of parameters => cache it.
- Sensitive, volatile data => optimize the database first.
- Expensive, predictable reports => precompute snapshots.
- Large payloads => reduce fields, compress and paginate.
Measure, test and deploy safely
Run canary releases with p95/p99 metrics per version. Warm caches before routing full traffic. Use feature flags to enable changes for segments.
Automate tests and deployments to reduce risk. When creating large indexes, plan maintenance windows and use online index techniques when possible. Monitor closely after rollout.
Rate limiting doesn't reduce latency by itself, but it protects resources under peak load. Combine rate limits with caching for sustained stability.
- Load tests with realistic traffic profiles.
- Alerts for cache and database errors.
- Dashboards showing hit rate per endpoint.
- Fast rollback if latency increases.
Frequently asked questions
Which should I implement first: caching or query optimization?
Let the data decide. If an endpoint is highly reused and updates are rare, cached responses yield quick wins. If data is dynamic or projected cache hit rate is low, prioritize SQL: indexes, query plans and eliminating N+1s. Measure p95/p99 and TTFB before and after any change to validate impact and avoid blind optimization.
What TTL should I use in Redis for REST APIs?
TTL depends on how tolerant clients are to staleness and how often data changes. Use longer TTLs for near-static data (minutes to hours) and shorter TTLs or targeted invalidation for sensitive, frequently updated items. Apply jitter to spread expirations and consider exposing controlled invalidation endpoints for critical updates.
How do I prevent cache stampede on popular endpoints?
Prevent stampedes with request coalescing or per-key locks so a single request rebuilds a value while others wait. Combine soft TTL with background refresh to serve slightly stale data while refreshing, and add backoff or circuit breakers for cache failures. Monitor misses-per-second and sudden drops in hit rate to detect problems early.
What to do when large OFFSET makes the API slow?
Avoid large OFFSETs by using cursor (keyset) pagination. Keyset pagination uses a stable marker (cursor or next_token) to continue scans without skipping rows, keeping execution plans efficient and latency low for deep pagination. Return a next_token in responses to let clients continue navigation with predictable performance.
Does HTTP caching work for authenticated APIs?
Yes, with caution. Use ETag plus Cache-Control and Vary headers; mark responses private when they are user-specific and include user or auth-derived keys at the gateway. Client-side and gateway caches can help, but avoid relying on public intermediaries for sensitive authenticated content and ensure cache keys capture relevant parameters.
Does rate limiting reduce API latency?
Rate limiting does not directly lower per-request latency, but it protects resources under peaks, preventing overload that causes long tails. Use rate limits alongside caching and query optimization: limits stabilize load while caching reduces work and optimized queries lower database cost, together keeping p95/p99 latency under control.
Want to tackle latency without risking production?
Talk about your scenario, current metrics and priorities. We can sketch a safe cache and SQL plan to test in canary.
Discuss your caseSee also
- How to recover corrupted statistics and indexes in PostgreSQL that caused slow queries
- REST API latency spikes from N+1 queries and PHP GC — how to diagnose and fix
- Postgres 'Too many connections' at billing peak — practical diagnosis and remediation guide
- Reduce costs migrating Magento to OpenMage with a rollback plan and acceptance tests