MODRACXKENNETH D'SILVA

← Archive & Insights

Magento 2 on AWS: Cloud Architecture, Migration & Cost Optimization

At 08:03 on a Tuesday in November, a boutique manufacturer of scale model aircraft kits dropped a limited-edition 1/32 scale Supermarine Spitfire Mk. IX. The ensuing traffic exhausted their PHP-FPM pool and took the site down in four minutes.

By Kenneth D'SilvaReading Time: 35 min readCategory: Architecture & Cloud

1. Four Minutes to Failure

At 08:03 on a Tuesday in November, a boutique manufacturer of scale model aircraft kits dropped a limited-edition 1/32 scale Supermarine Spitfire Mk. IX. They had manufactured two thousand units, featuring exclusive photo-etched brass detailing sets, custom resin cockpit components, and Cartograf decals. They had an email list of forty thousand dedicated hobbyists. The mailshot went out at 08:00. By 08:04, their single-server Magento 2 instance had exhausted its PHP-FPM worker pool, spiked to a load average of 84, and began dropping database connections. Customers attempting to pay for £150 kits were greeted with a 502 Bad Gateway. They sold exactly zero Spitfires in the first hour.

This is what happens when you attempt to run a heavily-trafficked event-driven commerce site on a static, monolithic infrastructure. The traditional LAMP stack approach for Magento 2 breaks entirely when you introduce steep vertical traffic spikes. The database becomes an IO bottleneck, the PHP-FPM pool runs out of memory, Redis blocks on cache invalidations, and your static media serving grinds to a halt. The failure is absolute and catastrophic.

Fixing it took a month of migration and architectural restructuring. I moved them from a bare-metal monolith to an AWS architecture built for elasticity. We swapped a static topology for ECS Fargate, Aurora RDS, and a heavily tuned Redis cluster. This article breaks down the exact configurations, the specific AWS limits that tripped us up, and the precise database parameters that make Magento 2 behave under stampeding herd conditions.

You cannot buy your way out of this with instance sizing. I have seen clients upgrade their cPanel instances to 128-core behemoths with a terabyte of RAM and still collapse under the thundering herd. The bottleneck is structural. When fifty thousand HTTP requests hit Magento simultaneously, they queue. When the queue exceeds the `pm.max_children` setting in PHP-FPM, Nginx drops the connections. When the PHP scripts that do execute simultaneously demand complex JOIN operations on the `catalog_product_entity` tables, MySQL deadlocks. More CPU cores only allow it to deadlock faster.

To survive, the architecture must decouple every component. The database must scale IO independently of compute. The caching layer must route read/write operations to distinct data nodes based on lifecycle volatility. The file system must replicate synchronously across availability zones without monopolizing local I/O. Above all, the web tier must clone itself horizontally at a rate that outpaces the incoming traffic gradient.

2. Discarding the Monolith: Why AWS Requires a Complete Rewrite

You cannot simply lift and shift a Magento 2 installation onto an EC2 instance and call it cloud architecture. You are just renting a computer at an exorbitant hourly rate. Proper AWS architecture for Magento demands that every component is stateless, horizontally scalable, and entirely decoupled. The application must not know or care how many siblings it has.

The first step is separating the web server, the application server, the database, the caching layer, the session storage, and the media storage. In a typical cPanel or single-VM setup, these all live on the same filesystem. In AWS, they must be distinct managed services.

For the model kit manufacturer, the target architecture was defined by the requirement to handle rapid scaling from zero baseline to five thousand concurrent users within seconds, without manual intervention. This mandated an ECS (Elastic Container Service) Fargate deployment for the application layer, Aurora MySQL for the database, ElastiCache for Redis, and EFS (Elastic File System) for the persistent media directory.

The operational difference in how you build:

Immutable infrastructure is mandatory. You cannot SSH into a container to run `bin/magento setup:di:compile` or clear a cache. The container image must be built, compiled, and baked entirely in a CI/CD pipeline before it ever touches a production environment. Any manual state modification is a configuration drift that will break on the next auto-scale event. If a developer needs to debug a specific cache state, they pull the logs from CloudWatch; they do not drop into an interactive shell on the production node.

Filesystems are ephemeral. The `/var` and `/pub/static` directories in Magento are notorious for disk IO abuse. In a containerized environment, these directories are blown away when the container dies. You must pre-generate static assets during the build phase and configure the application to run in `production` mode with read-only file systems where possible. Writing temporary data to local storage causes the disk space to fill rapidly on long-running containers, leading to silent failures.

Configuration lives in the environment. Magento's `env.php` file must be generated dynamically at runtime or injected via environment variables sourced from AWS Systems Manager (SSM) Parameter Store or AWS Secrets Manager. Hardcoding credentials in the codebase is unacceptable. The `app:config:import` command should be integrated into the entrypoint script or handled strictly during the CI build process, injecting the variables before the FPM process starts.

Message Queues become the backbone. Asynchronous operations, specifically RabbitMQ, take over all heavy lifting. Email sending, inventory synchronization, order exports to the ERP, and bulk product updates cannot block the web request. They are pushed to an Amazon MQ (RabbitMQ) instance, and a separate pool of consumer containers processes them at a controlled rate, regardless of the traffic on the storefront.

3. ECS Fargate vs EKS: The Orchestration Decision

The choice between ECS and EKS (Elastic Kubernetes Service) often derails projects into endless bikeshedding. For Magento 2, unless you have a dedicated platform engineering team managing a multi-tenant microservices mesh, EKS is overkill. The complexity tax of managing Helm charts, ingress controllers, and node groups distracts from the actual problem: serving PHP requests quickly.

ECS with Fargate removes the need to manage underlying EC2 instances entirely. You define a task definition, set auto-scaling rules based on CPU and memory utilization, and AWS handles the provisioning. For the hobbyist supplier, we deployed two primary services: one for the web/PHP-FPM tier handling customer traffic, and a separate, isolated service for cron jobs and message queue consumers.

Running cron jobs on the same containers serving web traffic is a recipe for sporadic latency spikes. Magento's indexers are notoriously resource-hungry. By isolating background processes into their own ECS service, we ensure that a massive catalog reindex never starves the web tier of CPU cycles. The web service scales horizontally based on Request Count per Target; the cron service operates on a fixed schedule or scales based on the RabbitMQ queue depth.

{
  "family": "magento-web",
  "cpu": "2048",
  "memory": "4096",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "containerDefinitions": [
    {
      "name": "nginx",
      "image": "account.dkr.ecr.region.amazonaws.com/magento-nginx:latest",
      "portMappings": [{"containerPort": 80}],
      "essential": true,
      "dependsOn": [{"containerName": "php-fpm", "condition": "START"}]
    },
    {
      "name": "php-fpm",
      "image": "account.dkr.ecr.region.amazonaws.com/magento-php:latest",
      "essential": true,
      "environmentFiles": [
        {"value": "arn:aws:s3:::config-bucket/magento.env", "type": "s3"}
      ],
      "secrets": [
        {"name": "DB_PASSWORD", "valueFrom": "arn:aws:ssm:region:account:parameter/db_password"}
      ]
    }
  ]
}

The task definition explicitly couples Nginx and PHP-FPM within the same task. They communicate over localhost via TCP (or a shared UNIX socket if a shared memory volume is mounted), eliminating network latency between the web server and the application server. The CPU and memory allocations (2 vCPU, 4GB RAM) are the sweet spot for a Magento 2 node; allocating more leads to diminishing returns and poor utilization, while allocating less risks OOM kills during heavy checkout flows or complex GraphQL queries.

We specifically avoided EC2-backed ECS clusters. The primary reason is auto-scaling speed. Fargate instances launch in roughly 45-60 seconds. An EC2-backed cluster requires scaling the EC2 Auto Scaling Group first, waiting for the instance to boot, register with the cluster, and then schedule the task. That multi-step process can take three to five minutes. During a product drop, three minutes is an eternity of 502s.

