Skip to content
advanced Phase 119 · Senior Projects

Project - High-Traffic Flash Sale Store

Design and optimize a high-traffic Magento store for flash sales with caching, queuing, and monitoring

3h
0 problems
Topic Progress 0%

Infrastructure Architecture

Traffic Profile

Flash Sale Traffic Timeline:
─────────────────────────────────────────────────
Time     │ Traffic    │ Events
─────────┼────────────┼────────────────────────
T-24h    │ 1x         │ Pre-sale announcement
T-4h     │ 3x         │ Email blast goes out
T-1h     │ 5x         │ Customers waiting
T-0      │ 50x        │ Sale starts
T+15min  │ 30x        │ Stock running low
T+30min  │ 10x        │ Most items sold
T+1h     │ 3x         │ Post-sale browsing
T+2h     │ 1x         │ Back to normal

Infrastructure Topology

                    ┌─────────────┐
                    │    CDN      │
                    │  (CloudFlare)│
                    └──────┬──────┘
                           │
                    ┌──────┴──────┐
                    │   Varnish   │
                    │  (4 nodes)  │
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
       ┌──────┴──────┐ ┌──┴───┐ ┌──────┴──────┐
       │  Web Node 1 │ │ ...  │ │  Web Node N  │
       │  (Auto)     │ │      │ │  (Auto)      │
       └──────┬──────┘ └──┬───┘ └──────┬──────┘
              │            │            │
              └────────────┼────────────┘
                           │
                    ┌──────┴──────┐
                    │  Load       │
                    │  Balancer   │
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
       ┌──────┴──────┐ ┌──┴───┐ ┌──────┴──────┐
       │  Redis      │ │ ...  │ │  Redis      │
       │  Cluster    │ │      │ │  Sentinel   │
       └──────┬──────┘ └──┬───┘ └──────┬──────┘
              │            │            │
              └────────────┼────────────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
       ┌──────┴──────┐ ┌──┴───┐ ┌──────┴──────┐
       │  MySQL      │ │ ...  │ │  MySQL      │
       │  Primary    │ │      │ │  Read       │
       │             │ │      │ │  Replicas   │
       └─────────────┘ └──────┘ └─────────────┘

Resource Sizing

Component        │ Normal     │ Flash Sale  │ Scaling Method
─────────────────┼────────────┼─────────────┼─────────────────
Web Nodes        │ 2          │ 8-16        │ Auto-scaling group
Varnish          │ 2          │ 4-6         │ Manual + health checks
Redis            │ 3 (cluster)│ 6           │ Cluster expansion
MySQL Primary    │ 1 (8vCPU)  │ 1 (16vCPU)  │ Vertical scale
MySQL Read       │ 1          │ 3           │ Add replicas
RabbitMQ         │ 1          │ 2 (cluster) │ Cluster mode
OpenSearch       │ 3 nodes    │ 6 nodes     │ Add data nodes
CDN              │ Standard   │ Premium     │ Pre-deploy assets

Auto-Scaling Configuration

# AWS Auto Scaling Group
auto_scaling_group:
  min_size: 2
  max_size: 16
  desired_capacity: 2
  scaling_policies:
    - name: scale_up_cpu
      metric: CPUUtilization
      threshold: 60
      adjustment: +2
      cooldown: 180
    - name: scale_up_requests
      metric: RequestCount
      threshold: 1000
      adjustment: +2
      cooldown: 120
    - name: scale_down
      metric: CPUUtilization
      threshold: 30
      adjustment: -1
      cooldown: 300

Pre-Sale Checklist

#!/bin/bash
# pre-sale-checklist.sh

# 1. Scale infrastructure
echo "Scaling infrastructure..."
terraform apply -var='node_count=12'

# 2. Warm caches
echo "Warming caches..."
bin/magento cache:clean
bin/magento cache:warm --url=http://magento.local/flash-sale

# 3. Pre-deploy static content
echo "Deploying static content..."
bin/magento setup:static-content:deploy -f

