clustering.rst 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. .. vim: set ts=3 sw=3 et :
  2. .. php:namespace:: Predis
  3. Clustering
  4. ----------
  5. A "cluster" is a group of Redis servers that collectively provide a shared
  6. namespace. In a cluster, data is not shared between Redis instances; instead,
  7. each server is used to serve a portion of the keys.
  8. In broad terms, this is done by identifying the key part of each Predis command
  9. to be run on the clustered connection. This key is then used to distribute
  10. commands among the underlying connections.
  11. Clustering has obvious advantages. As you add Redis instances to your
  12. cluster, your available space increases. At the same time, commands should be
  13. distributed between the nodes, meaning each individual node has to service
  14. less requests.
  15. Configuring a Cluster
  16. =====================
  17. Recall that the `Client` constructor takes two types of argument: a
  18. set of connection parameters, and a set of options::
  19. $client = new Predis\Client($connection, $options);
  20. You only need to do one thing differently to set up a clustered client:
  21. identify multiple connections. You can also, optionally, configure your cluster
  22. with the ``cluster`` client option.
  23. Configuring Multiple Connections
  24. ''''''''''''''''''''''''''''''''
  25. Passing information about multiple connections is as simple as wrapping them
  26. all in an array::
  27. $client = new Predis\Client(array(
  28. array(
  29. 'host' => '127.0.0.1',
  30. 'port' => 6379,
  31. 'database' => 2,
  32. 'alias' => 'first'
  33. ),
  34. array(
  35. 'host' => '127.0.0.1',
  36. 'port' => 6379,
  37. 'database' => 3,
  38. 'alias' => 'second',
  39. )
  40. ), $options);
  41. You can still use the URI syntax to configure the connections::
  42. $client = new Predis\Client(array(
  43. 'tcp://127.0.0.1:6370?alias=first&database=0',
  44. 'tcp://127.0.0.1:6370?alias=second&database=1'
  45. ), $options);
  46. .. note::
  47. When you want to pass information about multiple connections, Predis expects
  48. you'll do so with a numeric array, indexed from 0. If you've removed
  49. connections from your array (perhaps after catching a
  50. `Predis\\CommunicationException`), you can use array_values() to reindex it.
  51. If your connection array does not have a value at [0], Predis
  52. will assume you're trying to configure a single connection with an
  53. associative array.
  54. The ``cluster`` Client Option
  55. '''''''''''''''''''''''''''''
  56. .. php:namespace:: Predis\Connection
  57. You can optionally configure your client's clustering by using the ``cluster``
  58. client option. This option can take a few different types of value. It can take
  59. the special strings ``"predis"`` or ``"redis"`` to switch between the two
  60. built-in cluster connection classes `PredisCluster` and
  61. `RedisCluster` respectively::
  62. $client = new Predis\Client(array(
  63. // ...
  64. ), array('cluster' => 'predis'));
  65. If the value is any other string, it's expected to be the fully qualified name
  66. of a class implementing `ClusterConnectionInterface`.
  67. Finally, you can also configure the option with a callable. This callable is
  68. expected to return an instance of `ClusterConnectionInterface`::
  69. $client = new Predis\Client(array(
  70. // ...
  71. ), array(
  72. 'cluster' => function () {
  73. return new Predis\Connection\PredisCluster();
  74. }
  75. ));
  76. Provided Connection Classes
  77. ===========================
  78. PredisCluster
  79. '''''''''''''
  80. .. php:class:: PredisCluster
  81. ``PredisCluster`` is a simple Predis-native clustered connection implementation.
  82. This form of clustered connection does *not* provide redundancy. If your
  83. application makes requests for 100 different keys, with the default
  84. distribution strategy these keys are likely to be spit across all the servers
  85. in your pool.
  86. Distribution Strategy
  87. :::::::::::::::::::::
  88. Exactly how keys are split across a cluster is specified by a
  89. :term:`distribution strategy`. There are two distribution strategy classes
  90. shipped with Predis. What they have in common is that they try to manage the
  91. task of adding and removing servers from the cluster cleverly. When a server is
  92. added or removed, the distribution strategy takes care of ensuring that as few
  93. keys as possible have to be moved between the remaining servers. When you
  94. remove a server from a clustered connection of ten servers, ideally you'd only
  95. like 10% of your keys to be newly missing.
  96. This is broadly known as "`consistent hashing`_".
  97. It's also worth noting what a distribution strategy doesn't do: it doesn't
  98. actually ensure availability of your data between different cluster
  99. configurations. Or, more accurately, it leaves this up to you.
  100. You might decide to take the naive approach: that if a node goes offline, it'll take a
  101. portion of your keyspace with it. This might not matter to your application,
  102. especially if you can recalculate the data you were storing, or if you're using
  103. your cluster as a cache.
  104. If this sort of availability does matter for your application, it's up to you
  105. to take care of it, using tools external to Predis. You may want to move data
  106. before taking a node offline, for instance, ensuring minimal disruption. The
  107. fact that you can customize or replace the distribution strategy should make
  108. integrating such tools with `PredisCluster` much easier. For example, you may
  109. want to use a `Predis\\Cluster\\Distribution\\KetamaPureRing` strategy,
  110. combined with `libketama`_-based tools.
  111. The distribution strategy for a `PredisCluster` must implement
  112. `Predis\\Cluster\\Distribution\\DistributionStrategyInterface`. You pass your
  113. strategy into the `PredisCluster` instance as the first argument, using a
  114. 'cluster' client-option callback::
  115. $client = new Predis\Client(array(
  116. // ...
  117. ), array(
  118. 'cluster' => function () {
  119. $strategy = new Predis\Cluster\Distribution\KetamaPureRing();
  120. return new Predis\Connection\PredisCluster($strategy);
  121. }
  122. ));
  123. .. _consistent hashing: https://en.wikipedia.org/wiki/Consistent_hashing
  124. .. _libketama: https://github.com/RJ/ketama
  125. RedisCluster
  126. ''''''''''''
  127. .. php:class:: RedisCluster
  128. ``RedisCluster`` is a clustered connection implementation intended for use with
  129. Redis Cluster.
  130. `Redis Cluster`_ is not yet finalized, but it already includes some
  131. pretty cool features. Nodes in a Redis Cluster arrangement configure
  132. themselves to deal with changes in availability. Once consequence of this is
  133. that a distribution strategy is unnecessary: nodes in this cluster type agree
  134. and decide themselves about which node is to serve a portion of the keyspace.
  135. .. _Redis Cluster: http://redis.io/topics/cluster-spec
  136. Disallowed Commands
  137. ===================
  138. Some commands just don't make sense to run on a clustered connection. For
  139. example, the ``INFO`` command returns information about the server on which
  140. it's run, so running it on a cluster would be meaningless.
  141. If you try to run one of these commands, you'll get a
  142. `Predis\\NotSupportedException`.
  143. Running Commands on Nodes
  144. =========================
  145. `PredisCluster` and :php:class:`RedisCluster` both
  146. implement `\\IteratorAggregate`, so you can easily run commands against the
  147. individual Redis servers in a cluster::
  148. $hosts = array();
  149. foreach ($client->getConnection() as $shard) {
  150. $hosts[] = $shard->info();
  151. }