redis 内存分析工具 rma4go 简介

redis是一个很有名的内存型数据库,这里不做详细介绍。而rma4go (redis memory analyzer for golang) 是一个redis的内存分析工具,这个工具的主要作用是针对运行时期的redis进行内存的分析,统计redis中key的分布情况, 各种数据类型的使用情况,key的size,大key的数量及分布, key的过期状况分布等一些有助于定位redis使用问题的工具,希望这能够给应用开发者提供便利排查生产中所遇到的实际问题。

rma4go的应用场景

redis是目前很流行的一个内存型数据库,很多企业都在使用。 但由于业界并没有很多对于redis使用上的规范,或者是有一些规范并没有被很好的遵循, 存在很多redis使用上的问题,我这边就列举一些例子:

  1. redis 存用满了, 不知道key的分布情况,不知道来源于那个应用
  2. redis 被block了,不知道什么原因导致的block,是哪个应用里的什么key的操作导致的
  3. 想迁移redis数据,或者调整一些设置,但不知道要不要对redis里的数据进行保留,以及不知道什么业务在使用等
  4. redis的key的过期情况不明朗, 不知道哪些东西可以删除或者调整 其实上面的一些问题是我随便列举出来的一些,并不是所有的存在的问题,相信也有很多其他场景同样会用到这样的一个redis内存分析工具rma4go

rma4go的具体功能

数据维度

对于key的分析我们这个工具会提供如下几个维度的数据:

  • key的数量分布维度
  • key的过期分布维度
  • key的类型分布维度
  • key对应的的数据的大小分布维度
  • key的前缀分布维度
  • 慢key与大key的维度

当然以后如果发现有更好的纬度也会添加进去,目前先以这几个纬度为主

数据类型设计

type RedisStat struct {All     KeyStat `json:"all"`String  KeyStat `json:"string"`Hash    KeyStat `json:"hash"`Set     KeyStat `json:"set"`List    KeyStat `json:"list"`ZSet    KeyStat `json:"zset"`Other   KeyStat `json:"other"`BigKeys KeyStat `json:"bigKeys"`
}// distributions of keys of all prefixes
type Distribution struct {KeyPattern string `json:"pattern"`Metrics
}// basic metrics of a group of key
type Metrics struct {KeyCount       int64 `json:"keyCount"`KeySize        int64 `json:"keySize"`DataSize       int64 `json:"dataSize"`KeyNeverExpire int64 `json:"neverExpire"`ExpireInHour   int64 `json:"expireInHour"`  // >= 0h < 1hExpireInDay    int64 `json:"expireInDay"`   // >= 1h < 24hExpireInWeek   int64 `json:"expireInWeek"`  // >= 1d < 7dExpireOutWeek  int64 `json:"expireOutWeek"` // >= 7d
}复制代码

实现细节

key元信息

type KeyMeta struct {Key      stringKeySize  int64DataSize int64Ttl      int64Type     string
}复制代码

众所周知, redis里的所有的数据基本都是由key的, 也是根据key进行操作的,那么对redis里的key进行分析我们必须要记录下来这个key的信息才可以做到, 我们能记录的信息正如以上结构中的一样, key本身, key的大小, 数据的大小, 过期时间以及key的类型。这些信息是我们对key进行分析的一个基础信息,都可以通过一些简单的redis命令就可以取到。

遍历redis所有key

要对一个redis进行完整的key分析, 我们就需要有办法能够访问到所有key的源信息, 所幸redis提供了 scan这么一种方式可以比较轻量的遍历所有的key,访问到相应的key的元信息。 这样对于redis而言, 进行在线key分析的时候造成的压力也不会非常大,当然key分析不能再QPS高峰期进行, 需要在redis资源余量允许的情况下进行分析。

另外由于redis本身的一个内存清理机制,有25%的过期占用可以在分析key的时候被清理掉, 因此这个分析工具同时兼具了清理一部分内存的作用, 如果redis里面存在过期的而且存在于内存里面的key的话。

对记录的信息进行分析与汇总

有了遍历所有key的方法, 又有了元数据, 剩下的事情就是把这些数据进行聚合汇总, 这个主要是一个算法上的工作, 最难的部分要数这个key聚合的部分了, 这里面有很多取舍, 由于作者我本人不是专攻算法的, 而且没有找到合适的库, 因此只能动手自己想了一种方式。 基本的思路是:

