官方url: https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#readme
2017年10月29日20:44:25
Redis引入3.0.0版本的群集支持,并且使用phpredis与群集进行通信时,需要使用RedisCluster类。 对于大多数操作,RedisCluster类可以作为Redis类的替换,而不需要修改它的调用方式。 由于Tradesy的慷慨赞助,这个功能被添加了
创建并连接到集群
为了保持与RedisArray类的一致性,可以通过传递一个或多个“种子”节点,或者将redis.ini中的这些节点定义为“命名”集群来创建和连接到集群
声明具有种子数组的群集
// 创建一个集群,将两个节点设置为种子
$obj_cluster = new RedisCluster(NULL, Array('host:7000', 'host:7001', 'host:7003'));
// 连接并指定timeout和read_timeout
$obj_cluster = new RedisCluster(NULL, Array("host:7000", "host:7001"), 1.5, 1.5);
// 连接读/写超时,并指定phpredis应该使用
// 连接到每个节点
$obj_cluster = new RedisCluster(NULL, Array("host:7000", "host:7001"), 1.5, 1.5, true);
按名称加载群集配置
为了加载一个命名的数组,必须首先在redis.ini中定义种子节点。 以下行将定义集群“mycluster”,并由phpredis自动加载
# In redis.ini
redis.clusters.seeds = "mycluster[]=localhost:7000&test[]=localhost:7001"
redis.clusters.timeout = "mycluster=5"
redis.clusters.read_timeout = "mycluster=10"
然后,可以通过执行以下操作来加载此群集
$obj_cluster = new RedisCluster('mycluster');
连接过程
在构建时,RedisCluster类将遍历提供的种子节点,直到它可以获得与群集的连接,并运行CLUSTER SLOTS以映射本地群集中的每个节点。 一旦键空间被映射,RedisCluster只会在需要时连接到节点(例如,您获得了我们相信该节点上的密钥)。
超时
由于Redis集群旨在提供高可用性,因此超时在正常套接字通信中的工作方式不一样。 完全可能在给定的套接字上发生超时甚至异常(例如,在主节点发生故障的情况下),并且如果可以将从属机制升级为新主机,则继续提供请求。
RedisCluster处理用户指定的超时值的方式是,每当命令发送到集群时,我们会记录在请求开始时的时间,然后再次每次重新发出命令到另一个节点 因为Redis集群用MOVED / ASK响应,或者因为我们未能与给定节点进行通信)。 一旦我们检测到在命令循环中超过我们指定的超时时间,就会出现错误。
Keyspace map
如前所述,RedisCluster对构建中的每个主(和任何从站)进行初始映射,它用于确定哪些节点用于指定给定的命令。 但是,Redis集群的核心功能之一就是,这个密钥空间可以在集群运行时发生变化。
因此,RedisCluster类将在请求数据时收到MOVED错误时更新它的密钥空间映射。 在我们收到ASK重定向的情况下,它遵循Redis规范,并从ASK节点请求密钥,前缀为ASKING命令。
Automatic slave failover / distribution 自动从站故障切换/分发
默认情况下,RedisCluster只会向主节点发送命令,但是如果请求,可以为readonly命令配置不同的命令。
//默认选项,只发送命令到主节点
$obj_cluster->setOption(RedisCluster::OPT_SLAVE_FAILOVER, RedisCluster::FAILOVER_NONE);
// 如果我们无法访问主服务器,并且对于读取命令,它们具有从站,故障转移
$obj_cluster->setOption(RedisCluster::OPT_SLAVE_FAILOVER, RedisCluster::FAILOVER_ERROR);
// 始终在主机和从机之间随机分配只读命令
$obj_cluster->setOption(
RedisCluster::OPT_SLAVE_FAILOVER, RedisCluster::FAILOVER_DISTRIBUTE
);
Main command loop 主命令循环
除了指向特定节点的命令之外,通过RedisCluster执行的每个命令都将通过命令循环进行处理,在该循环中,我们进行请求,处理任何MOVED或ASK重定向,并在必要时重复执行。 这将持续到满足以下条件之一:
- 我们无法与我们所知道的任何节点通信,在这种情况下会引发RedisClusterExecption。
- 我们已经反弹了比施工期限的时间更长的时间。(翻译有问题)
- Redis cluster返回一个CLUSTERDOWN错误,在这种情况下会引发一个RedisClusterException异常。
- 我们收到一个有效的响应,在这种情况下,数据将返回给来调用者。
Transactions
RedisCluster类完全支持MULTI ... EXEC事务,包括在多个键上操作的诸如MGET和MSET的命令。 但是,在这里必须考虑到这些因素。
当您调用RedisCluster-> multi()时,集群将进入MULTI状态,但是在该节点上请求一个密钥之前,MULTI命令不会传递给任何节点。 此外,对EXEC的调用将始终返回一个数组(即使在给定节点的事务发生故障的情况下),因为根据所调用的命令可以转到任意数量的节点
请考虑以下示例:
// 集群在本地进入MULTI状态
$obj_cluster->multi();
// 集群将首先在该节点上发布MULTI(并且只有一次)
$obj_cluster->get("mykey");
$obj_cluster->set("mykey", "new_value");
// 如果'myotherkey'映射到不同的节点,MULTI将在那里发出
// before requesting the key
$obj_cluster->get("myotherkey");
// 即使在事件失败的情况下,它也将始终返回一个数组
// 在其中一个节点上,在这种情况下,该元素将为FALSE
print_r($obj_cluster->exec());
Pipelining
RedisCluster类不支持流水线,因为无法检测密钥是否仍然存在于我们的地图表示它们所做的事情上,因此本来不安全。 如果需要这样的功能,可以实施这种支持作为选择。
Multiple key commands
Redis集群允许在多个键上操作的命令,但只有当所有这些键都散列到同一个插槽时。 请注意,这些密钥全部在同一个节点上是不够的,但实际上必须哈希到完全相同的哈希槽。
对于所有这些多个密钥命令(除了MGET和MSET之外),RedisCluster类将验证每个密钥映射到相同的哈希槽,并引发“CROSSSLOT”警告,如果没有,则返回false。
MGET and MSET
RedisCluster具有针对MGET和MSET的专门处理功能,允许您发送任意数量的密钥(散列到任意一个插槽),而无需考虑其居住地点。 这样做的方式是,RedisCluster类会在命令遍历密钥时分割命令,并为每个密钥的插槽提供一组命令
// 这将通过两个命令传递。 首先对于所有的{hash1}键
// 然后抓取'otherkey'
$obj_cluster->mget(Array("{hash1}key1","{hash1}key2","{hash1}key3","otherkey"));
这个操作也可以在MULTI模式下透明地完成
Directed node commands
有各种命令必须针对特定节点。 在这些命令的情况下,调用者可以传递一个键(它将被散列并用于指示我们的命令),或者传递一个带有host:port的数组
// 这将针对将存储“mykey”的插槽/节点
$obj_cluster->echo("mykey","Hello World!");
// 在这里,我们重复了所有已知的主节点,并在那里交付命令
foreach ($obj_cluster->_masters() as $arr_master) {
$obj_cluster->echo($arr_master, "Hello: " . implode(':', $arr_master));
}
在需要指向节点的所有命令的情况下,调用约定与Redis调用相同,只是它们需要额外的(第一个)参数才能传递命令。 以下是每个命令的列表:
- SAVE
- BGSAVE
- FLUSHDB
- FLUSHALL
- DBSIZE
- BGREWRITEAOF
- LASTSAVE
- INFO
- CLIENT
- CLUSTER
- CONFIG
- PUBSUB
- SLOWLOG
- RANDOMKEY
- PING
Session Handler
您可以使用phpredis的集群功能将Redhat集群中的PHP会话信息存储在可启用的不支持集群功能的Redis实例中。
为此,您必须配置session.save_handler和session.save_path INI变量,以使phpredis足够的信息与群集通信。
session.save_handler = rediscluster
session.save_path = "seed[]=host1:port1&seed[]=host2:port2&seed[]=hostN:portN&timeout=2&read_timeout=2&failover=error&persistent=1"
session.session_handler
将此变量设置为“rediscluster”以通知phpredis这是一个集群实例
session.save_path
基于群集的会话存储的保存路径采用PHP GET请求的形式,并要求您至少在种子节点上指定。 您可以指定的其他选项如下:
- timeout (double): phpredis在连接或写入群集时等待的时间量
- read_timeout (double): phpredis的时间将等待集群的结果
- persistent: 告诉phpredis是否应该使用永久连接
- distribute: phpredis将随机分配主机和任何连接的从站之间的会话读取(负载平衡)
- failover (string): phpredis应如何分配主节点和从节点之间的会话读取
-
- none : phpredis只能与主节点进行通信
-
- error: phpredis将与主节点进行通信,除非出现故障,在这种情况下,将尝试从从站读取会话信息