# 4. Reindex
echo "Reindexing..."
bin/magento indexer:reindex catalogsearch_fulltext
bin/magento indexer:reindex catalog_product_price

# 5. Clear sessions
echo "Clearing old sessions..."
redis-cli -h redis-cluster DEL session:*

# 6. Verify Varnish
echo "Testing Varnish..."
curl -s -o /dev/null -w '%{http_code}' -H 'X-Magento-Cache-Type: FPC' http://varnish/flash-sale

# 7. Enable maintenance for deployment (if needed)
# bin/magento maintenance:enable
# bin/magento maintenance:disable

# 8. Verify database connections
echo "Verifying DB..."
mysql -h primary -e "SELECT 1" > /dev/null
mysql -h replica1 -e "SELECT 1" > /dev/null

# 9. Start queue consumers
echo "Starting queue consumers..."
php bin/magento queue:consumers:start flash.sale.orders --max-messages=1000 &

# 10. Final verification
echo "Pre-sale checklist complete!"

Multi-Layer Caching Strategy

Cache Layers

Request Flow:

Browser → CDN (CloudFlare)
  │
  ├── Static assets → CDN cache (7 days)
  │
  └── Dynamic pages → Varnish
       │
       ├── FPC hit → Return cached HTML (24h TTL)
       │
       └── FPC miss → Magento
            │
            ├── Block cache → Redis (1h TTL)
            ├── Config cache → Redis (permanent)
            ├── Page cache → Redis (1h TTL)
            │
            └── Database query → MySQL

Varnish Configuration

# flash-sale.vcl - Varnish configuration for flash sales

backend default {
    .host = "magento-web";
    .port = "8080";
    .connect_timeout = 5s;
    .first_byte_timeout = 90s;
}

sub vcl_recv {
    # Flash sale pages - aggressive caching
    if (req.url ~ "^/flash-sale") {
        unset req.http.Cookie;
        set req.http.X-Cache-Control = "public, max-age=86400";
        return (hash);
    }

    # Product pages - moderate caching
    if (req.url ~ "^/catalog/product/view") {
        unset req.http.Cookie;
        return (hash);
    }

    # Category pages - moderate caching
    if (req.url ~ "^/catalog/category/view") {
        unset req.http.Cookie;
        return (hash);
    }

    # Never cache cart/checkout
    if (req.url ~ "^/checkout" || req.url ~ "^/cart") {
        return (pass);
    }
}

sub vcl_backend_response {
    # Flash sale content - long TTL
    if (bereq.url ~ "^/flash-sale") {
        set beresp.ttl = 24h;
        set beresp.http.X-Cacheable = "YES:FlashSale";
    }

    # Product pages
    if (bereq.url ~ "^/catalog/product/view") {
        set beresp.ttl = 1h;
        set beresp.http.X-Cacheable = "YES:Product";
    }

    # Static assets
    if (bereq.url ~ "\.(js|css|png|jpg|gif|ico|svg)$") {
        set beresp.ttl = 7d;
        set beresp.http.X-Cacheable = "YES:Static";
    }

    # Set grace period for stale content
    set beresp.grace = 10m;
}

Redis Cache Configuration

<?php
// app/etc/env.php cache configuration
'cache' => [
    'frontend' => [
        'default' => [
            'backend' => 'Cm_Cache_Backend_Redis',
            'backend_options' => [
                'server' => 'redis-cluster',
                'port' => '6379',
                'database' => '0',
                'compress_data' => '1',
                'force_standalone' => '0',
                'connect_retries' => '1',
                'read_timeout' => '10',
                'automatic_cleaning_factor' => '20',
                'compress_tags' => '1',
                'lazy_flush' => '1',
            ],
        ],
        'page_cache' => [
            'backend' => 'Cm_Cache_Backend_Redis',
            'backend_options' => [
                'server' => 'redis-cluster',
                'port' => '6379',
                'database' => '1',
                'compress_data' => '1',
                'force_standalone' => '0',
                'connect_retries' => '1',
                'read_timeout' => '10',
                'compress_tags' => '1',
                'lazy_flush' => '1',
            ],
        ],
    ],
],

