如何查看zan框架机器连接池状况?
Usage:
curl -s http://gitlab.qima-inc.com/chuxiaofeng/zan-dev-doc/raw/master/poolstat.php | sudo php
script:
#!/usr/bin/env php
<?php
/**
* @author xiaofeng
* 连接池信息查看
*/
$usage = "Usage: $argv[0] ZanProjectRoot\n";
checkEnv($usage);
// 依赖supervisor directory配置
// 约定cwd为项目rootPath
$runMode = getenv('KDT_RUN_MODE') ?: get_cfg_var('kdt.RUN_MODE') ?: "online";
if (isset($argv[1])) {
$dirs = [ "$argv[1]/resource/config/$runMode/connection" ];
} else {
$dirs = `for pid in $(pidof php); do echo $(sudo readlink /proc/\$pid/cwd); done | uniq`;
$dirs = array_unique(array_filter(explode(PHP_EOL, trim($dirs))));
$dirs = array_map(function($v) use($runMode) { return "$v/resource/config/$runMode/connection"; }, $dirs);
}
foreach ($dirs as $dir) {
if (!file_exists($dir)) {
continue;
}
echo $dir, "\n";
connstat($dir);
}
function checkEnv($usage)
{
global $argv;
if (trim(`whoami`) !== "root") {
sys_abort("请使用root权限运行");
}
if (!ini_get("register_argc_argv")) {
echo "You must turn 'register_argc_argv' to On in php.ini\n";
exit(1);
}
// assert(PHP_OS === "Linux", "Only Support Linux");
if (!is_readable("/proc/1/status")) {
echo "/proc/1/status does not exist, what OS are you running ?\n";
exit(1);
}
if (isset($argv[1]) && $argv[1] === "install") {
$self = __FILE__;
`rm -rf /usr/local/bin/nova`;
`chmod +x $self && cp $self /usr/local/bin/nova`;
exit;
}
if (isset($argv[1]) && ($argv[1] === "--help" || $argv[1] === "-h")) {
echo $usage;
exit(1);
}
}
/**
* 读取zan项目connection配置
* @param $connDir
*/
function connstat($connDir) {
$stat = [];
$iter = new \RecursiveDirectoryIterator($connDir, \RecursiveDirectoryIterator::SKIP_DOTS);
$iter = new \RecursiveIteratorIterator($iter, \RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($iter as $fileInfo) {
/* @var $fileInfo \SplFileInfo */
$ext = $fileInfo->getExtension();
$connName = substr($fileInfo->getFilename(), 0, -strlen($ext) - 1);
/** @noinspection PhpIncludeInspection */
$connInfo = require_once $fileInfo->getRealPath();
if (!is_array($connInfo)) {
continue;
}
$connStat = [];
foreach ($connInfo as $connKey => $conn) {
if (isset($conn["pool"]) && $conn["pool"]) { // for tcp
if (isset($conn["host"]) && isset($conn["port"])) {
list($host, $port) = [$conn["host"], $conn["port"]];
$connStat["$connKey#$host:$port"] = TcpStat::count($host, $port);
} else if (isset($conn["path"])) { // for unix socket
$path = $conn["path"];
$connStat["$connKey#$path"] = TcpStat::xCount($path);
}
}
}
if ($connStat) {
$stat[$connName] = $connStat;
}
}
echo json_encode($stat, JSON_PRETTY_PRINT), PHP_EOL;
}
/**
* Class TcpStat
* @package Zan\Framework\Components\ZanBox
*/
class TcpStat
{
const SS_NETSTAT_TCP_STATE_MAP = [
"established" => "ESTABLISHED",
"syn-sent" => "SYN_SENT",
"syn-recv" => "SYN_RCVD",
"fin-wait-1" => "FIN_WAIT_1",
"fin-wait-2" => "FIN_WAIT_2",
"time-wait" => "TIME_WAIT",
"closed" => "CLOSED",
"close-wait" => "CLOSE_WAIT",
"last-ack" => "LAST_ACK",
"listen" => "LISTEN",
"closing" => "CLOSING",
];
public static function xCount($path)
{
if (PHP_OS === "Darwin") {
$n = `netstat -x | grep $path | wc -l`;
return intval(trim($n));
} else {
$n = `ss -x src $path | wc -l`;
return intval(trim($n)) - 1;
}
}
/**
* 统计不同状态连接数量, 兼容mac与linux
* @param string $host
* @param int $port
* @param array $states
* @return array
*/
public static function count($host, $port, $states = ["established", "time-wait", "close-wait"]) {
if (!ip2long($host)) {
$host = gethostbyname($host);
}
$pipe = "wc -l";
$func = PHP_OS === "Darwin" ? "netstat" : "ss";
$states = static::fmtTcpState($states, $func);
$info = [];
foreach ($states as $state) {
$ret = call_user_func([static::class, $func], $host, $port, $state, $pipe);
$info[$state] = intval(trim($ret)) - 1;
}
return $info;
}
/**
* @param array $states
* @param string $type
* @return array
*/
public static function fmtTcpState(array $states, $type)
{
$from = $to = [];
if ($type === "ss") {
$to = static::SS_NETSTAT_TCP_STATE_MAP;
$from = array_flip($to);
} else if ($type === "netstat") {
$from = static::SS_NETSTAT_TCP_STATE_MAP;
$to = array_flip($from);
}
$ret = [];
foreach ($states as $state) {
if (isset($to[$state])) {
$ret[] = $state;
} else if (isset($from[$state])) {
$ret[] = $from[$state];
}
}
return $ret;
}
/** @noinspection PhpUnusedPrivateMethodInspection */
private static function netstat($host, $port, $state, $pipe = "")
{
if ($pipe) {
$pipe = " | $pipe";
}
// $4 src $5 dst $6 stats
return `netstat -an | awk '(\$5 == "$host.$port" && \$6 == "$state") || NR==2 {print \$0}' $pipe`;
}
/** @noinspection PhpUnusedPrivateMethodInspection */
private static function ss($host, $port, $state, $pipe = "")
{
if ($pipe) {
$pipe = " | $pipe";
}
return `ss state $state dst $host:$port $pipe`;
}
}