redis-rb
redis-rb copied to clipboard
Cluster Mode: Ability for client to send a command to specific cluster node(s) or all cluster nodes.
RE: Cluster Mode
- Use case: App wants to know the commands and resultant load per cluster node (e.g. 'info [section]' where section might be 'stats', 'commandstats', 'memory', 'cpu', etc).
- Request the ability for a client to send a command to a specific cluster node (e.g. supply the node id), or a means to specify a list or designate all cluster nodes (and perhaps have the response be a Hash of key-value pairs (e.g. key: node id, value: node specific response).
- FYI, FWIW: Command 'keys' apparently applies to all cluster nodes. Thought it odd that it behaves differently than other commands. Note that I'm not complaining about such behavior.
Hello,
Would you tell us what is the purpose of the use case? Is it for monitoring or load balancing?
@supercaracal - Yes, as you surmised, the use case is for cluster monitoring and load balancing.
- The specific use case is for monitoring streams throughput, resource utilization/consumption, and load balancing streams/slots amongst multiple clusters' nodes.
- FYI, FWIW: There are multiple Redis clusters, each with multiple nodes, that must work in concert to accommodate streaming millions of packets per second. Thus cluster node (and slot) monitoring and management are critical to ensure streams are properly allocated (to nodes that can accommodate streams' throughput requirements). Monitoring & Management logic is cluster aware, node aware, and stream aware - and must be able to dynamically monitor-allocate-reallocate clusters' resources.
You can extract all node information with workaround like this:
r = Redis.new cluster: ['redis://127.0.0.1:7000']
r._client.instance_variable_get(:@node).call_all(%w[info]).map { |reply| Redis::HashifyInfo.call(reply) }
It needs more parsing steps if you specify commandstats as section of the command.
https://github.com/redis/redis-rb/blob/fa76a2661739f56e3458fc5ed5a7b7c31861eff5/lib/redis.rb#L311-L317
The Gem certainly sends the command to a random node when using cluster mode. That behavior might be pointless. https://github.com/redis/redis-rb/blob/fa76a2661739f56e3458fc5ed5a7b7c31861eff5/lib/redis/cluster.rb#L128-L154
It seems that Redis Cluster Proxy doesn't support the command. https://github.com/RedisLabs/redis-cluster-proxy/blob/unstable/COMMANDS.md#unsupported-commands
Basically, keys and nodes go hand in hand when servers are cluster mode and clients send commands including keys. I would say that the Gem need not dare to support of exposing interfaces each node.
@supercaracal - Thanks for the feedback and work-around suggestions.
Following is an approach I believe should work to send commands to individual cluster nodes (in addition to your #call_all suggestion to call all cluster nodes). Please let me know your thoughts as to the viability, thanks:
- cluster_clients = redis_client._client.instance_variable_get(:@node).instance_variable_get(:@clients)
- cluster_nodes_keys = cluster_clients.keys
- Imagine logic that takes 'cluster nodes' response 'ip_port' and 'slots' makes an association to a given cluster_nodes_keys element (e.g. '10.60.62.19:30001').
- Then I should be able to call a specific cluster node directly, for example:
- cluster_clients['10.60.62.19:30001'].call(['info', 'commandstats'])
- It seems to work fine. Any caveats or problems regarding such an approach?
It seems that there are no problems except one of the first step:
s/@Clients/@clients/
https://github.com/redis/redis-rb/blob/fa76a2661739f56e3458fc5ed5a7b7c31861eff5/lib/redis/cluster/node.rb#L18