4. Aurora RDS Performance Tuning: Surviving the Indexers

Magento 2 treats the database as a hammer, and every request is a nail. The EAV (Entity-Attribute-Value) architecture results in complex, multi-join queries that absolutely shred standard MySQL instances. Aurora MySQL is fundamentally different; it decouples storage from compute and replicates data across three Availability Zones. This makes it highly available, but you still have to tune it for Magento's specific read/write patterns.

Out-of-the-box Aurora is not configured for Magento. The default parameter group will throttle your site under load. The model kit supplier experienced extreme database locking during catalog saves until we adjusted the InnoDB buffer pool, transaction isolation levels, and various specific buffer sizes.

READ-COMMITTED Isolation is Mandatory. By default, MySQL uses `REPEATABLE-READ`. This causes gap locks during massive indexer updates, freezing checkout processes when inventory levels are updated. When an indexer runs, it locks the gap between rows to prevent phantom reads. If a customer tries to place an order that affects stock in that same gap, their transaction hangs until the indexer finishes. You must set `tx_isolation` (or `transaction_isolation` in newer versions) to `READ-COMMITTED` globally. This is a non-negotiable requirement for Magento 2 performance, explicitly documented but frequently ignored. It reduces locking overhead dramatically, allowing reads to proceed even while writes are updating adjacent rows.

Buffer Pool and Instance Sizing. Aurora automatically allocates roughly 75% of instance memory to the InnoDB buffer pool. For Magento, this is usually sufficient, but you must monitor the `BufferCacheHitRatio` metric. If it drops below 99%, your database is reading from disk instead of memory, and latency will spike. Scale the instance class up until the entire working dataset (specifically `catalog_product_entity`, `sales_order`, and their associated EAV tables) fits securely in memory.

Optimizer Search Depth. Magento's EAV model generates queries with an excessive number of JOINs. MySQL's query optimizer struggles to find the optimal execution plan when there are more than seven or eight tables joined. Setting `optimizer_search_depth` to a lower value (e.g., 0 for auto, or explicitly bounding it) prevents the database from spending more time analyzing the query plan than it would take to simply execute a suboptimal one. We hardcode it to prevent CPU spikes during complex filtered category page loads.

Max Allowed Packet and Timeout Configurations. The `max_allowed_packet` size must be increased to at least 128MB. Magento's indexers, particularly the catalog search fulltext indexer, routinely generate massive bulk INSERT statements that exceed the default 4MB limit, causing silent indexer failures. Similarly, `innodb_lock_wait_timeout` should be reduced from the default 50 seconds to something more aggressive, like 15 seconds. If a query locks for 15 seconds, the HTTP request is already ruined; fail fast, kill the query, and let the application retry rather than piling up deadlocked threads.

resource "aws_rds_cluster_parameter_group" "magento_aurora" {
  name        = "magento-aurora-cluster-params"
  family      = "aurora-mysql5.7"
  description = "Magento 2 specific Aurora parameters"

  parameter {
    name  = "transaction_isolation"
    value = "READ-COMMITTED"
    apply_method = "pending-reboot"
  }

  parameter {
    name  = "max_allowed_packet"
    value = "134217728" # 128MB
  }

  parameter {
    name  = "innodb_lock_wait_timeout"
    value = "15"
  }

  parameter {
    name  = "optimizer_search_depth"
    value = "0"
  }

  parameter {
    name  = "query_cache_type"
    value = "0"
  }
}

Query Cache is Dead. Do not attempt to rely on the MySQL query cache. Aurora disables it by default in newer versions, but if you are migrating from an older setup, ensure it is explicitly set to `0`. It becomes a bottleneck due to invalidation contention. Magento relies on Redis for object caching; the database should focus purely on rapid raw data retrieval. A query cache hit rate on Magento is universally abysmal because the data is highly volatile.

Read Replicas and Split Routing. Aurora makes provisioning read replicas trivial. Magento 2 Enterprise (Adobe Commerce) supports split database configurations out of the box, allowing you to route checkout/master writes to the primary cluster endpoint, and catalog reads to the reader endpoint. If you are on Magento 2 Open Source, you must rely on third-party modules or proxy layers (like ProxySQL) to achieve this split. For the model kit company, running Open Source, we implemented a lightweight proxy to route read-only HTTP GET requests to the Aurora reader endpoint, reducing load on the primary writer during product drops by 60%.

5. ElastiCache Clustering: The Redis Triad

Magento 2 demands Redis. It uses it for three distinct purposes: session storage, object caching, and full page caching (FPC). A common, fatal mistake is dumping all three into a single Redis instance. This guarantees failure under load.

When the model kit supplier launched their Spitfire kit, thousands of users hit the site simultaneously. The FPC Redis instance was overwhelmed with invalidation requests as stock levels dropped, causing it to block the single-threaded Redis process. Because sessions were stored on the exact same instance, existing users had their sessions locked. The Redis thread was busy processing massive `DEL` commands for cache tags, meaning requests for session data timed out. This resulted in abrupt logouts, empty shopping carts, and a completely ruined customer experience.

You must provision three separate ElastiCache Redis clusters (or logical databases on sufficiently isolated nodes). They have entirely different eviction policies, access patterns, and persistence requirements.

Redis RoleEviction PolicyPersistenceNode Type
SessionsnoevictionEnabled (AOF or Multi-AZ)Memory optimized
Object Cachevolatile-lruDisabledCompute optimized
FPC (Varnish preferred)allkeys-lruDisabledCompute optimized

Session Cache: The Non-Eviction Rule. For sessions, `maxmemory-policy noeviction` is critical. If memory fills up, the server should reject new writes rather than silently dropping a user's active checkout session to make room. If you use an LRU eviction policy on sessions, a traffic spike will cause older sessions to be purged. A customer browsing for thirty minutes suddenly loses their cart. We deploy the Session ElastiCache cluster across multiple Availability Zones with automatic failover enabled. Session loss translates directly to lost revenue.

Object Cache: Volatile LRU. The object cache stores the compiled configuration, layout block HTML, and EAV attributes. It is highly volatile. We use `volatile-lru` here, ensuring that only keys with an expiration set are evicted when memory pressure hits. Furthermore, configure `L2` caching in Magento's `env.php` using the `id_prefix` to prevent collisions if you share this instance with other environments, though sharing is strongly discouraged.

Compression and Connection Pooling. You must use the `predis` or `phpredis` extension properly in `env.php`. Enable persistent connections (`persistent: 1`) to reduce TCP handshake overhead. The connection latency to ElastiCache must be under a millisecond; ensure the Redis nodes are deployed in the same private subnets as the ECS Fargate tasks. Additionally, enable compression (`compress_data: 1`) for the object cache. Magento's layout blocks are massive strings of HTML; compressing them before shipping them to Redis reduces network bandwidth and memory consumption drastically.

'cache' => [
    'frontend' => [
        'default' => [
            'id_prefix' => 'abc_',
            'backend' => 'Cm_Cache_Backend_Redis',
            'backend_options' => [
                'server' => 'magento-obj-cache.xxxxxx.0001.euw2.cache.amazonaws.com',
                'port' => '6379',
                'persistent' => '1',
                'database' => '0',
                'password' => '',
                'force_standalone' => '0',
                'connect_retries' => '1',
                'read_timeout' => '10',
                'automatic_cleaning_factor' => '0',
                'compress_data' => '1',
                'compress_tags' => '1',
                'compress_threshold' => '20480',
                'compression_lib' => 'gzip',
            ],
        ],
    ],
],

L2 Caching for Redis. Magento 2 introduced an L2 cache feature that is frequently overlooked. By utilizing an in-memory L1 cache (like APCu on the local PHP container) backed by the L2 Redis cache, you can eliminate thousands of network round-trips for highly static configuration data. We enable APCu on the Fargate containers specifically to cache the global config tree, falling back to ElastiCache only when the local cache is empty.

6. The EFS Performance Trap

If there is a single component in AWS that consistently ruins Magento architectures, it is the Elastic File System (EFS). Magento requires a shared filesystem for the `pub/media` directory so that product images uploaded via the admin panel are visible to all web nodes.

EFS provides this, but it is a network filesystem. Its performance characteristics are vastly different from a local SSD. Out of the box, EFS operates in Bursting Throughput mode. You earn burst credits based on the size of your filesystem. A typical Magento `pub/media` directory is perhaps 20GB. This earns very few burst credits.

During the Spitfire launch, the sudden surge in image requests exhausted the EFS burst credits in ten minutes. Throughput plummeted to 1 MiB/s. Images stopped loading, and PHP-FPM processes hung indefinitely waiting for file stat operations, taking down the web tier. The file stat operations block the entire FPM worker thread, leading to a cascade failure where healthy containers are marked unhealthy by the load balancer because they cannot respond to health checks.

The fix is absolute: Provisioned Throughput or Elastic Throughput. You must configure EFS to use Provisioned Throughput mode, explicitly defining the required MiB/s, or switch to Elastic Throughput mode (which scales dynamically but costs more per read/write). Never rely on Bursting mode for a production commerce site. For the model kit company, we established a baseline of 100 MiB/s Provisioned Throughput.

resource "aws_efs_file_system" "magento_media" {
  creation_token = "magento-media-efs"
  performance_mode = "generalPurpose"
  throughput_mode  = "provisioned"
  provisioned_throughput_in_mibps = 100

  lifecycle_policy {
    transition_to_ia = "AFTER_30_DAYS"
  }
}

Additionally, mount the EFS volume with the correct NFS options in your ECS task definition. You must use `nfsvers=4.1`, `rsize=1048576`, `wsize=1048576`, `hard`, `timeo=600`, `retrans=2`, and `noresvport`. Failing to optimize these mount options results in crippling latency on every image read. Furthermore, implement an aggressively caching CDN in front of these images so that EFS is only touched for the origin fetch. If your CDN hit rate for images is below 99%, you are abusing your EFS mount unnecessarily.

7. CDN Edge Optimization: Fastly and Varnish

The fastest request is the one that never reaches your servers. While Magento supports Redis for Full Page Caching, running Varnish (or a Varnish-based CDN like Fastly) at the edge is the only way to survive a massive traffic event. Relying on PHP and Redis to serve full HTML pages means bootstrapping the framework on every hit, which is computationally expensive.

For the model kit manufacturer, we implemented Fastly. The key to successful Fastly integration with Magento is aggressive cache tagging and synthetic responses.

When a user visits a product page, Fastly caches the HTML and associates it with cache tags provided by Magento (e.g., `cat_p_1234`). When the stock level changes, Magento issues a PURGE request with the specific cache tag for that product. Fastly invalidates only that page, leaving the rest of the catalog cached.

However, dynamic content—like the customer's cart count or personalized greeting—cannot be cached globally. Magento handles this using ESI (Edge Side Includes) or AJAX requests. ESI instructs Fastly to stitch together a cached generic page with a dynamic, uncacheable block fetched directly from the origin. AJAX is often preferred as it allows the main page to load instantly from the CDN, populating the dynamic elements a second later via the `customer/section/load` endpoint.

The VCL (Varnish Configuration Language) must explicitly strip cookies for static assets and catalog pages, otherwise Varnish will bypass the cache entirely. If your hit rate is below 90%, your VCL is wrong.

