Skip to content

max_connections is not being honoured in RedisCluster mode #3684

Open
@Sakin-Subbaiah

Description

@Sakin-Subbaiah

Description:
When using redis-py with RedisCluster, exceeding max_connections raises a ConnectionError. However, this error triggers reinitialisation of the cluster nodes and drops the old connection pool. This in turn leads to situation where an new connection pool is created to the affected node indefinitely whenever it hit the configured max_connections.

Relevant Code Snippet:
https://github.com/redis/redis-py/blob/master/redis/connection.py#L1559

def make_connection(self) -> "ConnectionInterface":
    if self._created_connections >= self.max_connections:
        raise ConnectionError("Too many connections")
    self._created_connections += 1
And in the reconnection logic:

Error handling of execute_command
As observed the impacted node's connection object is dropped so when a subsequent operation for that node or reinitialisation is done, a new connection pool object will be created for that node. So if there is a bulk operation on this node, it will go on dropping(not releasing) and creating new connections.
https://github.com/redis/redis-py/blob/master/redis/cluster.py#L1238C1-L1251C24

            except (ConnectionError, TimeoutError) as e:
                # ConnectionError can also be raised if we couldn't get a
                # connection from the pool before timing out, so check that
                # this is an actual connection before attempting to disconnect.
                if connection is not None:
                    connection.disconnect()

                # Remove the failed node from the startup nodes before we try
                # to reinitialize the cluster
                self.nodes_manager.startup_nodes.pop(target_node.name, None)
                # Reset the cluster node's connection
                target_node.redis_connection = None
                self.nodes_manager.initialize()
                raise e

One of node reinitialisation step involves getting CLUSTER SLOT. Since the actual cause of the ConnectionError is not a node failure but rather an exceeded connection limit, the node still appears in the CLUSTER SLOTS output. Consequently, a new connection pool is created for the same node.
https://github.com/redis/redis-py/blob/master/redis/cluster.py#L1691

        for startup_node in tuple(self.startup_nodes.values()):
            try:
                if startup_node.redis_connection:
                    r = startup_node.redis_connection
                else:
                    # Create a new Redis connection
                    r = self.create_redis_node(
                        startup_node.host, startup_node.port, **kwargs
                    )
                    self.startup_nodes[startup_node.name].redis_connection = r
                # Make sure cluster mode is enabled on this node
                try:
                    cluster_slots = str_if_bytes(r.execute_command("CLUSTER SLOTS"))
                    r.connection_pool.disconnect()
........
        # Create Redis connections to all nodes
        self.create_redis_connections(list(tmp_nodes_cache.values()))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions