LLMOps · Reliability

Scaling Through the Spike: Mitigating High-Volume E-Commerce Flash Sales with Semantic Caching & Azure Monitor

By SolutionJet Architecture Team

The problem: flash sales, traffic spikes and LLM cost explosions

During a flash sale such as Black Friday, product-search and recommendation traffic can jump by an order of magnitude in minutes. If every query goes to the model, three things happen at once: latency climbs, the deployment starts returning 429 rate-limit errors, and the token bill spikes. The worst part is that much of that traffic is the same few questions phrased slightly differently. "Is the 65-inch TV still on sale?" and "65 inch TV deal still on?" don't need two model calls.

The solution: semantic caching plus real-time telemetry

  • Semantic caching for cost and scale. Put Azure API Management in front of Azure OpenAI and enable its semantic cache on Azure Managed Redis. Each prompt is embedded and compared with recent prompts; a close enough match is answered from Redis without calling the model. How much this saves depends on how repetitive your traffic is, so measure the hit ratio rather than assuming one.
  • Limits for resilience. A rate limit straight after the cache lookup, plus a token limit, keeps a burst of cache misses (or a cache outage) from exhausting the model quota.
  • Telemetry for control. API Management emits token usage to Application Insights, and Azure Monitor alerts when usage, latency or errors move outside budget.

All three are API Management policies, so the storefront's application code doesn't change.

Solution architecture and data flow

Shopper queries pass through Azure API Management: semantic cache lookup in Azure Managed Redis answers hits immediately; misses pass rate and token limits to Azure OpenAI and are stored; token metrics flow to Application Insights and Azure Monitor
Hits are answered from cache; misses are limited, metered and stored for the next shopper.
  1. Request: the storefront sends the shopper's query to the API Management endpoint instead of directly to Azure OpenAI.
  2. Cache lookup: the llm-semantic-cache-lookup policy embeds the prompt with an embeddings deployment and runs a vector search in Azure Managed Redis (RediSearch). A match within the score threshold returns the stored answer immediately, with zero model tokens.
  3. Limits: on a miss, rate-limit-by-key and llm-token-limit check the caller's budget before the request reaches the model.
  4. Inference: Azure OpenAI answers, grounded in the live catalog.
  5. Store: llm-semantic-cache-store saves the answer for a short TTL so the next similar question is a hit.
  6. Telemetry: llm-emit-token-metric sends token counts per API and subscription to Application Insights for dashboards and alerts.

The policy

Prerequisites: an embeddings deployment registered as an API Management backend (embeddings-backend), an Azure Managed Redis instance created with the RediSearch module and attached to API Management as its external cache, and Application Insights connected with custom metrics enabled.

<policies>
    <inbound>
        <base />
        <!-- 1. Answer repeated questions from the semantic cache -->
        <llm-semantic-cache-lookup
            score-threshold="0.05"
            embeddings-backend-id="embeddings-backend"
            embeddings-backend-auth="system-assigned"
            ignore-system-messages="true"
            max-message-count="5">
            <!-- separate caches per storefront AND per catalog/price version -->
            <vary-by>@(context.Request.Headers.GetValueOrDefault("x-storefront", "default"))</vary-by>
            <vary-by>@(context.Request.Headers.GetValueOrDefault("x-catalog-version", "0"))</vary-by>
        </llm-semantic-cache-lookup>

        <!-- 2. Protect the model quota when misses spike (also covers a cache outage) -->
        <rate-limit-by-key calls="600" renewal-period="60" counter-key="@(context.Subscription.Id)" />
        <llm-token-limit
            counter-key="@(context.Subscription.Id)"
            tokens-per-minute="200000"
            estimate-prompt-tokens="false"
            remaining-tokens-header-name="x-remaining-tokens" />

        <!-- 3. Meter every call that reaches the model -->
        <llm-emit-token-metric namespace="FlashSale">
            <dimension name="API ID" />
            <dimension name="Subscription ID" />
        </llm-emit-token-metric>
    </inbound>
    <outbound>
        <!-- store answers briefly: prices move during a sale -->
        <llm-semantic-cache-store duration="300" />
        <base />
    </outbound>
</policies>

Three settings matter most during a sale:

  • score-threshold ranges from 0 to 1, and lower means a stricter match. Microsoft recommends starting low (around 0.05) and notes that values above 0.2 risk returning mismatched answers.
  • vary-by on the catalog version is what keeps the cache safe when prices change. When merchandising bumps x-catalog-version, every new question misses the old entries, so a shopper is never told a stale price.
  • duration should be short (minutes, not hours) for anything price- or stock-sensitive.

Watching it live: telemetry and alerts

  • Token usage per minute against budget, split by API and subscription (from llm-emit-token-metric).
  • Cache effectiveness: requests reaching the model versus total requests through the gateway. A sudden drop in hits after a catalog change is expected; a drop without one is worth investigating.
  • Latency (p95) and 429 responses at the gateway and backend.
  • Alerts in Azure Monitor on all of the above, plus an Azure Monitor workbook for the war room on sale day.

Key benefits

  • Lower cost under load: repeated questions cost zero model tokens.
  • Faster answers: cache hits return from Redis instead of waiting on inference.
  • No quota meltdown: rate and token limits keep a miss storm from taking the model deployment down for everyone.
  • Proactive observability: token, latency and error trends are visible in real time, not on next month's invoice.

Takeaways

  1. Front Azure OpenAI with API Management and turn on semantic caching before the sale, not during it.
  2. Partition the cache by catalog/price version and keep TTLs short for anything that changes.
  3. Put a rate limit right after the lookup, so a cache outage can't become a model outage.
  4. Meter tokens per caller and alert on budget, hit ratio and latency.
  5. Load-test with realistic, repetitive query mixes to tune score-threshold before traffic arrives.

References & further reading

#AzureAI#LLMOps#SemanticCaching#AzureAPIManagement#AzureManagedRedis#AzureMonitor#ApplicationInsights#Scalability#ECommerce#FinOps#CloudArchitecture

More in this series