Architecting Moodle's Universal Cache (MUC) for Scalability
Learn how to architect Moodle's Universal Cache (MUC) to prevent database bottlenecks, avoid data inconsistency in multi-node clusters, and secure your cache boundaries.
10 May 2026, 18:49 UTC

The Problem: Performance Degradation and Data Inconsistency
Moodle is an intensive application that performs frequent database queries for course structures, user permissions, and plugin configurations. Without an effective caching strategy, the database becomes a bottleneck, leading to high latency and server timeouts. However, implementing a cache introduces the risk of "stale data"—where a user sees an old version of a course or a revoked permission—and architectural complexity when moving from a single server to a cluster.
The takeaway: Moodle's Universal Cache (MUC) abstracts the storage backend from the application logic. To maintain performance without sacrificing consistency, you must align your cache store (Filesystem, Redis, or Memcached) with your deployment topology.
Requirements for a Stable Cache Architecture
- Disposable Data: The cache must be treated as non-authoritative. Any data stored must be reconstructible from the database.
- Invalidation Reliability: When a course setting changes, the corresponding cache entry must be purged across all nodes.
- Low Latency: The cache store must respond faster than a database query, typically in the sub-millisecond range.
- Isolation: Sensitive user data must be separated from shared application data to prevent accidental leakage across sessions.
The Smallest Suitable Design: Single-Node Deployment
For a single-server installation, the simplest design uses the default MUC configuration. This requires no additional infrastructure and minimizes moving parts.
- Request Cache: Handled by PHP static variables. This exists only for the duration of a single page load.
- Session Cache: Stored in the PHP session handler or a local file.
- Application Cache: Stored in the
moodledata/mucdirectory on the local filesystem.
In this design, the filesystem is the source of truth for cached objects. This is sufficient for low-to-medium traffic sites where the disk I/O (preferably on SSD) can handle the read/write volume of the cache.
Trust and Data Boundaries
MUC stores are often unauthenticated by default. If you move beyond the filesystem to a network-based store like Redis or Memcached, the trust boundary shifts from the local OS to the network layer.
| Store Type | Trust Boundary | Risk | Mitigation |
|---|---|---|---|
| Filesystem | OS User Permissions | Local root access | Restrict moodledata permissions |
| Redis/Memcached | Network Interface | Unauthorized network access | Bind to 127.0.0.1 or use a private VPC |
Warning: Never expose a MUC network store to the public internet. Cached content can include session fragments or internal system paths that could be exploited if intercepted.
Operational Checks and Verification
To verify that MUC is functioning as intended, you can use a local plugin to test the lifecycle of a cached item. Run these checks on a development instance before deploying to production.
Verification Workflow
- Define a Cache: Create a custom cache definition in a local plugin's
db/caches.php. - Store and Retrieve: Use the MUC API to write a value and read it back.
- Purge Test: Run the purge command from the CLI (requires admin permissions):
php admin/cli/purge_all_caches.php - Confirm Invalidation: Attempt to retrieve the value again; it should return
nullor trigger a database reload.
Failure Modes and Design Shifts
The design must evolve when the environment changes. A filesystem cache that works on one server will fail in a load-balanced environment.
The Split-Brain Scenario
If you deploy Moodle across two web nodes using the default filesystem cache, each node maintains its own moodledata/muc. If Node A updates a course setting, Node B will continue to serve the old cached value until its local cache expires. This creates an inconsistent user experience.
When to Change the Design
- Multi-Node Hosting: Shift to a shared Redis or Memcached store. This ensures all web nodes see the same cached data and invalidations are global.
- High Traffic Spikes: If disk I/O wait times increase, move the application cache from the filesystem to an in-memory store.
- Strict Compliance: If GDPR or similar regulations forbid caching specific personal data on disk, configure those specific cache definitions to use a volatile memory store only.
Cold Start Stampedes
After a full cache purge (e.g., during a version upgrade), Moodle faces a "cold start." Every single request will trigger a database query to repopulate the cache. On high-traffic sites, this can crash the database. To mitigate this, stagger the rollout of your update or use a warming script to populate critical caches before opening the site to users.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.