Cache Warming Strategy

<?php
namespace Vendor\FlashSale\Model\Cache;

class CacheWarmer
{
    public function __construct(
        private \Magento\Framework\HTTP\Client\Curl $curl,
        private \Psr\Log\LoggerInterface $logger,
    ) {
    }

    public function warmFlashSalePages(): void
    {
        $urls = $this->getFlashSaleUrls();

        foreach ($urls as $url) {
            try {
                $this->curl->get($url);
                $this->logger->info('Cache warmed', ['url' => $url]);
            } catch (\Exception $e) {
                $this->logger->error('Cache warm failed', ['url' => $url, 'error' => $e->getMessage()]);
            }
        }
    }

    private function getFlashSaleUrls(): array
    {
        $baseUrl = 'https://magento.local';
        $urls = [
            $baseUrl . '/flash-sale',
            $baseUrl . '/flash-sale/widget',
            $baseUrl . '/flash-sale/gadget',
            $baseUrl . '/flash-sale/electronics',
        ];

        // Add product pages
        $products = $this->getFlashSaleProducts();
        foreach ($products as $product) {
            $urls[] = $baseUrl . '/' . $product->getUrlKey() . '.html';
        }

        return $urls;
    }
}

Queue-Based Order Processing

Queue Architecture

Order Processing Pipeline:

Customer → Cart → Checkout → Order Service
                                │
                    ┌───────────┴───────────┐
                    │                       │
              ┌─────┴─────┐           ┌─────┴─────┐
              │ Inventory │           │ Payment   │
              │ Queue     │           │ Queue     │
              └─────┬─────┘           └─────┬─────┘
                    │                       │
              ┌─────┴─────┐           ┌─────┴─────┐
              │ Reservation│           │ Payment   │
              │ Service   │           │ Process   │
              └─────┬─────┘           └─────┬─────┘
                    │                       │
                    └───────────┬───────────┘
                                │
                    ┌───────────┴───────────┐
                    │                       │
              ┌─────┴─────┐           ┌─────┴─────┐
              │ Email     │           │ Index     │
              │ Queue     │           │ Queue     │
              └───────────┘           └───────────┘

Queue Configuration

<!-- etc/queue_topology.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd">
    <exchange name="flash-sale" type="topic" durable="true">
        <binding queue="flash.sale.orders" topic="flash.sale.order.*"/>
        <binding queue="flash.sale.inventory" topic="flash.sale.inventory.*"/>
        <binding queue="flash.sale.email" topic="flash.sale.email.*"/>
    </exchange>
</config>

Order Queue Publisher

<?php
namespace Vendor\FlashSale\Queue\Publisher;

use Magento\Framework\MessageQueue\PublisherInterface;

class OrderPublisher
{
    public function __construct(
        private PublisherInterface $publisher,
    ) {
    }

    public function publishOrder(array $orderData): void
    {
        $this->publisher->publish(
            'flash.sale.order.process',
            json_encode([
                'order_id' => $orderData['order_id'],
                'items' => $orderData['items'],
                'timestamp' => time(),
                'priority' => $this->calculatePriority($orderData),
            ])
        );
    }

    private function calculatePriority(array $orderData): int
    {
        $total = $orderData['total'] ?? 0;

        if ($total > 500) return 1; // High priority
        if ($total > 100) return 2; // Medium priority
        return 3; // Normal priority
    }
}

Inventory Reservation Consumer

<?php
namespace Vendor\FlashSale\Queue\Consumer;

use Vendor\FlashSale\Api\InventorySyncInterface;
use Psr\Log\LoggerInterface;

class InventoryConsumer
{
    private int $maxRetries = 3;

    public function __construct(
        private InventorySyncInterface $inventorySync,
        private LoggerInterface $logger,
    ) {
    }

    public function process(string $messageBody): void
    {
        $message = json_decode($messageBody, true);
        $sku = $message['sku'] ?? '';
        $qty = $message['qty'] ?? 0;
        $orderId = $message['order_id'] ?? '';

        $this->logger->info('Inventory consumer processing', [
            'sku' => $sku,
            'qty' => $qty,
            'order' => $orderId,
        ]);

        $retryCount = 0;
        while ($retryCount < $this->maxRetries) {
            try {
                $this->inventorySync->reserveStock($sku, 1, $qty, $orderId);
                return; // Success
            } catch (\Exception $e) {
                $retryCount++;
                $this->logger->warning('Inventory reservation failed', [
                    'sku' => $sku,
                    'retry' => $retryCount,
                    'error' => $e->getMessage(),
                ]);
                usleep(100000 * $retryCount); // Backoff
            }
        }

        // Send to dead letter queue
        $this->sendToDeadLetter($message, 'Max retries exceeded');
    }

    private function sendToDeadLetter(array $message, string $reason): void
    {
        $this->logger->critical('Dead letter queue', [
            'message' => $message,
            'reason' => $reason,
        ]);
    }
}

Queue Scaling

#!/bin/bash
# scale-consumers.sh

# Scale based on queue depth
QUEUE_DEPTH=$(rabbitmqctl list_queues flash.sale.orders messages 2>/dev/null | tail -1)
CURRENT_CONSUMERS=$(pgrep -f 'flash.sale.orders' | wc -l)

if [ $QUEUE_DEPTH -gt 1000 ] && [ $CURRENT_CONSUMERS -lt 10 ]; then
    echo "Scaling up consumers (queue depth: $QUEUE_DEPTH)"
    for i in $(seq 1 3); do
        php bin/magento queue:consumers:start flash.sale.orders --max-messages=500 &
    done
fi

if [ $QUEUE_DEPTH -lt 100 ] && [ $CURRENT_CONSUMERS -gt 3 ]; then
    echo "Scaling down consumers (queue depth: $QUEUE_DEPTH)"
    # Kill oldest consumers
fi

Monitoring and Auto-Scaling

Monitoring Dashboard Metrics

# Prometheus/Grafana metrics
dashboard:
  name: Flash Sale Monitor
  panels:
    - title: Request Rate
      query: rate(http_requests_total[1m])
      threshold: >5000

    - title: Response Time P99
      query: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
      threshold: >2s

    - title: Queue Depth
      query: rabbitmq_queue_messages{queue=~"flash.*"}
      threshold: >5000

    - title: Cache Hit Rate
      query: redis_keyspace_hits / (redis_keyspace_hits + redis_keyspace_misses)
      threshold: <0.7

    - title: Database Connections
      query: mysql_global_status_threads_connected
      threshold: >80

    - title: Error Rate
      query: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
      threshold: >0.01

    - title: Order Processing Rate
      query: rate(orders_processed_total[5m])
      threshold: <10

    - title: Cart Abandonment
      query: rate(cart_abandoned_total[5m]) / rate(cart_created_total[5m])
      threshold: >0.5

Alerting Rules

# alerting-rules.yml
groups:
  - name: flash-sale-alerts
    rules:
      - alert: HighErrorRate
        expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.01
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "High error rate detected"

      - alert: QueueBacklog
        expr: rabbitmq_queue_messages{queue=~"flash.*"} > 5000
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Queue backlog building up"

      - alert: HighLatency
        expr: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 2
        for: 3m
        labels:
          severity: warning
        annotations:
          summary: "P99 latency above 2 seconds"

      - alert: LowCacheHitRate
        expr: redis_keyspace_hits / (redis_keyspace_hits + redis_keyspace_misses) < 0.7
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Cache hit rate below 70%"

Emergency Procedures

#!/bin/bash
# emergency-procedures.sh

case $1 in
    scale_web)
        echo "Emergency: Scaling web nodes to max"
        aws autoscaling set-desired-capacity --auto-scaling-group-name magento-web --desired-capacity 16
        ;;

    enable_maintenance)
        echo "Emergency: Enabling maintenance mode"
        bin/magento maintenance:enable --ip=10.0.0.0/8
        ;;

    flush_cache)
        echo "Emergency: Flushing all caches"
        bin/magento cache:flush
        redis-cli -h redis-cluster FLUSHDB
        ;;

    restart_queue)
        echo "Emergency: Restarting queue consumers"
        pkill -f 'queue:consumers'
        sleep 5
        for queue in flash.sale.orders flash.sale.inventory flash.sale.email; do
            php bin/magento queue:consumers:start $queue --max-messages=1000 &
        done
        ;;

    db_readonly)
        echo "Emergency: Switching to read-only mode"
        mysql -h primary -e "SET GLOBAL read_only = ON;"
        ;;

    rollback)
        echo "Emergency: Rolling back deployment"
        bin/magento setup:rollback --backup/media
        bin/magento cache:flush
        ;;
esac

Post-Sale Analysis

<?php
namespace Vendor\FlashSale\Model\Analytics;

class PostSaleAnalyzer
{
    public function analyze(): array
    {
        return [
            'peak_traffic' => $this->getPeakTraffic(),
            'total_orders' => $this->getTotalOrders(),
            'revenue' => $this->getTotalRevenue(),
            'avg_response_time' => $this->getAvgResponseTime(),
            'cache_hit_rate' => $this->getCacheHitRate(),
            'error_rate' => $this->getErrorRate(),
            'inventory_sold' => $this->getInventorySold(),
            'conversion_rate' => $this->getConversionRate(),
            'top_products' => $this->getTopProducts(),
            'bottlenecks' => $this->identifyBottlenecks(),
            'recommendations' => $this->generateRecommendations(),
        ];
    }
}

Quiz

1. What is the typical traffic multiplier for flash sale peak?

Question 1 options

2. Should flash sale prices be cached?

Question 2 options

3. What is the recommended queue depth alert threshold?

Question 3 options

Flashcards

Question

Flash sale traffic multiplier?

Answer

10-50x normal traffic at peak

Question

Cache strategy for flash sales?

Answer

Aggressive for static, no-cache for prices/inventory

Question

Inventory handling?

Answer

Queue-based reservation with TTL

Question

Queue depth alert threshold?

Answer

>5000 messages indicates consumer backlog

Question

Varnish TTL for flash sale pages?

Answer

24h for product pages, no-cache for cart/checkout

Revision Notes

Key Takeaways

  • 1. Flash sales see 10-50x normal traffic at peak
  • 2. Multi-layer caching: CDN → Varnish → Redis → MySQL
  • 3. Queue-based order processing ensures reliability under load
  • 4. Auto-scaling triggers on CPU, request count, and queue depth
  • 5. Monitor key metrics and have emergency procedures ready

Interview Tips

  • Explain infrastructure sizing for 50x traffic spikes
  • Describe multi-layer caching strategy and TTL decisions
  • Discuss queue architecture for order processing
  • Talk about monitoring, alerting, and emergency procedures

Cheat Sheet

High Traffic Flash Sale:
  Traffic: 10-50x normal
  Scale: Web(16), Varnish(6), Redis(6), DB(3 replicas)

Caching Layers:
  CDN → Static assets (7d)
  Varnish → FPC (24h), Product (1h)
  Redis → Block/Config (1h-forever)
  No-cache → Prices, Cart, Checkout

Order Pipeline:
  Order → Inventory Queue → Reservation
  Order → Payment Queue → Processing
  Order → Email Queue → Confirmation
  Order → Index Queue → Search Update

Scaling Triggers:
  CPU >60% → Scale up
  Requests >1000/s → Scale up
  Queue >5000 → Add consumers
  CPU <30% → Scale down

Monitoring:
  Latency P99 <2s
  Error rate <1%
  Cache hit >70%
  Queue depth <5000