sub vcl_recv {
  # Bypass cache for checkout and admin
  if (req.url ~ "^/(checkout|admin|customer|rest)/") {
    return (pass);
  }

  # Strip tracking cookies before checking cache
  if (req.http.cookie) {
    set req.http.cookie = regsuball(req.http.cookie, "(^|;\s*)(_ga|__utm[a-z]+)=[^;]*", "");
    # If no other cookies exist, unset the header entirely
    if (req.http.cookie ~ "^\s*$") {
      unset req.http.cookie;
    }
  }

  # Normalize Accept-Encoding for better hit rates
  if (req.http.Accept-Encoding) {
    if (req.http.Accept-Encoding ~ "gzip") {
      set req.http.Accept-Encoding = "gzip";
    } elsif (req.http.Accept-Encoding ~ "deflate") {
      set req.http.Accept-Encoding = "deflate";
    } else {
      unset req.http.Accept-Encoding;
    }
  }
}

We also implemented shielding. Shielding designates a specific Fastly POP as the "shield" node in front of your AWS origin. If a piece of content is not cached at the local edge node, it checks the shield node. Only if the shield node misses does the request go to AWS. This drastically reduces origin fetch load, particularly during global product drops where traffic originates from multiple continents simultaneously.

8. Scaling Metrics and Autoscaling Policies

Autoscaling based on CPU utilization is a lagging indicator for Magento. By the time CPU usage spikes across the cluster, requests are already queuing, and the user experience is degrading. You need a leading indicator.

The most effective scaling metric for the web tier is the Application Load Balancer (ALB) `RequestCountPerTarget`. This metric tracks the exact number of requests hitting each container. If you know that a single PHP-FPM container can handle 50 requests per minute before latency increases, you set your target tracking policy to maintain that threshold.

When the mailshot goes out, the request count spikes instantly. Target tracking immediately provisions new ECS tasks to distribute the load, maintaining the 50 requests/minute/target ratio. The scale-in policy must be conservative; scale out rapidly, scale in slowly. Terminating instances prematurely during brief traffic lulls causes thrashing.

We combine this with step scaling based on queue depth for the RabbitMQ consumers. If the queue of order confirmation emails exceeds 1,000, we scale the consumer service up by five tasks. This ensures that background processing never falls behind, even when the web tier is overwhelmed.

9. The Structural Reality of Cost Optimization

Cloud architecture is not inherently cheaper than bare metal. It is often significantly more expensive, particularly when idle. The goal is elasticity: paying for the capacity only when the traffic demands it.

Cost optimization in this environment requires ruthlessness. The EFS volume transitions files untouched for 30 days to the Infrequent Access (IA) storage class, cutting storage costs by 80%. Non-production environments—staging, UAT, integration—are spun down completely outside of business hours using EventBridge schedules and Lambda functions adjusting the ECS desired count to zero.

Aurora Serverless v2 is an option for fluctuating workloads, but for high-traffic commerce, the unpredictable scaling latency and the high cost per ACU (Aurora Capacity Unit) often make provisioned instances with reserved pricing a more financially sound choice. We opted for provisioned Aurora clusters backed by 1-year Compute Savings Plans, covering the baseline usage while allowing ECS Fargate to handle the burst capacity via spot instances for background tasks.

The model kit supplier now pays more in baseline infrastructure costs than they did for their single server. But when they release the next limited-edition kit, the site remains online. They process the orders, capture the revenue, and the infrastructure scales back down gracefully. The architecture is no longer a liability; it is the engine of their revenue.

10. OpenSearch Integration: The Catalog Backbone

Magento 2 entirely removed MySQL as a search engine option, relying exclusively on Elasticsearch or OpenSearch. Running OpenSearch on your own EC2 instances is a maintenance nightmare of JVM tuning, shard balancing, and index corruption. We utilized AWS OpenSearch Service.

The architecture mistake most teams make is undersizing the OpenSearch domain. Magento pushes immense amounts of data to OpenSearch during reindexes. If the domain is undersized, the CPU pegs at 100%, and the reindex fails silently, leaving the catalog out of sync. We deployed a multi-AZ cluster of `m6g.large.search` instances. The Gravity-based instances (Graviton2) offer significantly better price-performance for Java-based workloads like OpenSearch.

