Multi-Database Separation: Isolating Cache, Session and FPC
AI generated
SET
TTL
Redis · Magento · Performance · Caching
Multi-Database Separation: Isolating Cache, Session and FPC
combining database indexes, prefixes and eviction policy correctly

A single Redis instance for cache, session and full page cache without clean database separation is one of the most underrated sources of operational risk in Magento setups. This article explains why dedicated database indexes per role prevent key collisions, when separate Redis instances make sense, and how eviction policy can be configured differently depending on the role.

14 min read database index · eviction policy · key prefixes Redis 7.x · Magento 2.4.8 · PHP 8.4

1. Why one shared Redis instance for everything is problematic

It is technically possible to place cache, session and full page cache in Magento on the same Redis database index. The shop starts, pages load, and at first glance everything appears to work. The problem only shows up under load or during operational interventions: without database separation, all three roles share the same key space, which creates several subtle but dangerous risks.

The most obvious risk is an accidental FLUSHDB that was only meant to clear the configuration cache but simultaneously deletes every active customer session because they live in the same index. A less obvious risk is shared eviction: when Redis hits its maxmemory limit, the configured policy decides which keys get removed, without regard to whether it is an unimportant cache entry or an active session. Without database separation this distinction is impossible.

The third aspect concerns monitoring and capacity planning: without separate databases it is no longer possible to determine how much memory is actually used by cache, how much by sessions, and how much by the full page cache. Yet this visibility is a prerequisite for well founded decisions on memory planning and scaling, which this article covers further below.

2. Redis database indexes: the SELECT concept

By default Redis supports 16 logical databases within a single instance, numbered 0 through 15, configurable via databases in redis.conf. Every logical database is a fully separate key space, reachable via the SELECT command or, in redis-cli, via the -n option. Important to understand: this database separation is purely logical, all databases share the same memory, the same process and the same instance wide maxmemory limit.

That means separating by database index fully solves the collision problem, but not the resource isolation problem. If the cache grows under load and hits the global maxmemory limit, that can, depending on the configured maxmemory-policy, theoretically also affect session data in a different database. This distinction between logical database separation and physical resource separation is central to deciding whether one or several Redis instances are needed, covered in more depth in section 6.

3. env.php: separate database values for cache, session and FPC

Practical implementation of database separation in Magento happens through three independent database parameters in app/etc/env.php: one for the regular cache under cache.frontend.default.backend_options.database, one for the full page cache under cache.frontend.page_cache.backend_options.database, and one for sessions under session.redis.database. The common convention is to use index 0 for the general cache, index 1 for the full page cache, and index 2 for sessions.

This configuration costs no additional latency, because all indexes are reachable through the same TCP connection and the same Redis process. The effort for database separation is therefore limited to three extra lines in env.php, yet brings substantial operational safety compared to the single database approach.


<?php
// app/etc/env.php - explicit database separation for cache, page cache and session
return [
    'cache' => [
        'frontend' => [
            'default' => [
                'backend' => 'Cm_Cache_Backend_Redis',
                'backend_options' => [
                    'server' => '127.0.0.1',
                    'port' => '6379',
                    'database' => '0', // General config/layout/block_html cache
                ],
            ],
            'page_cache' => [
                'backend' => 'Cm_Cache_Backend_Redis',
                'backend_options' => [
                    'server' => '127.0.0.1',
                    'port' => '6379',
                    'database' => '1', // Full page cache, separated from general cache
                ],
            ],
        ],
    ],
    'session' => [
        'save' => 'redis',
        'redis' => [
            'host' => '127.0.0.1',
            'port' => '6379',
            'database' => '2', // Sessions, isolated from both cache roles
        ],
    ],
];

4. Avoiding key collisions: prefixes and namespaces

Even with clean database separation at the index level, it is worth taking a closer look at key prefixes, especially when multiple Magento installations share the same Redis instance, for example in multi tenant or staging environments. Magento itself already uses internal prefixes such as zc:k: for cache entries, but with several independent Magento installations on the same database index, these prefixes still collide, because both installations can generate the same cache keys for similar entities.

The robust solution is either complete database separation per installation, meaning dedicated indexes 3, 4, 5 and so on for a second installation, or fully separate Redis instances when there are many tenants. An additional id_prefix parameter in backend_options can serve as a further safeguard, but it does not replace the fundamental separation by role and tenant.


<?php
// app/etc/env.php - additional id_prefix safeguard for a second tenant
// sharing the same Redis instance and database index range
'cache' => [
    'frontend' => [
        'default' => [
            'backend' => 'Cm_Cache_Backend_Redis',
            'backend_options' => [
                'server' => '127.0.0.1',
                'port' => '6379',
                'database' => '3', // Dedicated index for the second Magento installation
                'id_prefix' => 'tenant2_', // Extra namespace safeguard
            ],
        ],
    ],
],

5. Eviction policy per role explained

When Redis reaches its maxmemory limit, it automatically removes keys according to the configured maxmemory-policy. For cache data, allkeys-lru is usually the right choice: Redis removes the least recently used keys, regardless of whether an explicit TTL is set, which is unproblematic for cache data because it can be recomputed at any time.

For session data this policy is riskier: if an active session gets removed by LRU while it is being used, the customer loses their cart in the middle of checkout. It is therefore advisable to run session data with a sufficiently generous maxmemory limit so eviction practically never triggers there during normal operation, combined with volatile-lru, which only removes keys that have a TTL set, preventing accidental removal of persistent data.

These differing requirements are a strong argument for physically separate Redis instances in larger installations: only that way can different maxmemory-policy values actually be configured independently per role, because maxmemory-policy is an instance wide setting and cannot be set per database index.

