はじめに
memcached でキーの一覧を取得するのは面倒だ。
- telnet コマンドで接続する。
-
stats items
で存在する slab 番号を調べる。 - キーが存在しそうな slab 番号で
stats cachedump
を実行する。
ということをやらないといけない。
Perl で書かれた memcached-tool の dump を使うという手もある。しかし、この記事ではお手製の Ruby スクリプトで取得してみる。
コード
list_memcached_keys
#! /usr/bin/env ruby
require 'bundler/inline'
# 必要な Gem をインストールする。
gemfile do
source 'https://rubygems.org'
gem 'net-telnet'
gem 'terminal-table'
end
class Item
attr_reader :slab_no, :key, :bytesize
def initialize(slab_no, key, bytesize, expires_at)
@slab_no = slab_no
@key = key
@bytesize = bytesize.to_i
@expires_at = expires_at.to_i
end
# UNIX 時間を Time オブジェクトに変換する。
def expires_at
return nil if @expires_at.zero?
Time.at(@expires_at)
end
end
require 'optparse'
require 'net/telnet'
require 'terminal-table'
# コマンドライン引数で host と port を指定できるようにする。
options = { host: 'localhost', port: 11211 }
OptionParser.new do |opt|
opt.on('--host=[VALUE]') { |v| options[:host] = v }
opt.on('--port=[VALUE]') { |v| options[:port] = v }
opt.parse!(ARGV)
end
def get_items(host, port)
localhost = nil
begin
localhost = Net::Telnet.new('Host' => host, 'Port' => port, 'Prompt' => /^END$/)
slab_nos = localhost.cmd('stats items').scan(/(?<=^STAT items:)\d+/).uniq.map(&:to_i)
items = slab_nos.flat_map do |slab_no|
results = localhost.cmd("stats cachedump #{slab_no} 1000").scan(/^ITEM (\w+) \[(\d+) b; (\d+) s\]/)
results.map { |result| Item.new(slab_no, *result) }
end
items
ensure
localhost&.close
end
end
def build_table_rows(items)
items.map do |item|
[
item.slab_no,
item.key,
item.bytesize,
item.expires_at&.strftime('%Y/%m/%d %H:%M:%S')
]
end
end
items = get_items(options[:host], options[:port])
headings = ['slab no', 'key', 'size (byte)', 'expires at']
rows = build_table_rows(items)
# terminal-table を使って、結果を表形式で標準出力に出力する。
table = Terminal::Table.new(headings: headings, rows: rows)
puts(table)
実行例
Ruby の memcached クライアントである Dalli を使って値を set し、さきほどの Ruby スクリプトを実行してみる。
$ ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin18]
require 'dalli'
require 'securerandom'
client = Dalli::Client.new('localhost:11211')
client.set('author', '村上 春樹')
client.set('sentence', '完璧な文章などといったものは存在しない。完璧な絶望が存在しないようにね。')
client.set('very_long_string', SecureRandom.hex(100_000), 60)
$ chmod +x list_memcached_keys
$ ./list_memcached_keys
+---------+------------------+-------------+---------------------+
| slab no | key | size (byte) | expires at |
+---------+------------------+-------------+---------------------+
| 1 | author | 23 | |
| 4 | sentence | 118 | |
| 35 | very_long_string | 200013 | 2020/01/11 12:48:36 |
+---------+------------------+-------------+---------------------+
CLI にテーブル形式で出力するのに tj/terminal-table いいぞ 😎