Crucially, we separated the indexing alias from the search alias. During a full reindex, Magento builds a completely new index in the background and only swaps the alias once complete. If OpenSearch goes down, product listings fail entirely. It is a critical path dependency, and monitoring the `ClusterStatus` (Yellow or Red) and `JVMMemoryPressure` is mandatory. An alert triggers if JVM pressure exceeds 85%, allowing us to vertically scale the domain before a crash occurs.

11. CI/CD and Zero-Downtime Deployments

In a monolithic setup, deployments involve pulling code, running `setup:upgrade`, and clearing the cache while the site is in maintenance mode. This results in ten minutes of downtime per deployment. In AWS ECS, zero-downtime deployments are structural.

We implemented a blue/green deployment strategy using AWS CodeDeploy. The CI pipeline (GitHub Actions) runs the Magento compilation process (`setup:di:compile`, `setup:static-content:deploy`) inside a builder container. It produces a finalized, immutable Docker image holding the compiled application. This image is pushed to ECR.

CodeDeploy spins up a replacement set of ECS tasks (the green environment). It registers them with a secondary target group on the ALB and runs health checks. Once the new containers are confirmed healthy and serving traffic, CodeDeploy reroutes 100% of the live traffic to the green target group. The old containers (the blue environment) are left running for five minutes to drain existing connections before being terminated. The customer never sees a maintenance page. They do not experience downtime. The deployment is invisible.

12. Frequently Asked Questions

Why not use EC2 Auto Scaling instead of Fargate?

EC2 Auto Scaling requires managing the underlying AMI, patching the OS, and handling the delay of instance boot times. When a massive spike hits, waiting three minutes for an EC2 instance to boot, join the cluster, and pull the Docker image is too slow. Fargate abstracts the host management and provisions containers rapidly, aligning perfectly with the volatile traffic patterns of event-driven commerce.

How do you handle Magento's cron jobs in a clustered environment?

Magento cron jobs cannot run on every web node simultaneously, or you will trigger massive database deadlocks and duplicate processing. We isolate cron processing to a single dedicated Fargate task running outside the auto-scaling group. Alternatively, we use EventBridge to trigger specific Fargate tasks for individual cron groups, ensuring absolute separation of concerns.

Does splitting the Redis instances actually improve performance?

Immensely. Redis is single-threaded. When you combine sessions, object cache, and FPC, a massive cache invalidation (like a stock update purging thousands of FPC tags) blocks the single thread. During that blockage, any request trying to read a user session times out. Splitting them into three instances ensures that cache volatility never impacts session stability or object retrieval latency.

Why avoid Aurora Serverless v2 for Magento?

While Serverless v2 scales much faster than v1, the cost per ACU is significantly higher than provisioned capacity. Magento's baseline database load is relatively high due to continuous background indexing and cron jobs. The constant scaling up and down of ACUs often results in a monthly bill that eclipses a correctly sized provisioned Aurora cluster covered by Reserved Instances. We reserve Serverless v2 for highly unpredictable, lower-baseline workloads.

How do you handle media files without EFS?

If EFS is entirely unacceptable due to cost or specific latency requirements, the alternative is an S3-backed media architecture. This requires a Magento module (like the popular AWS S3 module) that overrides the core file system adapters to push media directly to an S3 bucket, which is then served via CloudFront. This removes the need for a shared network filesystem entirely, but introduces complexity in module compatibility and local development environments.

What happens when the RabbitMQ queue backs up?

If RabbitMQ queue depth spikes, it usually indicates a failure in a downstream system (e.g., an ERP API rejecting orders) or a stalled consumer. We rely on CloudWatch alarms tied to the `QueueDepth` metric. If the depth exceeds a threshold, an alert pages the on-call engineer, and target tracking auto-scales the consumer ECS service to burn down the backlog. If the backlog is due to a persistent error, messages are routed to a Dead Letter Queue (DLQ) for manual review.


End of Transmission