In practice it pays off to regularly watch the evicted_keys value from redis-cli INFO stats per instance. If this value rises on a shared instance, without database separation it is no longer possible to determine whether cache or session keys were affected, which needlessly complicates troubleshooting.


# Check current eviction policy of the running Redis instance
redis-cli CONFIG GET maxmemory-policy

# Recommended policy for a cache-only instance
redis-cli CONFIG SET maxmemory-policy allkeys-lru

# Recommended policy for a session-only instance (never evict without TTL)
redis-cli CONFIG SET maxmemory-policy volatile-lru

# Check memory usage broken down per logical database
redis-cli INFO keyspace

# Verify maxmemory-policy is a global instance setting, not per database
redis-cli CONFIG GET maxmemory

# Count evicted keys since last restart, per instance
redis-cli INFO stats | grep evicted_keys

6. When separate Redis instances make sense instead of just database indexes

For small to medium Magento shops, logical database separation via indexes is usually completely sufficient. Beyond a certain traffic volume or with particularly memory intensive catalogs, though, moving to physically separate Redis instances, typically on different ports or even different hosts, pays off. The main reason is resource isolation: a cache spike triggered by a large category change can then no longer affect the maxmemory limit of the session instance.

Another reason for separate instances is differing scaling behavior: session data grows roughly proportional to concurrent traffic, while cache data grows more proportional to catalog size. Separate instances allow each role to scale independently, for example sizing the session server more generously during a traffic spike without touching the cache server.

7. Persistence strategies per role: RDB and AOF

Cache data does not need to survive a Redis restart, since it can be rebuilt at any time from the database or by re-rendering. For a pure cache instance, persistence can therefore be disabled entirely (save "" in redis.conf), which reduces write load and makes the instance faster.

Session data, on the other hand, should ideally survive a restart, otherwise every Redis restart logs out all logged in customers and empties all carts. For the session instance, AOF (appendonly yes) with appendfsync everysec is therefore the sensible choice, a good compromise between data safety and write performance. These differing persistence requirements are another strong argument for database separation at the instance level, because persistence settings also apply instance wide.


# redis.conf snippet for a pure cache instance - persistence disabled
save ""
appendonly no

# redis.conf snippet for a session instance - durable but fast
appendonly yes
appendfsync everysec

8. redis-cli: switching and checking databases

For practical verification of database separation, SELECT switches between indexes within a redis-cli session, while the -n command line option selects a database directly at startup. redis-cli -n 0 DBSIZE, redis-cli -n 1 DBSIZE and redis-cli -n 2 DBSIZE give an overview within seconds of how the key count is distributed across cache, full page cache and sessions, and immediately reveal if a role mistakenly uses the same index as another.


# Compare key counts across the three role-specific databases
redis-cli -n 0 DBSIZE
redis-cli -n 1 DBSIZE
redis-cli -n 2 DBSIZE

# Switch database inside an interactive redis-cli session
redis-cli
> SELECT 2
> DBSIZE

redis-cli INFO keyspace shows every active database with its respective key count and the number of keys with an expiry set, in a single command. If an expected database is completely missing from this output, it points to the corresponding env.php configuration not taking effect as intended.

9. One index versus separate indexes versus separate instances

The table below summarizes the three common architecture variants and ranks them by safety and effort.

Architecture Key collisions Resource isolation Operational effort
One shared index High, very risky None Minimal, but not recommended
Separate database indexes None Logical only, shared RAM Low, three lines in env.php
Separate Redis instances None Complete, independent maxmemory Higher, several processes to manage
Separate instances with replication None Complete plus failover resilience Highest, maintaining replication and failover

For most Magento shops, separate database indexes are the right starting point, because they fully eliminate the collision risk and require minimal extra effort. Only once resource pressure is demonstrable, or eviction and persistence requirements truly differ, does the step to separate instances pay off, together with the added operational effort of managing multiple Redis processes.

10. Summary

Clean database separation between cache, session and full page cache is not a cosmetic configuration detail, it is a fundamental safeguard against key collisions and risky eviction effects. Three separate database values in env.php are enough for most installations to completely eliminate the biggest risk: accidental data loss from shared key spaces.

For larger installations with differing eviction policy and persistence requirements between cache and session, the additional step to physically separate Redis instances makes sense. Database separation at the index level remains the baseline requirement regardless of whether one or several Redis instances end up in use.

Redis Database Separation for Magento - The Essentials at a Glance

Three separate indexes

Assign cache, full page cache and session each their own database value in env.php.

Check eviction policy

allkeys-lru for cache, volatile-lru for session, ideally configured separately per instance.

Differentiate persistence

Cache without persistence, session with AOF, to avoid logging customers out on every restart.

Separate instances under scaling pressure

Only physically separate instances allow truly independent maxmemory limits and policies.

11. FAQ: Multi-Database Separation in Redis for Magento

1One shared index not enough?
Cache and session share the key space. FLUSHDB or eviction can accidentally hit active sessions.
2How many databases does Redis offer?
16 databases (0-15), configurable via databases in redis.conf, all sharing the same memory.
3Do multiple indexes cost latency?
No, all indexes run through the same connection and process, no measurable overhead.
4Fitting policy for cache data?
allkeys-lru, because cache data can be recomputed at any time.
5Fitting policy for session data?
volatile-lru with a generous maxmemory limit, so eviction practically never triggers in normal operation.
6When separate instances?
When eviction or persistence requirements differ, since these settings apply instance wide.
7Enable persistence for cache instance?
Usually not, cache rebuilds without issue. save "" disables persistence.
8Why persistence for session?
Without persistence, customers get logged out on every restart. AOF with everysec is a good compromise.
9Verify separation?
redis-cli -n X DBSIZE per index or redis-cli INFO keyspace for the full overview.
10Multiple installations on one instance?
Only with dedicated index blocks per installation, plus id_prefix as an extra safeguard.