官方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將與主節點進行通信,除非出現故障,在這種情況下,將嘗試從從站讀取會話信息
