Last active
November 17, 2020 06:33
-
-
Save hiroara/5c776b3b5731fc258a3cd879d1b345c4 to your computer and use it in GitHub Desktop.
Analyze Redis data usage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'csv' | |
class Level | |
attr_reader :key, :parent, :bytesize, :total_bytesize, :children | |
def initialize parent, key, bytesize = 0 | |
@parent = parent | |
@key = key | |
@bytesize = bytesize | |
@total_bytesize = bytesize | |
@children = {} | |
end | |
def eql? other | |
other.is_a?(Level) && other.key == self.key | |
end | |
def hash | |
self.key.hash * 3 + 13 | |
end | |
def full_key | |
self.parent.full_key + ":#{self.key}" | |
end | |
def to_str | |
"<Item##{self.full_key} total_bytesize=#{self.total_bytesize}>" | |
end | |
alias to_s to_str | |
def add child | |
if self.children.key? child.key | |
self.children[child.key].bytesize = child.bytesize | |
return self.children[child.key] | |
end | |
self.children[child.key] = child.tap { |ch| add_bytesize ch.total_bytesize } | |
end | |
alias << add | |
def print_tree output, indent: 0, depth: nil, threshold: nil | |
output.puts "#{self.key || '<root>'}: #{self.total_bytesize}#{" (#{self.bytesize})" if self.bytesize > 0}" | |
return if !depth.nil? && depth <= 0 | |
options = { indent: indent + 1, depth: depth.nil? ? nil : depth - 1, threshold: threshold } | |
self.children.values.lazy | |
.select { |child| threshold.nil? || child.total_bytesize >= threshold } | |
.each do |child| | |
output.print "#{' ' * indent}|- " | |
child.print_tree(output, **options) | |
end | |
end | |
def bytesize= value | |
diff = value - self.bytesize | |
@bytesize = value | |
self.add_bytesize diff | |
end | |
protected | |
def add_bytesize bytesize | |
@total_bytesize += bytesize | |
self.parent.add_bytesize bytesize if self.parent | |
end | |
end | |
root = Level.new nil, nil | |
# ARGF should be a file generated with redis-rdb-tools with `-c memory` option. | |
# See: https://github.com/sripathikrishnan/redis-rdb-tools/tree/548b11ec3c81a603f5b321228d07a61a0b940159#generate-memory-report | |
CSV.new(ARGF, headers: true).each_with_index do |row| | |
cursor = root | |
tokens = row['key'].split(':') | |
item_token = tokens.pop | |
tokens.each { |token| cursor = cursor.add(Level.new(cursor, token)) } | |
cursor << Level.new(cursor, item_token, row['size_in_bytes'].to_i) | |
end | |
root.print_tree STDOUT, threshold: 1024**2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment