Site icon 时鹏亮的Blog

PHP Redis Cluster集群状态检测脚本

请知悉:本文最近一次更新为 11个月 前,文中内容可能已经过时。

嗯,Redis Cluster集群状态检测其实一般telnet上去直接一个CLUSTER INFO就可以了。

但如果你需要节点等细节工作状态,那么这里有个来自Github的 michael-grunder 现成脚本:

<?php
// php cluter-quick-check --host <host> --port <port> [--auth password]

function panicAbort($str_msg) {
fprintf(STDERR, "Error: $str_msg\n");
exit(-1);
}

function panicClusterSlotsError($arr_slots, $str_context) {
$str_slots = print_r($arr_slots, true);
printWarning($str_slots);
panicError("Malformed CLUSTER SLOTS response ($str_context)");
}

function panicRedisError($str_msg, $arr_errors) {
fprintf(STDERR, "Redis Error: $str_msg\n");
foreach ($arr_errors as $str_error) {
if ($str_error) {
fprintf(STDERR, " Context: $str_error\n");
}
}

exit(-1);
}

function printWarning($str_msg) {
fprintf(STDERR, "Warning: $str_msg\n");
}

function printWarningArray($str_header, $arr_lines) {
fprintf(STDERR, "--- $str_header ---\n");
foreach ($arr_lines as $str_line) {
fprintf(STDERR, "$str_line\n");
}
}

function printUsage() {
fprintf(STDERR, "Usage: php cluster-quick-check.php --host <host> --port <port> [ --auth <auth>]\n");
exit(-1);
}

function getRedisConnection($str_host, $i_port, $str_auth) {
static $_arr_redis = [];

$str_hash = "$str_host:$i_port";
if (!isset($_arr_redis[$str_hash])) {
try {
$obj_r = new Redis(); $obj_r->connect($str_host, $i_port);
if ( ! $obj_r->isConnected()) {
panicAbort("Cannot connect to Redis at $str_hash");
}

if ($str_auth) $obj_r->auth($str_auth);
$arr_errors = [$obj_r->getLastError()];

if ( ! $obj_r->ping()) {
$arr_errors[] = $obj_r->getLastError();
panicRedisError("Can't connect/ping Redis at $str_hash", $arr_errors);
}

$_arr_redis[$str_hash] = $obj_r;
} catch(Exception $ex) {
panicAbort("getRedisConnection(): Can't connect to '$str_hash' (" . $ex->getMessage() . ')');
}
}

return $_arr_redis[$str_hash];
}

function checkClusterState($obj_r) {
$arr_info = array_filter(explode("\r\n", $obj_r->rawCommand('CLUSTER', 'INFO')));
foreach ($arr_info as $str_line) {
$arr_bits = explode(':', $str_line);
if (count($arr_bits) != 2) {
printWarning("Malformed CLUSTER INFO line: $str_line");
continue;
}

list ($key, $value) = $arr_bits;
if ($key == 'cluster_state') {
if ($value != 'ok') {
printWarningArray("CLUSTER INFO", $arr_info);
panicAbort("Cluster is not properly up!");
}

/* Redis thinks it's up */
return;
}
}

/* We shouldn't really get here but make sure anyway */
printWarningArray("CLUSTER INFO", $arr_info);
panicAbort("Cluster is not properly up!");
}

function checkClusterSlots($obj_r) {
$arr_slots = $obj_r->rawCommand('CLUSTER', 'SLOTS');

foreach ($arr_slots as $arr_slot) {
if (count($arr_slot) < 3) {
panicClusterSlotsError($arr_slots, 'node');
}

$sslot = array_shift($arr_slot);
$eslot = array_shift($arr_slot);

foreach ($arr_slot as $arr_info) {
if (count($arr_info) != 3) {
panicClusterSlotsError($arr_slots, 'info');
}

list($str_host, $i_port) = $arr_info;
echo "Checking [$sslot:$eslot] ($str_host:$i_port): ";
getRedisConnection($str_host, $i_port, $obj_r->getAuth());
echo "OK\n";
}
}
}

function getMovedNode($obj_r, $str_msg, &$str_host, &$i_port) {
$arr_bits = explode(' ', $str_msg);

if ($arr_bits[0] == 'MOVED' || $arr_bits[0] == 'ASKING') {
if (count($arr_bits) != 3) {
panicAbort("Malformed redirection!");
}

$arr_dest = explode(':', $arr_bits[2]);
if (count($arr_dest) != 2) {
panicAbort("Malformed destination node!");
}

list($str_host, $i_port) = $arr_dest;
$i_port = str_replace("\0", '', $i_port);
return true;
}

return false;
}

function sendClusterCommand($obj_r, $str_cmd, $arr_args) {
$tries = 10;

while($tries--) {
try {
call_user_func_array([$obj_r, $str_cmd], $arr_args);

if (($str_error = $obj_r->getLastError())) {
if (getMovedNode($obj_r, $str_error, $str_host, $i_port)) {
echo "Redirected to '$str_host:$i_port'\n";
$obj_r = getRedisConnection($str_host, $i_port, $obj_r->getAuth());
} else {
panicRedisError("Non MOVED error", [$str_error]);
}
}

return $obj_r;
} catch(Exception $ex) {
$str_msg = $ex->getMessage();
if (getMovedNode($obj_r, $str_msg, $str_host, $i_port)) {
echo "Redirected to '$str_host:$i_port'\n";
$obj_r = getRedisConnection($str_host, $i_port, $obj_r->getAuth());
} else {
panicAbort("Non MOVED Redis exception: " . $ex->getMessage());
}
}
}

panicAbort("Too many tries tring to find destination node!");
}

$arr_opt = getopt('', ['host:', 'port:', 'auth:']);
$str_host = $arr_opt['host'] ?? NULL;
$i_port = $arr_opt['port'] ?? NULL;
$str_auth = $arr_opt['auth'] ?? NULL;

if (!$str_host || !$i_port) {
printUsage();
}

/* Attempt to connect to the seed */
$obj_r = getRedisConnection($str_host, $i_port, $str_auth);

/* Step one, see if Redis thinks it's a cluster and if the cluster is OK */
echo "Checking general cluster INFO: ";
checkClusterState($obj_r);
echo "OK\n";

/* OK this seems good, now let's iterate over cluster slots */
checkClusterSlots($obj_r);

/* Finally let's set some data */
for($i = 0; $i < 10; $i++) {
$str_key = "phpredis-cluster-key:$i";
$str_val = "phpredis-cluster-val:$i";

echo "Attempting to set key '$str_key'\n";
$obj_r = sendClusterCommand($obj_r, 'SET', [$str_key, $str_val]);
echo "Success setting '$str_key'\n";
}

echo "Cluster seems OK\n";

?>

相关GitHub

cluster-quick-check.php


如您从本文得到了有价值的信息或帮助,请考虑扫描文末二维码捐赠和鼓励。

尊重他人劳动成果。转载请务必附上原文链接,我将感激不尽。


与《PHP Redis Cluster集群状态检测脚本》相关的博文:

Exit mobile version