Magento performance optimalisatie: een praktische gids
Bij high-traffic Magento shops is performance geen feature maar een vereiste. Een 100ms vertraging kost 1% conversie. In dit artikel behandelen we production-grade optimalisaties: Varnish VCL configuratie voor Magento-specifieke edge cases, Redis architectuur voor session clustering, MySQL query profiling en indexing strategieën. Gebaseerd op ervaring met shops die 10.000+ concurrent users verwerken.
Varnish VCL: beyond de basis configuratie
Magento's standaard VCL mist cruciale optimalisaties. Custom VCL voor grace mode, saint mode en intelligente cache warming maakt het verschil tussen een stabiele en een falende Black Friday:
vcl 4.1;
import std;
import directors;
backend default {
.host = "127.0.0.1";
.port = "8080";
.probe = {
.url = "/health_check.php";
.timeout = 2s;
.interval = 5s;
.window = 5;
.threshold = 3;
}
.first_byte_timeout = 300s;
.connect_timeout = 5s;
.between_bytes_timeout = 2s;
}
sub vcl_recv {
set req.grace = 6h;
set req.url = std.querysort(req.url);
if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|gclid|fbclid)=") {
set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|gclid|fbclid)=[^&]+", "");
set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|gclid|fbclid)=[^&]+&?", "?");
set req.url = regsub(req.url, "\?$", "");
}
if (req.method == "POST" && req.url ~ "/graphql") {
if (req.http.X-GraphQL-Operation ~ "mutation") {
return (pass);
}
}
}
sub vcl_backend_response {
if (beresp.http.X-Magento-Tags) {
set beresp.do_esi = true;
}
if (beresp.status >= 500 && beresp.status < 600) {
set beresp.saintmode = 30s;
if (req.method != "POST") {
return (retry);
}
}
if (bereq.url ~ "\.(css|js|jpg|jpeg|png|gif|ico|woff2?)$") {
set beresp.ttl = 365d;
unset beresp.http.Set-Cookie;
}
}Grace mode is essentieel: bij backend overload serveert Varnish cached content tot 6 uur oud. Dit voorkomt cascade failures tijdens traffic spikes. Saint mode markeert backends tijdelijk als unhealthy bij 5xx errors.
Redis: session clustering en cache segmentatie
Een enkele Redis instance is een single point of failure én een bottleneck. Optimale setup: gescheiden instances voor sessions, cache en FPC met correcte eviction policies:
'session' => [
'save' => 'redis',
'redis' => [
'host' => 'redis-session.internal',
'port' => '6379',
'timeout' => '2.5',
'persistent_identifier' => 'sess',
'database' => '0',
'compression_threshold' => '2048',
'compression_library' => 'lz4',
'max_concurrency' => '20',
'break_after_frontend' => '5',
'break_after_adminhtml' => '30',
'first_lifetime' => '600',
'bot_first_lifetime' => '60',
'bot_lifetime' => '7200',
'disable_locking' => '1',
'min_lifetime' => '60',
'max_lifetime' => '2592000',
'sentinel_master' => 'mymaster',
'sentinel_servers' => 'sentinel1:26379,sentinel2:26379,sentinel3:26379',
]
],
'cache' => [
'frontend' => [
'default' => [
'backend' => 'Magento\Framework\Cache\Backend\Redis',
'backend_options' => [
'server' => 'redis-cache.internal',
'port' => '6379',
'database' => '0',
'compress_data' => '1',
'compression_lib' => 'lz4',
'preload_keys' => [
'EAV_ENTITY_TYPES',
'GLOBAL_PLUGIN_LIST',
'DB_IS_UP_TO_DATE',
'SYSTEM_DEFAULT'
]
]
],
'page_cache' => [
'backend' => 'Magento\Framework\Cache\Backend\Redis',
'backend_options' => [
'server' => 'redis-fpc.internal',
'port' => '6379',
'database' => '0',
'compress_data' => '0'
]
]
]
]Critische insight: disable_locking op sessions voorkomt lock contention die bij hoge concurrency tot timeouts leidt. De preload_keys optie warmt de meest gebruikte cache entries direct na flush.
MySQL query profiling en index optimalisatie
Magento's EAV model genereert complexe queries. Zonder proper indexing degradeert performance exponentieel met catalogus grootte. Systematische profiling identificeert bottlenecks:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 0.5;
SET GLOBAL log_queries_not_using_indexes = 'ON';
SELECT
ea.attribute_code,
ea.backend_type,
COUNT(*) as usage_count
FROM catalog_product_entity_varchar cpev
JOIN eav_attribute ea ON cpev.attribute_id = ea.attribute_id
WHERE ea.entity_type_id = 4
GROUP BY ea.attribute_id
HAVING usage_count > 1000
ORDER BY usage_count DESC;
ALTER TABLE catalog_product_index_price
ADD INDEX idx_website_customer_price (website_id, customer_group_id, min_price);
ALTER TABLE catalog_product_entity
ADD INDEX idx_listing_cover (type_id, attribute_set_id, entity_id, sku, created_at);Real-world tip: de catalog_product_flat tabel escaleert niet bij 100k+ producten. Disable flat tables en optimaliseer EAV queries met proper covering indexes.
Async operations en queue processing
Synchrone operations tijdens checkout zijn conversion killers. Verplaats alles wat niet direct nodig is naar async queues:
namespace Ten50\Module\Model\Queue;
use Magento\Framework\MessageQueue\PublisherInterface;
use Magento\Sales\Api\Data\OrderInterface;
class OrderPostProcessor
{
private const TOPIC_INVENTORY = 'inventory.reservations.update';
private const TOPIC_INDEX = 'product.index.update';
public function __construct(
private PublisherInterface $publisher
) {}
public function afterPlace(OrderInterface $order): void
{
$this->publisher->publish(
self::TOPIC_INVENTORY,
json_encode([
'order_id' => $order->getEntityId(),
'items' => $this->extractSkuQty($order)
])
);
$productIds = array_column($order->getAllItems(), 'product_id');
$this->publisher->publish(
self::TOPIC_INDEX,
json_encode(['product_ids' => array_unique($productIds)])
);
}
}Run consumers via supervisor met auto-restart. Benchmark: checkout tijd reduceerde van 3.2s naar 0.8s door inventory updates en email verzending naar async te verplaatsen.
Performance audit nodig?
Wij analyseren uw Magento stack van Varnish tot MySQL en implementeren gerichte optimalisaties met meetbare resultaten.
Neem contact op