1
0

More than 3 years have passed since last update.

[Ruby] memcached のキー一覧を表示する

Last updated at Posted at 2020-01-11

はじめに

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 いいぞ 😎

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0