-
Notifications
You must be signed in to change notification settings - Fork 111
Description
Add Redis Cluster Support for v0.9.1
#194
This PR adds Redis Cluster support to the legacy v0.9.1 version.
While integrating this library into an older PHP project, I discovered that the original Redis adapter does not work correctly in cluster mode. After analyzing the source code, I identified three key issues and implemented a backward-compatible solution.
🐞 Problem Analysis & Solutions
- CROSSSLOT Key Distribution Issue
Problem:
When multiple keys fall into different hash slots, Redis Cluster returns:
CROSSSLOT Keys in request don't hash to the same slot
Solution:
Introduce a setHashTag method to ensure all related keys are placed under the same hash slot:
RedisCluster::setHashTag('TEST_PROMETHEUS');
- Multi-Instance Write Contention
Problem:
The original adapter relies on EVAL to guarantee atomicity.
However, Redis Cluster does not support cross-slot Lua scripts, resulting in potential write conflicts between multiple application instances.
Solution:
Following Prometheus best practices, assign a unique prefix for each instance to isolate keys:
$instanceID = !empty($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '127.0.0.1';
RedisCluster::setPrefix('TEST_PROMETHEUS:' . $instanceID);
This ensures each instance only writes to its own metrics keys.
- Multi-Process Atomicity Issue
Problem:
Atomic operations can no longer rely on EVAL since Lua scripts may not run on the same node in cluster mode.
Solution:
Use idempotent Redis operations to simulate atomic behavior and reduce inconsistency risks:
// Idempotent operations replacing the original Lua script logic
$pipe->hsetnx($metricKey, '__meta', json_encode($metaData)); // Set only if missing
$pipe->sadd($metricKeysKey, $metricKey); // Idempotent insert
⚖️ Trade-offs
If a Redis connection drops during pipeline execution, some operations may succeed while others fail — strict atomicity cannot be guaranteed.
However, this trade-off is acceptable for Prometheus metric data, where a small amount of inconsistency is tolerable.
💡 Contribution Suggestions
If the maintainers find this approach valuable, I am happy to continue contributing with:
Full Redis Cluster support for the latest version, or
Keeping this PR as a backward-compatible solution, where users only need to copy:
src/Prometheus/Storage/RedisCluster.php