diff options
Diffstat (limited to 'src/pmdas/memcache/pmdamemcache.pl')
-rw-r--r-- | src/pmdas/memcache/pmdamemcache.pl | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/src/pmdas/memcache/pmdamemcache.pl b/src/pmdas/memcache/pmdamemcache.pl new file mode 100644 index 0000000..de232b2 --- /dev/null +++ b/src/pmdas/memcache/pmdamemcache.pl @@ -0,0 +1,307 @@ +# +# Copyright (c) 2012 Red Hat. +# Copyright (c) 2008 Aconex. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# The memcached PMDA +# NOTE: Not all metrics are exported at the moment, in particular, +# the per-slab and per-item statistics are not. It may be better to +# manage instances differently as these values are dynamic - perhaps +# have the monitored memcaches (the current indom) in the namespace, +# like the old DBMS PMDAs. +# +use strict; +use warnings; +use PCP::PMDA; +use vars qw( $pmda $id $n %caches ); + +my $memcache_delay = 5; # refresh rate in seconds +my @memcache_instances = ( 0 => '127.0.0.1:11211', + # 1 => '127.0.0.1:11212', + # 2 => '192.168.5.76:11211', + ); +# Configuration files for overriding the above settings +for my $file ( pmda_config('PCP_PMDAS_DIR') . '/memcache/memcache.conf', + './memcache.conf' ) { + eval `cat $file` unless ! -f $file; +} + +my $memcache_indom = 0; # one for each memcached +my $query = "stats\r\nstats slabs\r\nstats items\r\n"; # sent to memcached + +sub memcache_stats_callback +{ + ( $id, $_ ) = @_; + # $pmda->log("memcache_stats_callback: id $id"); + + if (/^STAT items:(\d+):(\w+) (\d+)/) { # stats items + # $caches{$id}{"item$1"}{$2} = $3; + } + elsif (/^STAT (\d+):(\w+) (\d+)/) { # stats slabs + # $caches{$id}{"slab$1"}{$2} = $3; + } + elsif (/^STAT (\w+) (\d+)/) { # stats + $caches{$id}{$1} = $2; + } + elsif (!(/^END/)) { # unknown + $pmda->log("Eh?: $_"); + } +} + +sub memcache_connect +{ + # $pmda->log("memcache_connect: $#memcache_instances"); + + for ($id = 0; $id < $#memcache_instances; $id += 2) { + my ($host, $port) = split(/:/, $memcache_instances[$id+1]); + $pmda->add_sock($host, $port, \&memcache_stats_callback, $id); + } +} + +sub memcache_timer_callback +{ + # $pmda->log("memcache_timer_callback"); + + for ($id = 0; $id < $#memcache_instances; $id += 2) { + $pmda->put_sock($id, $query); + } +} + +sub memcache_fetch_callback +{ + my ($cluster, $item, $inst) = @_; + + # $pmda->log("memcache_fetch_callback: $cluster:$item ($inst)"); + + return (PM_ERR_INST, 0) unless ($inst != PM_IN_NULL); + return (PM_ERR_INST, 0) unless ($inst < $#memcache_instances); + $id = $memcache_instances[$inst]; + return (PM_ERR_AGAIN, 0) unless defined($caches{$id}); + + if ($cluster == 0) { + if ($item == 0) { return ($caches{$id}{'pid'}, 1); } + elsif ($item == 1) { return ($caches{$id}{'uptime'}, 1); } + elsif ($item == 2) { return ($caches{$id}{'curr_items'}, 1); } + elsif ($item == 3) { return ($caches{$id}{'total_items'}, 1); } + elsif ($item == 4) { return ($caches{$id}{'bytes'}, 1); } + elsif ($item == 5) { return ($caches{$id}{'curr_connections'}, 1); } + elsif ($item == 6) { return ($caches{$id}{'total_connections'}, 1); } + elsif ($item == 7) { return ($caches{$id}{'connection_structures'}, 1); } + elsif ($item == 8) { return ($caches{$id}{'cmd_get'}, 1); } + elsif ($item == 9) { return ($caches{$id}{'cmd_set'}, 1); } + elsif ($item == 10) { return ($caches{$id}{'get_hits'}, 1); } + elsif ($item == 11) { return ($caches{$id}{'get_misses'}, 1); } + elsif ($item == 12) { return ($caches{$id}{'bytes_read'}, 1); } + elsif ($item == 13) { return ($caches{$id}{'bytes_written'}, 1); } + elsif ($item == 14) { return ($caches{$id}{'limit_maxbytes'}, 1); } + } +# elsif ($cluster == 1) { +# # many different slabs (X..Y), and 7 metrics in this cluster +# if ($item > 7 * 11) { return (PM_ERR_PMID, 0); } +# $id = int($item / 7) + 6; +# $item %= 7; +# my $slab = "slab$id"; +# +# return (PM_ERR_AGAIN, 0) unless defined($caches{$id}{$slab}); +# if ($item == 0) { return ($caches{$id}{$slab}{'chunk_size'}, 1); } +# elsif ($item == 1) { return ($caches{$id}{$slab}{'chunks_per_page'}, 1); } +# elsif ($item == 2) { return ($caches{$id}{$slab}{'total_pages'}, 1); } +# elsif ($item == 3) { return ($caches{$id}{$slab}{'total_chunks'}, 1); } +# elsif ($item == 4) { return ($caches{$id}{$slab}{'used_chunks'}, 1); } +# elsif ($item == 5) { return ($caches{$id}{$slab}{'free_chunks'}, 1); } +# elsif ($item == 6) { return ($caches{$id}{$slab}{'free_chunks_end'}, 1); } +# } + elsif ($cluster == 2) { + if ($item == 0) { return ($caches{$id}{'active_slabs'}, 1); } + elsif ($item == 1) { return ($caches{$id}{'total_malloced'}, 1); } + } +# elsif ($cluster == 3) { +# # many different slabs (X..Y), and 2 metrics in this cluster +# if ($item > 2 * [Y]) { return (PM_ERR_PMID, 0); } +# $id = int($item / 2) + [X]; +# $item %= 2; +# my $itemid = "item$id"; +# +# return (PM_ERR_AGAIN, 0) unless defined($caches{$id}{$itemid}); +# if ($item == 0) { return ($caches{$id}{$itemid}{'count'}, 1); } +# elsif ($item == 1) { return ($caches{$id}{$itemid}{'age'}, 1); } +# } + return (PM_ERR_PMID, 0); +} + +$pmda = PCP::PMDA->new('memcache', 89); + +$pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, $memcache_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'memcache.pid', '', ''); +$pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U32, $memcache_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'memcache.uptime', '', ''); +$pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, $memcache_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'memcache.current_items', '', ''); +$pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, $memcache_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'memcache.total_items', '', ''); +$pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U64, $memcache_indom, + PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), + 'memcache.bytes', '', ''); +$pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U32, $memcache_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'memcache.current_connections', '', ''); +$pmda->add_metric(pmda_pmid(0,6), PM_TYPE_U32, $memcache_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'memcache.total_connections', '', ''); +$pmda->add_metric(pmda_pmid(0,7), PM_TYPE_U32, $memcache_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'memcache.connection_structures', '', ''); +$pmda->add_metric(pmda_pmid(0,8), PM_TYPE_U32, $memcache_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'memcache.gets', '', ''); +$pmda->add_metric(pmda_pmid(0,9), PM_TYPE_U32, $memcache_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'memcache.sets', '', ''); +$pmda->add_metric(pmda_pmid(0,10), PM_TYPE_U32, $memcache_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'memcache.hits', '', ''); +$pmda->add_metric(pmda_pmid(0,11), PM_TYPE_U32, $memcache_indom, + PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), + 'memcache.misses', '', ''); +$pmda->add_metric(pmda_pmid(0,12), PM_TYPE_U64, $memcache_indom, + PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), + 'memcache.bytes_read', '', ''); +$pmda->add_metric(pmda_pmid(0,13), PM_TYPE_U64, $memcache_indom, + PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), + 'memcache.bytes_written', '', ''); +$pmda->add_metric(pmda_pmid(0,14), PM_TYPE_U32, $memcache_indom, + PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), + 'memcache.limit_maxbytes', '', ''); +# $id = 0; +# foreach $n (6 .. 17) { # stats slabs (N=6-17) +# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, +# PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), +# "memcache.slabs.slab$n.chunk_size", '', ''); +# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, +# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), +# "memcache.slabs.slab$n.chunks_per_page", '', ''); +# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, +# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), +# "memcache.slabs.slab$n.total_pages", '', ''); +# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, +# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), +# "memcache.slabs.slab$n.total_chunks", '', ''); +# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, +# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), +# "memcache.slabs.slab$n.used_chunks", '', ''); +# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, +# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), +# "memcache.slabs.slab$n.free_chunks", '', ''); +# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, +# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), +# "memcache.slabs.slab$n.free_chunks_end", '', ''); +# } + +$pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U32, $memcache_indom, + PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), + 'memcache.active_slabs', '', ''); +$pmda->add_metric(pmda_pmid(2,1), PM_TYPE_U32, $memcache_indom, + PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), + 'memcache.total_malloced', '', ''); + +# $id = 0; +# foreach $n (6 .. 17) { # stats items (N=6-17) +# $pmda->add_metric(pmda_pmid(3,$id++), PM_TYPE_U32, $memcache_indom, +# PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), +# "memcache.items.item$n.count", '', ''); +# $pmda->add_metric(pmda_pmid(3,$id++), PM_TYPE_U32, $memcache_indom, +# PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), +# "memcache.items.item$n.age", '', ''); +# } + +$pmda->add_indom($memcache_indom, \@memcache_instances, + 'Instance domain exporting each memcache daemon', ''); + +$pmda->add_timer($memcache_delay, \&memcache_timer_callback, 0); +$pmda->set_fetch_callback(\&memcache_fetch_callback); + +&memcache_connect; +&memcache_timer_callback; + +$pmda->set_user('pcp'); +$pmda->run; + +=pod + +=head1 NAME + +pmdamemcache - memcache performance metrics domain agent (PMDA) + +=head1 DESCRIPTION + +This PMDA extracts performance data from memcached, a distributed memory +caching daemon commonly used to improve web serving performance. A farm +of memcached processes over multiple servers can be utilised by a single +web application, increasing the total available object cache size, and +decreasing the database load associated with smaller cache sizes. This +system is described in detail at http://www.danga.com/memcached. + +=head1 INSTALLATION + +Configure B<pmdamemcache> to extract the values from set of hosts +used in the memcache farm. These hosts can be listed in the +$PCP_PMDAS_DIR/memcache/memcache.conf file, in the format (i.e. +Perl array) described at the top of pmdamemcache.pl. A custom +refresh rate can also be configured using this mechanism. + + # cd $PCP_PMDAS_DIR/memcache + # [ edit memcache.conf ] + +Once this is setup, you can access the names and values for the +memcache performance metrics by doing the following as root: + + # cd $PCP_PMDAS_DIR/memcache + # ./Install + +If you want to undo the installation, do the following as root: + + # cd $PCP_PMDAS_DIR/memcache + # ./Remove + +B<pmdamemcache> is launched by pmcd(1) and should never be executed +directly. The Install and Remove scripts notify pmcd(1) when +the agent is installed or removed. + +=head1 FILES + +=over + +=item $PCP_PMDAS_DIR/memcache/memcache.conf + +configuration file listing monitored memcache instances + +=item $PCP_PMDAS_DIR/memcache/Install + +installation script for the B<pmdamemcache> agent + +=item $PCP_PMDAS_DIR/memcache/Remove + +undo installation script for the B<pmdamemcache> agent + +=item $PCP_LOG_DIR/pmcd/memcache.log + +default log file for error messages from B<pmdamemcache> + +=back + +=head1 SEE ALSO + +pmcd(1) and memcached(1). |