123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- .. vim: set ts=3 sw=3 et :
- .. php:namespace:: Predis
- Clustering
- ----------
- A "cluster" is a group of Redis servers that collectively provide a shared
- namespace. In a cluster, data is not shared between Redis instances; instead,
- each server is used to serve a portion of the keys.
- In broad terms, this is done by identifying the key part of each Predis command
- to be run on the clustered connection. This key is then used to distribute
- commands among the underlying connections.
- Clustering has obvious advantages. As you add Redis instances to your
- cluster, your available space increases. At the same time, commands should be
- distributed between the nodes, meaning each individual node has to service
- less requests.
- Configuring a Cluster
- =====================
- Recall that the `Client` constructor takes two types of argument: a
- set of connection parameters, and a set of options::
- $client = new Predis\Client($connection, $options);
- You only need to do one thing differently to set up a clustered client:
- identify multiple connections. You can also, optionally, configure your cluster
- with the ``cluster`` client option.
- Configuring Multiple Connections
- ''''''''''''''''''''''''''''''''
- Passing information about multiple connections is as simple as wrapping them
- all in an array::
- $client = new Predis\Client(array(
- array(
- 'host' => '127.0.0.1',
- 'port' => 6379,
- 'database' => 2,
- 'alias' => 'first'
- ),
- array(
- 'host' => '127.0.0.1',
- 'port' => 6379,
- 'database' => 3,
- 'alias' => 'second',
- )
- ), $options);
- You can still use the URI syntax to configure the connections::
- $client = new Predis\Client(array(
- 'tcp://127.0.0.1:6370?alias=first&database=0',
- 'tcp://127.0.0.1:6370?alias=second&database=1'
- ), $options);
- .. note::
- When you want to pass information about multiple connections, Predis expects
- you'll do so with a numeric array, indexed from 0. If you've removed
- connections from your array (perhaps after catching a
- `Predis\\CommunicationException`), you can use array_values() to reindex it.
- If your connection array does not have a value at [0], Predis
- will assume you're trying to configure a single connection with an
- associative array.
- The ``cluster`` Client Option
- '''''''''''''''''''''''''''''
- .. php:namespace:: Predis\Connection
- You can optionally configure your client's clustering by using the ``cluster``
- client option. This option can take a few different types of value. It can take
- the special strings ``"predis"`` or ``"redis"`` to switch between the two
- built-in cluster connection classes `PredisCluster` and
- `RedisCluster` respectively::
- $client = new Predis\Client(array(
- // ...
- ), array('cluster' => 'predis'));
- If the value is any other string, it's expected to be the fully qualified name
- of a class implementing `ClusterConnectionInterface`.
- Finally, you can also configure the option with a callable. This callable is
- expected to return an instance of `ClusterConnectionInterface`::
- $client = new Predis\Client(array(
- // ...
- ), array(
- 'cluster' => function () {
- return new Predis\Connection\PredisCluster();
- }
- ));
- Provided Connection Classes
- ===========================
- PredisCluster
- '''''''''''''
- .. php:class:: PredisCluster
- ``PredisCluster`` is a simple Predis-native clustered connection implementation.
- This form of clustered connection does *not* provide redundancy. If your
- application makes requests for 100 different keys, with the default
- distribution strategy these keys are likely to be spit across all the servers
- in your pool.
- Distribution Strategy
- :::::::::::::::::::::
- Exactly how keys are split across a cluster is specified by a
- :term:`distribution strategy`. There are two distribution strategy classes
- shipped with Predis. What they have in common is that they try to manage the
- task of adding and removing servers from the cluster cleverly. When a server is
- added or removed, the distribution strategy takes care of ensuring that as few
- keys as possible have to be moved between the remaining servers. When you
- remove a server from a clustered connection of ten servers, ideally you'd only
- like 10% of your keys to be newly missing.
- This is broadly known as "`consistent hashing`_".
- It's also worth noting what a distribution strategy doesn't do: it doesn't
- actually ensure availability of your data between different cluster
- configurations. Or, more accurately, it leaves this up to you.
- You might decide to take the naive approach: that if a node goes offline, it'll take a
- portion of your keyspace with it. This might not matter to your application,
- especially if you can recalculate the data you were storing, or if you're using
- your cluster as a cache.
- If this sort of availability does matter for your application, it's up to you
- to take care of it, using tools external to Predis. You may want to move data
- before taking a node offline, for instance, ensuring minimal disruption. The
- fact that you can customize or replace the distribution strategy should make
- integrating such tools with `PredisCluster` much easier. For example, you may
- want to use a `Predis\\Cluster\\Distribution\\KetamaPureRing` strategy,
- combined with `libketama`_-based tools.
- The distribution strategy for a `PredisCluster` must implement
- `Predis\\Cluster\\Distribution\\DistributionStrategyInterface`. You pass your
- strategy into the `PredisCluster` instance as the first argument, using a
- 'cluster' client-option callback::
- $client = new Predis\Client(array(
- // ...
- ), array(
- 'cluster' => function () {
- $strategy = new Predis\Cluster\Distribution\KetamaPureRing();
- return new Predis\Connection\PredisCluster($strategy);
- }
- ));
- .. _consistent hashing: https://en.wikipedia.org/wiki/Consistent_hashing
- .. _libketama: https://github.com/RJ/ketama
- RedisCluster
- ''''''''''''
- .. php:class:: RedisCluster
- ``RedisCluster`` is a clustered connection implementation intended for use with
- Redis Cluster.
- `Redis Cluster`_ is not yet finalized, but it already includes some
- pretty cool features. Nodes in a Redis Cluster arrangement configure
- themselves to deal with changes in availability. Once consequence of this is
- that a distribution strategy is unnecessary: nodes in this cluster type agree
- and decide themselves about which node is to serve a portion of the keyspace.
- .. _Redis Cluster: http://redis.io/topics/cluster-spec
- Disallowed Commands
- ===================
- Some commands just don't make sense to run on a clustered connection. For
- example, the ``INFO`` command returns information about the server on which
- it's run, so running it on a cluster would be meaningless.
- If you try to run one of these commands, you'll get a
- `Predis\\NotSupportedException`.
- Running Commands on Nodes
- =========================
- `PredisCluster` and :php:class:`RedisCluster` both
- implement `\\IteratorAggregate`, so you can easily run commands against the
- individual Redis servers in a cluster::
- $hosts = array();
- foreach ($client->getConnection() as $shard) {
- $hosts[] = $shard->info();
- }
|