Skip to content

Add redis cluster adapter for v0.9.1 #195

@RenewedLove

Description

@RenewedLove

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

  1. 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');

  1. 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.

  1. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions