Forked from michael-grunder/cluster-quick-check.php
Created
September 8, 2021 04:29
-
-
Save fhferreira/fc73f5fde25a63f2f98c1ff5bff63ef2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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"; | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment