mctop 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +11 -4
- data/bin/mctop +1 -0
- data/lib/cmdline.rb +7 -1
- data/lib/sniffer.rb +5 -3
- data/lib/ui.rb +20 -8
- data/mctop.gemspec +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -8,16 +8,18 @@ bandwidth.
|
|
8
8
|
You can read more detail about why this tool evovled over on our
|
9
9
|
[code as craft](http://codeascraft.etsy.com/2012/12/13/mctop-a-tool-for-analyzing-memcache-get-traffic) blog.
|
10
10
|
|
11
|
-
mctop depends on the [ruby-pcap](https://rubygems.org/gems/ruby-pcap) gem, if you don't have
|
12
|
-
this installed you'll need to ensure you have the development pcap libraries (libpcap-devel
|
11
|
+
mctop depends on the [ruby-pcap](https://rubygems.org/gems/ruby-pcap) gem, if you don't have
|
12
|
+
this installed you'll need to ensure you have the development pcap libraries (libpcap-devel
|
13
13
|
package on most linux distros) to build the native gem.
|
14
14
|
|
15
|
+
![](http://etsycodeascraft.files.wordpress.com/2012/12/mctop.jpg)
|
16
|
+
|
15
17
|
## How it works
|
16
18
|
|
17
19
|
mctop sniffs network traffic collecting memcache `VALUE` responses and calculates from
|
18
20
|
traffic statistics for each key seen. It currently reports on the following metrics per key:
|
19
21
|
|
20
|
-
* **calls** - the number of times the key has been called since mctop started
|
22
|
+
* **calls** - the number of times the key has been called since mctop started
|
21
23
|
* **objsize** - the size of the object stored for that key
|
22
24
|
* **req/sec** - the number of requests per second for the key
|
23
25
|
* **bw (kbps)** - the estimated netowrk bandwidth consumed by this key in kilobits-per-second
|
@@ -37,6 +39,7 @@ the quickest way to get it running is to:
|
|
37
39
|
|
38
40
|
Usage: mctop [options]
|
39
41
|
-i, --interface=NIC Network interface to sniff (required)
|
42
|
+
-p, --port=PORT Network port to sniff on (default 11211)
|
40
43
|
-d, --discard=THRESH Discard keys with request/sec rate below THRESH
|
41
44
|
-r, --refresh=MS Refresh the stats display every MS milliseconds
|
42
45
|
-h, --help Show usage info
|
@@ -61,8 +64,12 @@ The following details are displayed in the status bar
|
|
61
64
|
* `packets` - packets received and dropped by libpcap (% is percentage of packets dropped)
|
62
65
|
* `rt` - the time taken to sort and render the stats
|
63
66
|
|
67
|
+
## Changelog
|
68
|
+
|
69
|
+
* 2012-12-14 - Now compatible with Ruby 1.8.x (tested on 1.8.7-p371)
|
70
|
+
|
64
71
|
## Known issues / Gotchas
|
65
72
|
|
66
73
|
### ruby-pcap drops packets at high volume
|
67
|
-
from my testing the ruby-pcap native interface to libpcap struggles to keep up with high packet rates (in what we see on a production memcache instance) you can keep an eye on the packets recv/drop and loss percentage on the status bar at the bottom of the UI to get an idea of the packet
|
74
|
+
from my testing the ruby-pcap native interface to libpcap struggles to keep up with high packet rates (in what we see on a production memcache instance) you can keep an eye on the packets recv/drop and loss percentage on the status bar at the bottom of the UI to get an idea of the packet
|
68
75
|
|
data/bin/mctop
CHANGED
data/lib/cmdline.rb
CHANGED
@@ -10,15 +10,21 @@ class CmdLine
|
|
10
10
|
@config[:nic] = nic
|
11
11
|
end
|
12
12
|
|
13
|
+
opt.on('-p', '--port=PORT', 'Network port to sniff on (default 11211)') do |port|
|
14
|
+
@config[:port] = port
|
15
|
+
end
|
16
|
+
|
17
|
+
@config[:discard_thresh] = 0
|
13
18
|
opt.on '-d', '--discard=THRESH', Float, 'Discard keys with request/sec rate below THRESH' do |discard_thresh|
|
14
19
|
@config[:discard_thresh] = discard_thresh
|
15
20
|
end
|
16
21
|
|
22
|
+
@config[:refresh_rate] = 500
|
17
23
|
opt.on '-r', '--refresh=MS', Float, 'Refresh the stats display every MS milliseconds' do |refresh_rate|
|
18
24
|
@config[:refresh_rate] = refresh_rate
|
19
25
|
end
|
20
26
|
|
21
|
-
opt.on_tail '-h', '--help', 'Show usage info' do
|
27
|
+
opt.on_tail '-h', '--help', 'Show usage info' do
|
22
28
|
puts opts
|
23
29
|
exit
|
24
30
|
end
|
data/lib/sniffer.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'pcap'
|
2
|
+
require 'thread'
|
2
3
|
|
3
|
-
class MemcacheSniffer
|
4
|
+
class MemcacheSniffer
|
4
5
|
attr_accessor :metrics, :semaphore
|
5
6
|
|
6
7
|
def initialize(config)
|
7
8
|
@source = config[:nic]
|
9
|
+
@port = config.has_key?(:port) ? config[:port] : 11211
|
8
10
|
|
9
11
|
@metrics = {}
|
10
12
|
@metrics[:calls] = {}
|
@@ -18,12 +20,12 @@ class MemcacheSniffer
|
|
18
20
|
|
19
21
|
def start
|
20
22
|
cap = Pcap::Capture.open_live(@source, 1500)
|
21
|
-
|
23
|
+
|
22
24
|
@metrics[:start_time] = Time.new.to_f
|
23
25
|
|
24
26
|
@done = false
|
25
27
|
|
26
|
-
cap.setfilter(
|
28
|
+
cap.setfilter("port #{@port}")
|
27
29
|
cap.loop do |packet|
|
28
30
|
@metrics[:stats] = cap.stats
|
29
31
|
|
data/lib/ui.rb
CHANGED
@@ -4,12 +4,14 @@ include Curses
|
|
4
4
|
|
5
5
|
class UI
|
6
6
|
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
|
7
9
|
init_screen
|
8
10
|
cbreak
|
9
11
|
curs_set(0)
|
10
12
|
|
11
13
|
# set keyboard input timeout - sneaky way to manage refresh rate
|
12
|
-
Curses.timeout = config
|
14
|
+
Curses.timeout = @config[:refresh_rate]
|
13
15
|
|
14
16
|
if can_change_color?
|
15
17
|
start_color
|
@@ -22,9 +24,6 @@ class UI
|
|
22
24
|
@stat_col_width = 10
|
23
25
|
@key_col_width = 0
|
24
26
|
|
25
|
-
# we will delete any keys from the metrics table whose req/sec rate is below discard_rate
|
26
|
-
@discard_thresh = config.has_key?(:discard_thresh) ? config[:discard_thresh] : 0
|
27
|
-
|
28
27
|
@commands = {
|
29
28
|
'Q' => "quit",
|
30
29
|
'C' => "sort by calls",
|
@@ -63,7 +62,7 @@ class UI
|
|
63
62
|
|
64
63
|
# calculate packet loss ratio
|
65
64
|
if sniffer.metrics[:stats][:recv] > 0
|
66
|
-
loss = (sniffer.metrics[:stats][:drop].to_f / sniffer.metrics[:stats][:recv].to_f) * 100
|
65
|
+
loss = sprintf("%5.2f", (sniffer.metrics[:stats][:drop].to_f / sniffer.metrics[:stats][:recv].to_f) * 100)
|
67
66
|
else
|
68
67
|
loss = 0
|
69
68
|
end
|
@@ -74,7 +73,7 @@ class UI
|
|
74
73
|
header_summary = sprintf "%-28s %-14s %-30s",
|
75
74
|
"sort mode: #{sort_mode.to_s} (#{sort_order.to_s})",
|
76
75
|
"keys: #{sniffer.metrics[:calls].keys.count}",
|
77
|
-
"packets (recv/dropped): #{sniffer.metrics[:stats][:recv]} / #{sniffer.metrics[:stats][:drop]} (#{loss
|
76
|
+
"packets (recv/dropped): #{sniffer.metrics[:stats][:recv]} / #{sniffer.metrics[:stats][:drop]} (#{loss}%)"
|
78
77
|
addstr(sprintf "%-#{cols}s", header_summary)
|
79
78
|
|
80
79
|
# reset colours for main key display
|
@@ -95,7 +94,7 @@ class UI
|
|
95
94
|
# if req/sec is <= the discard threshold delete those keys from
|
96
95
|
# the metrics hash - this is a hack to manage the size of the
|
97
96
|
# metrics hash in high volume environments
|
98
|
-
if reqsec <= @discard_thresh
|
97
|
+
if reqsec <= @config[:discard_thresh]
|
99
98
|
sniffer.metrics[:calls].delete(k)
|
100
99
|
sniffer.metrics[:objsize].delete(k)
|
101
100
|
sniffer.metrics[:reqsec].delete(k)
|
@@ -151,7 +150,20 @@ class UI
|
|
151
150
|
end
|
152
151
|
|
153
152
|
def input_handler
|
154
|
-
getch
|
153
|
+
# Curses.getch has a bug in 1.8.x causing non-blocking
|
154
|
+
# calls to block reimplemented using IO.select
|
155
|
+
if RUBY_VERSION =~ /^1.8/
|
156
|
+
refresh_secs = @config[:refresh_rate].to_f / 1000
|
157
|
+
|
158
|
+
if IO.select([STDIN], nil, nil, refresh_secs)
|
159
|
+
c = getch
|
160
|
+
c.chr
|
161
|
+
else
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
else
|
165
|
+
getch
|
166
|
+
end
|
155
167
|
end
|
156
168
|
|
157
169
|
def done
|
data/mctop.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = "mctop"
|
7
|
-
gem.version = "0.0.
|
7
|
+
gem.version = "0.0.4"
|
8
8
|
gem.authors = ["Marcus Barczak"]
|
9
9
|
gem.email = ["marcus@etsy.com"]
|
10
10
|
gem.description = %q{mctop - a realtime memcache key analyzer}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mctop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ruby-pcap
|