一个非常好的memcached监控工具, 监控memcached的内存使用情况和命中率
配置非常简单,只用配置监控的Memcached服务器的信息和访问的用户名密码就可以了!
可以监控多个服务器
图形界面
<?php/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2004 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | [email protected] so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Harun Yayli | +----------------------------------------------------------------------+*/$VERSION='$Id: memcache.php,v 1.1.2.3 2008/08/28 18:07:54 mikl Exp $';define('ADMIN_USERNAME','memcache'); // Admin Usernamedefine('ADMIN_PASSWORD','password'); // Admin Passworddefine('DATE_FORMAT','Y/m/d H:i:s');define('GRAPH_SIZE',200);define('MAX_ITEM_DUMP',50);$MEMCACHE_SERVERS[] = 'mymemcache-server1:11211'; // add more as an array$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array////////// END OF DEFAULT CONFIG AREA ////////////////////////////////////////////////////////////////////////////// Password protect ////////////////////////////////////////////////////////////////if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || $_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME ||$_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) { Header("WWW-Authenticate: Basic realm=\"Memcache Login\""); Header("HTTP/1.0 401 Unauthorized"); echo <<<EOB <body>Rejected!
Wrong Username or Password! EOB; exit;}///////////MEMCACHE FUNCTIONS /////////////////////////////////////////////////////////////////////function sendMemcacheCommands($command){ global $MEMCACHE_SERVERS; $result = array(); foreach($MEMCACHE_SERVERS as $server){ $strs = explode(':',$server); $host = $strs[0] = '127.0.0.1'; //自己配置去 $port = $strs[1] = '11211'; $result[$server] = sendMemcacheCommand($host,$port,$command); } return $result;}function sendMemcacheCommand($server,$port,$command){ $s = @fsockopen($server,$port); if (!$s){ die("Cant connect to:".$server.':'.$port); } fwrite($s, $command."\r\n"); $buf=''; while ((!feof($s))) { $buf .= fgets($s, 256); if (strpos($buf,"END\r\n")!==false){ // stat says end break; } if (strpos($buf,"DELETED\r\n")!==false || strpos($buf,"NOT_FOUND\r\n")!==false){ // delete says these break; } if (strpos($buf,"OK\r\n")!==false){ // flush_all says ok break; } } fclose($s); return parseMemcacheResults($buf);}function parseMemcacheResults($str){ $res = array(); $lines = explode("\r\n",$str); $cnt = count($lines); for($i=0; $i$flag,'size'=>$size); $res[$l[0]][$l[1]]['value']=$lines[++$i]; } }elseif($line=='DELETED' || $line=='NOT_FOUND' || $line=='OK'){ return $line; } } return $res;}function dumpCacheSlab($server,$slabId,$limit){ list($host,$port) = explode(':',$server); $resp = sendMemcacheCommand($host,$port,'stats cachedump '.$slabId.' '.$limit); return $resp;}function flushServer($server){ list($host,$port) = explode(':',$server); $resp = sendMemcacheCommand($host,$port,'flush_all'); return $resp;}function getCacheItems(){ $items = sendMemcacheCommands('stats items'); $serverItems = array(); $totalItems = array(); foreach ($items as $server=>$itemlist){ $serverItems[$server] = array(); $totalItems[$server]=0; if (!isset($itemlist['STAT'])){ continue; } $iteminfo = $itemlist['STAT']; foreach($iteminfo as $keyinfo=>$value){ if (preg_match('/items\:(\d+?)\:(.+?)$/',$keyinfo,$matches)){ $serverItems[$server][$matches[1]][$matches[2]] = $value; if ($matches[2]=='number'){ $totalItems[$server] +=$value; } } } } return array('items'=>$serverItems,'counts'=>$totalItems);}function getMemcacheStats($total=true){ $resp = sendMemcacheCommands('stats'); if ($total){ $res = array(); foreach($resp as $server=>$r){ foreach($r['STAT'] as $key=>$row){ if (!isset($res[$key])){ $res[$key]=null; } switch ($key){ case 'pid': $res['pid'][$server]=$row; break; case 'uptime': $res['uptime'][$server]=$row; break; case 'time': $res['time'][$server]=$row; break; case 'version': $res['version'][$server]=$row; break; case 'pointer_size': $res['pointer_size'][$server]=$row; break; case 'rusage_user': $res['rusage_user'][$server]=$row; break; case 'rusage_system': $res['rusage_system'][$server]=$row; break; case 'curr_items': $res['curr_items']+=$row; break; case 'total_items': $res['total_items']+=$row; break; case 'bytes': $res['bytes']+=$row; break; case 'curr_connections': $res['curr_connections']+=$row; break; case 'total_connections': $res['total_connections']+=$row; break; case 'connection_structures': $res['connection_structures']+=$row; break; case 'cmd_get': $res['cmd_get']+=$row; break; case 'cmd_set': $res['cmd_set']+=$row; break; case 'get_hits': $res['get_hits']+=$row; break; case 'get_misses': $res['get_misses']+=$row; break; case 'evictions': $res['evictions']+=$row; break; case 'bytes_read': $res['bytes_read']+=$row; break; case 'bytes_written': $res['bytes_written']+=$row; break; case 'limit_maxbytes': $res['limit_maxbytes']+=$row; break; case 'threads': $res['rusage_system'][$server]=$row; break; } } } return $res; } return $resp;}////////////////////////////////////////////////////////// don't cache this page//header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1header("Cache-Control: post-check=0, pre-check=0", false);header("Pragma: no-cache"); // HTTP/1.0function duration($ts) { global $time; $years = (int)((($time - $ts)/(7*86400))/52.177457); $rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400)); $weeks = (int)(($rem)/(7*86400)); $days = (int)(($rem)/86400) - $weeks*7; $hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24; $mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60; $str = ''; if($years==1) $str .= "$years year, "; if($years>1) $str .= "$years years, "; if($weeks==1) $str .= "$weeks week, "; if($weeks>1) $str .= "$weeks weeks, "; if($days==1) $str .= "$days day,"; if($days>1) $str .= "$days days,"; if($hours == 1) $str .= " $hours hour and"; if($hours>1) $str .= " $hours hours and"; if($mins == 1) $str .= " 1 minute"; else $str .= " $mins minutes"; return $str;}// create graphics//function graphics_avail() { return extension_loaded('gd');}function bsize($s) { foreach (array('','K','M','G') as $i => $k) { if ($s < 1024) break; $s/=1024; } return sprintf("%5.1f %sBytes",$s,$k);}// create menu entryfunction menu_entry($ob,$title) { global $PHP_SELF; if ($ob==$_GET['op']){ return "
memcache memcache.php by Harun Yayli
EOB; return $header;}function getFooter(){ global $VERSION; $footer = '
'; return $footer;}function getMenu(){ global $PHP_SELF;echo " EOB;}// TODO, AUTH$_GET['op'] = !isset($_GET['op'])? '1':$_GET['op'];$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],'')) : '';$PHP_SELF=$PHP_SELF.'?';$time = time();// sanitize _GETforeach($_GET as $key=>$g){ $_GET[$key]=htmlentities($g);}// singleout// when singleout is set, it only gives details for that server.if (isset($_GET['singleout']) && $_GET['singleout']>=0 && $_GET['singleout'] $y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2); else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2); imagerectangle($im, $x, $y1, $x1, $y, $color1); if ($text) { if ($placeindex>0) { if ($placeindex<16) { $px=5; $py=$placeindex*12+6; imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2); imageline($im,$x,$y+$h/2,$px+90,$py,$color2); imagestring($im,2,$px,$py-6,$text,$color1); } else { if ($placeindex0) { imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1); imagestring($im,4,$diameter, $placeindex*12,$text,$color1); } else { imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1); } } } $size = GRAPH_SIZE; // image size $image = imagecreate($size+50, $size+10); $col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF); $col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30); $col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60); $col_black = imagecolorallocate($image, 0, 0, 0); imagecolortransparent($image,$col_white); switch ($_GET['IMG']){ case 1: // pie chart $tsize=$memcacheStats['limit_maxbytes']; $avail=$tsize-$memcacheStats['bytes']; $x=$y=$size/2; $angle_from = 0; $fuzz = 0.000001; foreach($memcacheStatsSingle as $serv=>$mcs) { $free = $mcs['STAT']['limit_maxbytes']-$mcs['STAT']['bytes']; $used = $mcs['STAT']['bytes']; if ($free>0){ // draw free $angle_to = ($free*360)/$tsize; $perc =sprintf("%.2f%%", ($free *100) / $tsize) ; fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_green,$perc); $angle_from = $angle_from + $angle_to ; } if ($used>0){ // draw used $angle_to = ($used*360)/$tsize; $perc =sprintf("%.2f%%", ($used *100) / $tsize) ; fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_red, '('.$perc.')' ); $angle_from = $angle_from+ $angle_to ; } } break; case 2: // hit miss $hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits']; $misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses']; $total = $hits + $misses ; fill_box($image, 30,$size,50,-$hits*($size-21)/$total,$col_black,$col_green,sprintf("%.1f%%",$hits*100/$total)); fill_box($image,130,$size,50,-max(4,($total-$hits)*($size-21)/$total),$col_black,$col_red,sprintf("%.1f%%",$misses*100/$total)); break; } header("Content-type: image/png"); imagepng($image); exit;}echo getHeader();echo getMenu();switch ($_GET['op']) { case 1: // host stats $phpversion = phpversion(); $memcacheStats = getMemcacheStats(); $memcacheStatsSingle = getMemcacheStats(false); $mem_size = $memcacheStats['limit_maxbytes']; $mem_used = $memcacheStats['bytes']; $mem_avail= $mem_size-$mem_used; $startTime = time()-array_sum($memcacheStats['uptime']); $curr_items = $memcacheStats['curr_items']; $total_items = $memcacheStats['total_items']; $hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits']; $misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses']; $sets = $memcacheStats['cmd_set']; $req_rate = sprintf("%.2f",($hits+$misses)/($time-$startTime)); $hit_rate = sprintf("%.2f",($hits)/($time-$startTime)); $miss_rate = sprintf("%.2f",($misses)/($time-$startTime)); $set_rate = sprintf("%.2f",($sets)/($time-$startTime)); echo <<< EOB
General Cache Information
PHP Version | $phpversion |
Memcached Host". ((count($MEMCACHE_SERVERS)>1) ? 's':'')." | "; $i=0; if (!isset($_GET['singleout']) && count($MEMCACHE_SERVERS)>1){ foreach($MEMCACHE_SERVERS as $server){ echo ($i+1).'. '.$server.' '; } } else{ echo '1.'.$MEMCACHE_SERVERS[0]; } if (isset($_GET['singleout'])){ echo '(all servers) '; } echo " |
Total Memcache Cache | ".bsize($memcacheStats['limit_maxbytes'])." |
Memcache Server Information
EOB; foreach($MEMCACHE_SERVERS as $server){ echo ''.$server.' | [Flush this serv本文来源gao@daima#com搞(%代@#码@网&搞gaodaima代码er] |
Start Time | ',date(DATE_FORMAT,$memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),' |
Uptime | ',duration($memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),' |
Memcached Server Version | '.$memcacheStatsSingle[$server]['STAT']['version'].' |
Used Cache Size | ',bsize($memcacheStatsSingle[$server]['STAT']['bytes']),' |
Total Cache Size | ',bsize($memcacheStatsSingle[$server]['STAT']['limit_maxbytes']),' |
Host Status Diagrams
Cache Usage | Hits & Misses |
". " | |
Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size)," | \n", 'Hits: ',$hits.sprintf(" (%.1f%%)",$hits*100/($hits+$misses))," | \n", '
Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size)," | \n", 'Misses: ',$misses.sprintf(" (%.1f%%)",$misses*100/($hits+$misses))," | \n"; echo <<< EOB
Cache Information
Current Items(total) | $curr_items ($total_items) |
Hits | {$hits} |
Misses | {$misses} |
Request Rate (hits, misses) | $req_rate cache requests/second |
Hit Rate | $hit_rate cache requests/second |
Miss Rate | $miss_rate cache requests/second |
Set Rate | $set_rate cache requests/second |
$server | |
---|---|
Slab Id | Info |
",'',$slabId,''," | ", "Item count: ",$slab['number'],' Age:',duration($time-$slab['age']),' Evicted:',((isset($slab['evicted']) && $slab['evicted']==1)? 'Yes':'No'); if ((isset($_GET['dumpslab']) && $_GET['dumpslab']==$slabId) && (isset($_GET['server']) && $_GET['server']==array_search($server,$MEMCACHE_SERVERS))){ echo " Items: item "; $items = dumpCacheSlab($server,$slabId,$slab['number']); // maybe someone likes to do a pagination here ![]() '; } elseif ($i!=$slab['number']+1){ echo ','; } } } echo " |
EOB;} break; break; case 4: //item dump if (!isset($_GET['key']) || !isset($_GET['server'])){ echo "No key set!"; break; } // I'm not doing anything to check the validity of the key string. // probably an exploit can be written to delete all the files in key=base64_encode("\n\r delete all"). // somebody has to do a fix to this. $theKey = htmlentities(base64_decode($_GET['key'])); $theserver = $MEMCACHE_SERVERS[(int)$_GET['server']]; list($h,$p) = explode(':',$theserver); $r = sendMemcacheCommand($h,$p,'get '.$theKey); echo <<<EOB
Server | Key | Value | Delete |
---|---|---|---|
",$theserver," | ",$theKey, " flag:",$r['VALUE'][$theKey]['stat']['flag'], " Size:",bsize($r['VALUE'][$theKey]['stat']['size']), " | ",chunk_split($r['VALUE'][$theKey]['value'],40)," | ", 'Delete | ","
EOB; break; case 5: // item delete if (!isset($_GET['key']) || !isset($_GET['server'])){ echo "No key set!"; break; } $theKey = htmlentities(base64_decode($_GET['key'])); $theserver = $MEMCACHE_SERVERS[(int)$_GET['server']]; list($h,$p) = explode(':',$theserver); $r = sendMemcacheCommand($h,$p,'delete '.$theKey); echo 'Deleting '.$theKey.':'.$r; break; case 6: // flush server $theserver = $MEMCACHE_SERVERS[(int)$_GET['server']]; $r = flushServer($theserver); echo 'Flush '.$theserver.":".$r; break;}echo getFooter();?>