инструмент анализа памяти Redisrma4go
Введение
Redis — это хорошо известная база данных в памяти, которая не будет здесь подробно описываться. иrma4go
(анализатор памяти redis для golang) — это инструмент для анализа памяти Redis. Основная функция этого инструмента — анализировать память Redis во время выполнения, подсчитывать распределение ключей в Redis, использование различных типов данных и размер keys. , количество и распределение больших ключей, распределение статуса истечения срока действия ключа и другие инструменты, которые помогают обнаруживать проблемы с использованием Redis. Я надеюсь, что это может предоставить разработчикам приложений удобство для устранения практических проблем, возникающих в рабочей среде.
rma4go
сценарии применения
Redis — очень популярная база данных в памяти, и многие предприятия используют ее. Однако, поскольку в отрасли не так много спецификаций для использования Redis или некоторые спецификации не соблюдаются должным образом, при использовании Redis возникает много проблем.Вот несколько примеров:
- Хранилище Redis заполнено, я не знаю распределение ключей, и я не знаю, откуда исходит приложение
- Redis заблокирован, я не знаю, что вызвало блокировку, какая ключевая операция, в каком приложении это вызвало
- Я хочу перенести данные Redis или настроить некоторые параметры, но я не знаю, сохранять ли данные в Redis, и я не знаю, какой бизнес используется и т. д.
- Срок действия ключа Redis неясен, и я не знаю, что можно удалить или изменить.
На самом деле, некоторые из вышеперечисленных проблем просто перечислены мной, а не все существующие проблемы, я полагаю, что есть много других сценариев, которые также будут использовать такой инструмент анализа памяти Redis.
rma4go
Особенности rma4go
измерение данных
Для ключевого анализа наш инструмент предоставит данные в следующих измерениях:
- Количество распределение Размер клавиш
- измерение распределения срока действия ключа
- измерение распределения типа ключа
- Измерение распределения размера данных, соответствующих ключу
- Измерение распределения префикса ключа
- Размер медленного ключа и большого ключа
Конечно, если в будущем будут найдены лучшие широты, они будут добавлены.В настоящее время эти широты являются основными.
дизайн типа данных
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 < 1h
ExpireInDay int64 `json:"expireInDay"` // >= 1h < 24h
ExpireInWeek int64 `json:"expireInWeek"` // >= 1d < 7d
ExpireOutWeek int64 `json:"expireOutWeek"` // >= 7d
}
детали реализации
ключевая метаинформация
type KeyMeta struct {
Key string
KeySize int64
DataSize int64
Ttl int64
Type string
}
Как мы все знаем, все данные в Redis в основном основаны на ключе, и они также работают в соответствии с ключом. Затем, чтобы проанализировать ключ в Redis, мы должны записать информацию об этом ключе. Информация, которую мы можем записать, Так же, как и в приведенной выше структуре, сам ключ, размер ключа, размер данных, срок действия и тип ключа. Эта информация является базовой информацией для нашего ключевого анализа, которую можно получить с помощью некоторых простых команд Redis.
Пройти все ключи Redis
Чтобы выполнить полный анализ ключей в Redis, нам нужен способ доступа к исходной информации обо всех ключах.scan
Таким образом, все ключи могут быть легко пройдены, и можно получить доступ к метаинформации соответствующего ключа.
Таким образом, для Redis нагрузка, вызванная онлайн-анализом ключей, не будет очень большой.Конечно, анализ ключей не может выполняться в пиковый период QPS, и его необходимо анализировать, когда позволяют ресурсы Redis.
Кроме того, благодаря механизму очистки памяти самого redis, при анализе ключа можно очистить 25% просроченной занятости, поэтому данный инструмент анализа также имеет функцию очистки части памяти. в redis и существует в памяти внутри ключевых слов.
Анализировать и обобщать записанную информацию
При использовании метода обхода всех ключей и метаданных все остальное заключается в агрегировании и обобщении этих данных, что в основном представляет собой алгоритмическую работу. Самое сложное это часть агрегации ключей.Много компромиссов.Поскольку автор не специализируется на алгоритмах,а подходящей библиотеки я не нашел,могу только сам придумать способ. Основная идея такова:
алгоритм сжатия
- Метаинформация для каждого нового ключа добавляется к объекту анализа старого ключа
- Укоротите ключ от задней части к передней, удалите хвост и посмотрите, включена ли статистическая информация о ключе.Если она включена, информация о ключе накапливается.Если она не включена, создается новая запись .
- Когда количество записей добавляется к определенному числу, количество объектов сжимается один раз
- Алгоритм сжатия также сжимает от конца строки к началу строки.
- Когда сжатие не может увеличить количество ключей этого паттерна, используйте исходный ключ (ключ до сжатия)
- При сжатии можно увеличить количество ключей этого паттерна, объединить ключи и установить паттерн в сжатый паттерн.
- Когда количество записей превышает указанное число, цикл будет повторяться до тех пор, пока сжатие не станет меньше указанного числа.
- Если есть требование минимальной длины ключа (даже при повторном сжатии одна-две цифры должны быть зарезервированы), то есть некоторые параметры, сжатые до минимальной длины строки, которые можно настроить и задать, и определенные компромиссы сделаны.
- пока не завершится сканирование
код показывает, как показано ниже
const (
defaultSize = 128
compactNum = 30
maxLeftNum = 150
minKeyLenLower = 2
minKeyLen = 5
)
func (stat *KeyStat) compact() {
distMap := stat.Distribution
tmpMap := make(map[string][]string, defaultSize)
shrinkTo := compactNum
for k := range distMap {
compactedKey := k
if 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 {
// shrink
if 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 没有使得这个集合的元素数量增加, 就使用原来的key
for 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 = tnMap
shrinkTo --
}
dists := make(map[string]Distribution, defaultSize)
for k, v := range tmpMap {
if len(v) > 1 {
var nd Distribution
for _, dk := range v {
d := distMap[dk]
nd.KeyPattern = k + "*"
nd.KeyCount += d.KeyCount
nd.KeySize += d.KeySize
nd.DataSize += d.DataSize
nd.ExpireInHour += d.ExpireInHour
nd.ExpireInWeek += d.ExpireInWeek
nd.ExpireInDay += d.ExpireInDay
nd.ExpireOutWeek += d.ExpireOutWeek
nd.KeyNeverExpire += d.KeyNeverExpire
}
dists[k] = nd
} else {
for _, dk := range v {
nd := distMap[dk]
nd.KeyPattern = dk + "*"
dists[dk] = nd
}
}
}
stat.Distribution = dists
}
проект github для онлайн-анализа ключей
Это проект, который я написал, он очень прост в использовании, бинарный пакет готов, вы можете скачать его по следующей ссылкеLinux MAC
метод сборки
- Перед сборкой убедитесь, что golang sdk установлен и его версия >=1.11.0.
- Пожалуйста, убедитесь, что у вас есть среда для преодоления стены, потому что она требует загрузки некоторых зависимостей, которые могут исходить из-за стены Способ опрокидывания стены следующий
// linux/osx
export http_proxy=somehost:port
export https_proxy=somehost:port
// windows
set http_proxy=somehost:port
set https_proxy=somehost:port
- Построить
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 string
address of a redis (default "localhost")
-a string
password/auth of the redis
-d int
db of the redis to analyze
-h help content
-p int
port of the redis (default 6379)
-r string
address 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 := 6379
cli := client.BuildRedisClient(client.ConnInfo{
Host: h,
Auth: a,
Port: p,
}, cmder.GetDb())
stat := analyzer.ScanAllKeys(cli)
// print in command line
stat.Print()
// the object is ready to use
}
обслуживание github (основная позиция)
- Другие разработчики могут присоединиться
- Добро пожаловать, чтобы оставить отзыв
- Любые содержательные предложения приветствуются
- Кроме того, звездочка приветствуется, форк не рекомендуется, рекомендуется подавать PR напрямую ;)