redis集群使用
集群兼容方法
在正常情況下,有些方法是不能直接被集群客戶端調用成功的,比如mSet方法,它涉及了多個鍵名的操作,而多個鍵名是會分配給其他節點的
目前redis集群客戶端,實現了部分多鍵名操作方法的兼容,實現原理如下:
對多鍵名操作方法,進行拆分成單鍵名,然后通過鍵名去獲取槽節點,再通過槽節點分配的client去執行,每次只會執行一個鍵名
已經實現了兼容的方法:
方法名稱 | 參數 | 說明 | 備注 |
---|---|---|---|
mSet | $data | 設置多個鍵值對 | |
mGet | $keys | 獲取多個鍵名的值 | |
mSetNx | $data | 設置多個鍵值對 | 該方法將不能準確的判斷"當所有key不存在時,設置多個key值" |
集群禁用方法
由于集群的特性,不同的key分配到了不同的槽位,當你調用sUnion,sUnIonStore等涉及多個key操作的命令時,將會返回false,同時錯誤信息會在$redis->getErrorMsg()中顯示:
$redis = new \EasySwoole\Redis\RedisCluster(new \EasySwoole\Redis\Config\RedisClusterConfig([
['172.16.253.156', 9001],
['172.16.253.156', 9002],
['172.16.253.156', 9003],
['172.16.253.156', 9004],
], [
'auth' => '',
'serialize' => \EasySwoole\Redis\Config\RedisConfig::SERIALIZE_PHP
]));
$data = $redis->sUnIonStore('a','v','c');
var_dump($data,$redis->getErrorMsg());
將輸出:
bool(false)
string(53) "CROSSSLOT Keys in request don't hash to the same slot"
集群客戶端調度邏輯
客戶端默認調度
集群客戶端在調用redis方法的時候,自動默認一個客戶端進行發送接收命令:
function sendCommand(array $com, ?ClusterClient $client = null): bool
{
$client = $client ?? $this->getDefaultClient();
$this->setDefaultClient($client);
return $this->sendCommandByClient($com, $client);
}
function recv($timeout = null, ?ClusterClient $client = null): ?Response
{
$client = $client ?? $this->getDefaultClient();
$this->setDefaultClient($client);
return $this->recvByClient($client, $timeout);
}
當get,或者set的key值槽位不一致時,會自動切換客戶端進行發送接收命令:
//節點轉移客戶端處理
if ($result->getErrorType() == 'MOVED') {
$nodeId = $this->getMoveNodeId($result);
$client = $this->getClient($nodeId);
$this->clientConnect($client);
//只處理一次moved,如果出錯則不再處理
$client->sendCommand($command);
$result = $client->recv($timeout ?? $this->config->getTimeout());
}
切換完成之后,下一次命令,依舊是默認客戶端.
獲取集群的客戶端
集群操作方法列表:
方法名稱 | 參數 | 說明 | 備注 |
---|---|---|---|
getNodeClientList | 獲取集群客戶端列表 | ||
getNodeList | 獲取集群節點信息數組 | ||
clientAuth | ClusterClient $client, $password | 集群客戶端auth驗證 | |
setDefaultClient | ClusterClient $defaultClient | 設置一個默認的客戶端 | |
getDefaultClient | 獲取一個默認的客戶端(初始化會自動默認一個) | ||
tryConnectServerList | 嘗試重新獲取客戶端列表 | 當調用命令返回false,可嘗試重新獲取 | |
getClient | $nodeKey = null | 根據nodeKey獲取一個客戶端 | |
getMoveNodeId | Response $response | 根據recv返回的Move消息獲取一個nodeKey | |
getSlotNodeId | $slotId | 根據槽id獲取 nodeKey |
這些方法用于用戶自定義發送命令給redis服務端,或者是自己定義默認客戶端進行發送
集群兼容管道方法
由于管道的特性,開啟管道后,之后執行的命令將會保存不會直接發送,直到最后執行execPipe才會一次性發送
在集群中,只能選擇一個客戶端,進行一次性發送命令:
方法名稱 | 參數 | 說明 | 備注 |
---|---|---|---|
execPipe | ?ClusterClient $client = null | 一次性執行管道中保存的方法 | 可通過獲取客戶端列表,自定義選擇一個客戶端進行發送 |
discardPipe | 取消管道 | ||
startPipe | 管道開始記錄 |