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?
2. Should flash sale prices be cached?
3. What is the recommended queue depth alert threshold?
Flashcards
Question
Flash sale traffic multiplier?
Click to reveal answer
Answer
10-50x normal traffic at peak
Question
Cache strategy for flash sales?
Click to reveal answer
Answer
Aggressive for static, no-cache for prices/inventory
Question
Inventory handling?
Click to reveal answer
Answer
Queue-based reservation with TTL
Question
Queue depth alert threshold?
Click to reveal answer
Answer
>5000 messages indicates consumer backlog
Question
Varnish TTL for flash sale pages?
Click to reveal answer
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