压缩的算法
  1. 对于每个新的key的元信息, 添加到老的key分析对象里去
  2. 对这个key从后往前缩短, 去除尾部,看是否已经包含这个key的统计信息,如果包含, 则把key的信息累加上去, 如果不包含则创建一个新的纪录。
  3. 当记录的个数添加到一定数量的时候, 对对象的个数进行一次压缩
    • 压缩的算法也是从字符串的末尾往字符串首部进行压缩
    • 当压缩不能增加这个pattern 的key的个数的时候使用原来的key(压缩前的key)
    • 当压缩可以增加这个pattern的key的个数的时候,进行key的合并,把pattern设置成压缩后的pattern
    • 当记录的条数超过指定的条数就循环往复,直到压缩到小于指定的条数为止
    • 如果对于key的最小长度(就算再压缩也要保留一两位)有要求, 有一些压缩到字符串的最小长度的参数可以进行调整与设置, 进行一定的取舍。
  4. 直到scan完毕
代码如下
const (defaultSize = 128compactNum  = 30maxLeftNum =  150minKeyLenLower = 2minKeyLen   = 5
)func (stat *KeyStat) compact() {distMap := stat.DistributiontmpMap := make(map[string][]string, defaultSize)shrinkTo := compactNumfor k := range distMap {compactedKey := kif orgks, ok := tmpMap[compactedKey]; ok {orgks = append(orgks, k)tmpMap[compactedKey] = orgks} else {ks := make([]string, 0, defaultSize)ks = append(ks, k)tmpMap[compactedKey] = ks}}shrinkTo--for (len(tmpMap) > compactNum && shrinkTo >= minKeyLen) || (len(tmpMap) > maxLeftNum && shrinkTo >= minKeyLenLower) {tnMap := make(map[string][]string, defaultSize)for k := range tmpMap {// shrinkif len(k) > shrinkTo {compactedKey := k[0:shrinkTo]if oik, ok := tnMap[compactedKey]; ok {oik = append(oik, tmpMap[k]...)tnMap[compactedKey] = oik} else {ks := make([]string, 0, defaultSize)ks = append(ks, tmpMap[k]...)tnMap[compactedKey] = ks}} else {tnMap[k] = tmpMap[k]}}// 如果此次shrink 没有使得这个集合的元素数量增加, 就使用原来的keyfor k := range tmpMap {if len(k) > shrinkTo {ck := k[0:shrinkTo]if len(tnMap[ck]) == len(tmpMap[k]) && len(tnMap[ck]) > 1 {x := make([]string, 0, defaultSize)tnMap[k] = append(x, tnMap[ck]...)delete(tnMap, ck)}}}tmpMap = tnMapshrinkTo --}dists := make(map[string]Distribution, defaultSize)for k, v := range tmpMap {if len(v) > 1 {var nd Distributionfor _, dk := range v {d := distMap[dk]nd.KeyPattern = k + "*"nd.KeyCount += d.KeyCountnd.KeySize += d.KeySizend.DataSize += d.DataSizend.ExpireInHour += d.ExpireInHournd.ExpireInWeek += d.ExpireInWeeknd.ExpireInDay += d.ExpireInDaynd.ExpireOutWeek += d.ExpireOutWeeknd.KeyNeverExpire += d.KeyNeverExpire}dists[k] = nd} else {for _, dk := range v {nd := distMap[dk]nd.KeyPattern = dk + "*"dists[dk] = nd}}}stat.Distribution = dists
}复制代码

在线key分析的github项目

rma4go

github.com/winjeg/rma4…

这是一个我已经写好的项目, 它使用起来非常简单, 二进制包已经准备好, 大家可以点以下链接下载 Linux MAC

构建方法

  1. 构建之前请确保golang sdk 已经安装, 并且版本 >=1.11.0
  2. 请确保已经具备翻墙的环境, 因为它要下载一些依赖,可能来自墙外 翻墙方法如下
// linux/osx
export http_proxy=somehost:port
export https_proxy=somehost:port
// windows
set http_proxy=somehost:port
set https_proxy=somehost:port复制代码
  1. 构建
git clone git@github.com:winjeg/rma4go.git
cd rma4go
go build .
复制代码

使用方法

用法如下:rma4go -h

rma4go usage:
rma4go -r some_host -p 6379 -a password -d 0
======================================================-H stringaddress of a redis (default "localhost")-a stringpassword/auth of the redis-d intdb of the redis to analyze-h    help content-p intport of the redis (default 6379)-r stringaddress of a redis (default "localhost")
复制代码

示例输出

all keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
string keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
list keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
hash keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
set keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
zset keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
other keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |
big keys statistics| PATTERN | KEY NUM | KEY SIZE | DATA SIZE | EXPIRE IN HOUR | EXPIRE IN DAY | EXPIRE IN WEEK | EXPIRE OUT WEEK | NEVER EXPIRE |
|---------|---------|----------|-----------|----------------|---------------|----------------|-----------------|--------------|
| total   |       0 |        0 |         0 |              0 |             0 |              0 |               0 |            0 |复制代码

rendered by markdown total count 4004

all keys statistics

PATTERN KEY NUM KEY SIZE DATA SIZE EXPIRE IN HOUR EXPIRE IN DAY EXPIRE IN WEEK EXPIRE OUT WEEK NEVER EXPIRE
TOP_TEN_NEW_XXXXXXXX* 1 20 1529 0 0 0 0 1
XXXXXXXXXXXXXX_STATISTICS_MIGRATION_LIST* 1 40 7692832 0 0 0 0 1
time-root:* 23 272 299 0 0 0 0 23
DS_AXXXXXXXX_CORRECT* 2 45 46 0 0 0 0 2
time-2* 761 7528 9893 0 0 0 0 761
time-level:* 537 8461 6981 0 0 0 0 537
time-9* 102 901 1326 0 0 0 0 102
time-7* 153 1372 1989 0 0 0 0 153
DS_MAGIC_SUCC_2017-06-22* 1 24 415 0 0 0 0 1
tersssss* 5 124 0 0 0 0 0 5
appoint_abcdefg_msgid* 1 21 0 0 0 0 0 1
BUSSINESSXXXXXXX_STATISTICS_NEED_CALC_RECENT* 1 44 1 0 0 0 0 1
switch_abcd_abcde* 3 69 3 0 0 0 0 3
abcdeferCounter_201* 3 78 0 0 0 0 0 3
diy1234567flag* 1 14 1 0 0 0 0 1
DS_PRXXBCD_LIST* 1 15 17208 0 0 0 0 1
time-4* 133 1194 1729 0 0 0 0 133
datastatistics_switch_version0* 1 30 1 0 0 0 0 1
register_count_2_201* 592 15984 640 0 0 0 0 592
canVisitNewabcdef1234PageLevels* 1 31 0 0 0 0 0 1
YOUR_WEEK_VITALITY_INFO* 1 23 75782 0 0 0 0 1
time-8* 101 894 1313 0 0 0 0 101
EXPERTS_APPOINT_INFO_MAP* 1 24 0 0 0 0 0 1
time-3* 130 1215 1690 0 0 0 0 130
time-1* 943 9456 12259 0 0 0 0 943
time-64* 87 781 1131 0 0 0 0 87
time-5* 168 1516 2184 0 0 0 0 168
total 4004 53422 7832490 0 0 0 0 4004

string keys statistics

PATTERN KEY NUM KEY SIZE DATA SIZE EXPIRE IN HOUR EXPIRE IN DAY EXPIRE IN WEEK EXPIRE OUT WEEK NEVER EXPIRE
BUSSINESSXXXXXXX_STATISTICS_NEED_CALC_RECENT* 1 44 1 0 0 0 0 1
time-5* 130 1174 1690 0 0 0 0 130
datastatistics_switch_version0* 1 30 1 0 0 0 0 1
time-7* 39 348 507 0 0 0 0 39
time-level:* 567 8939 7371 0 0 0 0 567
diy1234567flag* 1 14 1 0 0 0 0 1
switch_abcd_abcde* 3 69 3 0 0 0 0 3
time-2* 598 5918 7774 0 0 0 0 598
time-6* 125 1118 1625 0 0 0 0 125
time-4* 136 1225 1768 0 0 0 0 136
time-8* 72 636 936 0 0 0 0 72
time-1* 1176 11814 15288 0 0 0 0 1176
time-9* 100 880 1300 0 0 0 0 100
time-root:* 23 272 299 0 0 0 0 23
register_count_2_201* 592 15984 640 0 0 0 0 592
DS_AXXXXXXXX_CORRECT* 1 20 20 0 0 0 0 1
TOP_TEN_NEW_tersssss* 1 20 1529 0 0 0 0 1
time-3* 202 1925 2626 0 0 0 0 202
total 3989 53042 46253 0 0 0 0 3989

list keys statistics

PATTERN KEY NUM KEY SIZE DATA SIZE EXPIRE IN HOUR EXPIRE IN DAY EXPIRE IN WEEK EXPIRE OUT WEEK NEVER EXPIRE
XXXXXXXXXXXXXX_STATISTICS_MIGRATION_LIST* 1 40 7692832 0 0 0 0 1
DS_MAGIC_SUCC_2017-06-22* 1 24 415 0 0 0 0 1
DS_PRXXBCD_LIST* 1 15 17208 0 0 0 0 1
total 3 79 7710455 0 0 0 0 3

hash keys statistics

PATTERN KEY NUM KEY SIZE DATA SIZE EXPIRE IN HOUR EXPIRE IN DAY EXPIRE IN WEEK EXPIRE OUT WEEK NEVER EXPIRE
tersssss_action_prepage_new* 1 27 0 0 0 0 0 1
YOUR_WEEK_VITALITY_INFO* 1 23 75782 0 0 0 0 1
EXPERTS_APPOINT_INFO_MAP* 1 24 0 0 0 0 0 1
abcdeferCounter_2017-06-11* 1 26 0 0 0 0 0 1
tersssssHardTaskCounter* 1 23 0 0 0 0 0 1
abcdeferCounter_2018-04-27* 1 26 0 0 0 0 0 1
abcdeferCounter_2017-09-01* 1 26 0 0 0 0 0 1
tersssssEasyTaskCounter* 1 23 0 0 0 0 0 1
total 8 198 75782 0 0 0 0 8

set keys statistics

PATTERN KEY NUM KEY SIZE DATA SIZE EXPIRE IN HOUR EXPIRE IN DAY EXPIRE IN WEEK EXPIRE OUT WEEK NEVER EXPIRE
tersssss_bind_phone_phone* 1 25 0 0 0 0 0 1
appoint_abcdefg_msgid* 1 21 0 0 0 0 0 1
canVisitNewabcdef1234PageLevels* 1 31 0 0 0 0 0 1
tersssss_bind_phone_userid* 1 26 0 0 0 0 0 1
total 4 103 0 0 0 0 0 4

zset keys statistics

PATTERN KEY NUM KEY SIZE DATA SIZE EXPIRE IN HOUR EXPIRE IN DAY EXPIRE IN WEEK EXPIRE OUT WEEK NEVER EXPIRE
total 0 0 0 0 0 0 0 0

other keys statistics

PATTERN KEY NUM KEY SIZE DATA SIZE EXPIRE IN HOUR EXPIRE IN DAY EXPIRE IN WEEK EXPIRE OUT WEEK NEVER EXPIRE
total 0 0 0 0 0 0 0 0

big keys statistics

PATTERN KEY NUM KEY SIZE DATA SIZE EXPIRE IN HOUR EXPIRE IN DAY EXPIRE IN WEEK EXPIRE OUT WEEK NEVER EXPIRE
XXXXXXXXXXXXXX_STATISTICS_MIGRATION_LIST* 1 40 7692832 0 0 0 0 1
total 1 40 7692832 0 0 0 0 1

作为依赖使用

获取方法如下:

go get github.com/winjeg/rma4go
复制代码

使用方法如下:

func testFunc() {h := "localhost"a := ""p := 6379cli := client.BuildRedisClient(client.ConnInfo{Host: h,Auth: a,Port: p,}, cmder.GetDb())stat := analyzer.ScanAllKeys(cli)// print in command linestat.Print()// the object is ready to use
}复制代码

github 维护(主要阵地)

  1. 欢迎其他开发者加入
  2. 欢迎提issue 反馈问题
  3. 欢迎任何有意义的建议
  4. 另外欢迎star,不建议fork,建议直接提交PR ; )

一个golang编写的redis内存分析工具rma4go相关推荐

  1. golang 编写的在线redis 内存分析工具 rma4go

    redis 内存分析工具 rma4go redis是一个很有名的内存型数据库,这里不做详细介绍.而rma4go (redis memory analyzer for golang) 是一个redis的 ...

  2. redis 内存分析工具 `rma4go`

    redis 内存分析工具 rma4go redis是一个很有名的内存型数据库,这里不做详细介绍.而rma4go (redis memory analyzer for golang) 是一个redis的 ...

  3. redis 内存分析工具 RMA 使用

    RMA 介绍 RMA 是一个控制台工具,用于实时扫描 Redis 密钥空间并按密钥模式聚合内存使用情况统计信息.您可以使用此工具而无需在生产服务器上进行维护.您可以按所有或选定的 Redis 类型进行 ...

  4. Redis内存分析工具

    2019独角兽企业重金招聘Python工程师标准>>> RdbTools是一个由于分析Redis dump.rdb文件的工具,有以下功能: 生成所有数据库和key的内存分析报告 把d ...

  5. redis内存分析工具rdbtools

    当Redis的内存已经快满的时候,我们能做什么呢? 最直接的方法就是分析一下Redis内存的构成,看是哪些键比较大,或者比较多,然后考虑一下对应的功能能不能优化,例如减少超时时间,例如不必要的数据不用 ...

  6. Redis内存分析工具之redis-rdb-tools的安装与使用

    操作系统:Centos7    1.redis-rdb-tools工具是用python语言编写的,所以首先需要安装python: 安装: (1)安装libffi-devel: yum -y insta ...

  7. 内存分析工具MAT的使用

    原文链接:http://www.jianshu.com/p/d8e247b1e7b2 MAT简介 MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速. ...

  8. 内存分析_Redis内存爆炸增长?你需要知道这一套Redis内存分析方法

    Redis Redis介绍 NoSQL Redis是当前比较热门的NOSQL数据库之一,和Memcache一样,数据都是缓存在计算机内存中.完全开源免费,遵守BSD协议,是一个高性能的key-valu ...

  9. Java内存分析工具MAT(Memory Analyzer Tool)的介绍与使用

    详细介绍了Java内存分析工具MAT(Memory Analyzer Tool)的常见使用方法,MAT可以帮助Java程序员快速进行内存分析,定位问题. MAT(Memory Analyzer Too ...

最新文章

  1. BIOS MCSDK 2.0 User Guide 示例学习
  2. _tmain和main
  3. LINUX 下构建OpenGL ES 3.0
  4. 一些知识点的整理以及面试题记录
  5. 如何在word文档中添加附件
  6. ASP.NET MVC 开源项目 收集
  7. 在ASP.NET MVC3项目中,自定义404错误页面
  8. php array_merge 与 + 区别
  9. Java线程中关于Synchronized的用法
  10. 开关电源测试系统用哪个软件,开关电源测试系统
  11. 业务gis 怎么让别的开发人员不需要懂gis就可以搞开发? (一)
  12. PLC+智能网关,实现HTTP+JSON/XML+POST/GET请求与解析
  13. 两款很小和强大的mp3分割软件
  14. Android系统启动源码分析
  15. 让生如夏花之绚烂 死如秋叶之静美 (全诗)
  16. Weighted Boxes Fusion
  17. 新建银行账户类,实现基本的属性和方法。
  18. 查看 namespace 下面所有的资源并删除
  19. digest 词根 gest
  20. PC机之间串口通信传输文件

热门文章

  1. 计算机专业规划书实地访谈,计算机专业职业生涯规划书(1).doc
  2. Java GUI(快递信息管理系统)
  3. 【收藏】2010年Ei收录的中国期刊
  4. kaggle 共享单车项目数据分析和单车租赁数预测
  5. c语言中的二目运算符,C语言中的三目运算符是什么
  6. 算法与数据结构(第一周)——线性查找法
  7. JavaScript实战 纯JavaScript实现别踩白块(源码)
  8. javascript-彩票游戏
  9. 吸引诸多名人及宫崎骏关注的Meta Rim有何魔力?
  10. 【python简易小程序设计】设计一个 python程序,模拟投掷100次色子。若总点数大于300点时,则提前结束 统计最后投掷出的各点数数量(要求使用列表)并输出