redis占用内存诊断过程

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 开篇 写这篇文章是因为近期在准备双11大促资源的盘点,盘点过程中发现部门占用的redis空间总共720G已经接近占满了,正常情况下第一反应是联系采购新的服务器扩容内存,但是因为好奇我们的redis集群内部数据占用情况而打算先分析一下,这才有这篇文章,也给所有想对redis内存存储一窥究竟的同学提供一个思路。

开篇

 写这篇文章是因为近期在准备双11大促资源的盘点,盘点过程中发现部门占用的redis空间总共720G已经接近占满了,正常情况下第一反应是联系采购新的服务器扩容内存,但是因为好奇我们的redis集群内部数据占用情况而打算先分析一下,这才有这篇文章,也给所有想对redis内存存储一窥究竟的同学提供一个思路。


推荐两个工具

 在github上有两个分析redis rdb文件的开源工具redis-rdb-toolsrdr。redis-rdb-tools用于分析所有key及占用空间;rdr能够分析出所有key但是没法计算key占用空间,不过额外提供图形化界面。

redis-rdb-tools介绍

安装介绍

  • 提供多种途径进行安装,看心情选择其中一个即可
Rdbtools is a parser for Redis' dump.rdb files. 
The parser generates events similar to an xml sax parser, and is very efficient memory wise.

In addition, rdbtools provides utilities to :
  1.  Generate a Memory Report of your data across all databases and keys
  2.  Convert dump files to JSON
  3.  Compare two dump files using standard diff tools

Pre-Requisites :
  1.  python-lzf is optional but highly recommended to speed up parsing.
  2.  redis-py is optional and only needed to run test cases.

To install from PyPI (recommended) :
   1.pip install rdbtools python-lzf

To install from source :
   1.git clone https://github.com/sripathikrishnan/redis-rdb-tools
   2.cd redis-rdb-tools
   3.sudo python setup.py install



功能分析

  • 解析rdb文件所有的key/value的内容
  • 解析rdb文件所有的key以及对应的value的大小
生成所有的key/value
> rdb --command json /var/redis/6379/dump.rdb

[{
  "user003":{"fname":"Ron","sname":"Bumquist"},
  "lizards":["Bush anole","Jackson's chameleon","Komodo dragon","Ground agama","Bearded dragon"],
  "user001":{"fname":"Raoul","sname":"Duke"},
  "user002":{"fname":"Gonzo","sname":"Dr"},
  "user_list":["user003","user002","user001"]},{
  "baloon":{"helium":"birthdays","medical":"angioplasty","weather":"meteorology"},
  "armadillo":["chacoan naked-tailed","giant","Andean hairy","nine-banded","pink fairy"],
  "aroma":{"pungent":"vinegar","putrid":"rotten eggs","floral":"roses"}
}]



生成所有key/value以及对应的存储空间
> rdb -c memory /var/redis/6379/dump.rdb --bytes 128 -f memory.csv
> cat memory.csv

database,type,key,size_in_bytes,encoding,num_elements,len_largest_element
0,list,lizards,241,quicklist,5,19
0,list,user_list,190,quicklist,3,7
2,hash,baloon,138,ziplist,3,11
2,list,armadillo,231,quicklist,5,20
2,hash,aroma,129,ziplist,3,11


rdr介绍

安装介绍

下载:http://ohjx11q65.bkt.clouddn.com/rdr
赋予执行权限:$ chmod a+x ./rdr



功能分析

  • 解析rdb文件中所有的key的值
$ ./rdr keys example.rdb
portfolio:stock_follower_count:ZH314136
portfolio:stock_follower_count:ZH654106
portfolio:stock_follower:ZH617824
portfolio:stock_follower_count:ZH001019
portfolio:stock_follower_count:ZH346349
portfolio:stock_follower_count:ZH951803
portfolio:stock_follower:ZH924804
portfolio:stock_follower_count:INS104806


问题定位过程

  • 通过redis-rdb-tools工具导出所有的key以及对应的占用情况
  • 通过linux的sort命令按照key的占用空间进行倒序进行排列
  • 通过rdr工具导出所有的key占用情况并和redis-rdb-tools工具导出所有的key进行对比
  • 开始怀疑大hash的并通过scan温和的导出所有hash的key,通过hlen以及hscan观察hash中filed对应的value大小,确定hash结构的变量存在问题
  • 因为业务属性我们的key最多保存7天,针对所有的hash类的key需要重点关注TTL时间
  • 最后通过python脚本连接redis集群,结合scan、hscan、del等命令删除所有垃圾数据
  • 中间走过的一个弯路是怀疑redis的key/value额外占用了太多空间,后来网上资料发现一个key最多也就额外占用50Bypte左右,不可能造成大量内存占用,所以可以排除这个方向。



工具使用的截图

img_277b9e75a11322c2965b9aac35bd43f5.png

img_676fdc64c6e47138e544aa4c13fbb5d9.png
img_9058f7982fa70eece344312c7564ed19.png


温和清理redis的hash数据

定位hash数据结构的key

  • 切记一定使用scan!切记一定使用scan!切记一定使用scan!
  • 通过scan加前缀匹配来扫面所有相关的hash的key,然后筛选其中待删除的key
from rediscluster import StrictRedisCluster
from redis import Redis
import time
import threading

conn_list = [
"1.1.1.1:2222",
"2.2.2.2:222",
]

def scan_key(conn):
    data = conn.split(":")
    print data[0],data[1]
    redis_client = Redis(data[0], data[1])

    cursor = 0
    count = 0
    while True:
        // 根据前缀如fuck_redis进行扫描
        scan_result = redis_client.scan(cursor, "fuck_redis*", 400)
        cursor = scan_result[0]
        key_list = scan_result[1]

        if len(key_list) > 0:
            for key in key_list:
                # redis_cluster.delete(key)
                print key, redis_client.ttl(key)

        if cursor == 0:
            break


for conn in conn_list:
    // 启动多线程进行key的扫描
    new_thread = threading.Thread(target=scan_key, args=(conn,))
    new_thread.start()



删除hash数据结构的key

  • 切记用hscan先删除hash的field,然后再删除hash的key!切记用hscan先删除hash的field,然后再删除hash的key!切记用hscan先删除hash的field,然后再删除hash的key!
  • 清理hash的field后再删除hash的key,防止redis阻塞造成服务抖动!
from rediscluster import StrictRedisCluster

nodes = [
    {"host": "1.1.1.1", "port": "6451"}
]

// redis3.0内部通过集群方式进行删除
redis_cluster = StrictRedisCluster(startup_nodes=nodes, decode_responses=True)

// 待删除的hash key
key_list = [xxx__ooo_0"]

// 遍历所有待删除的key进行温和删除
for hash_key in key_list:
    cursor = 0
    count = 0
    while True:
        // 温和的采用hscan进行遍历删除
        scan_result = redis_cluster.hscan(hash_key, cursor, count=200)
        cursor = scan_result[0]
        result = scan_result[1]
        for key in result:
            redis_cluster.hdel(hash_key, key)
            if count%200 == 0:
                print hash_key, key

        if cursor == 0:
            redis_cluster.delete(hash_key)
            break


结束语

深入到细节才能从本质上解决问题,不加分析就直接扩容其实在某种程度上掩盖了所有问题,不可取!

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
NoSQL Redis
12- Redis的内存用完了会发生什么?
当Redis内存满时,写操作将失败,但读操作仍可进行。系统可配置内存淘汰策略,在达到最大内存时自动删除旧数据。
39 6
|
3天前
|
NoSQL Linux Redis
Redis内存分析工具RDR
Redis内存分析工具RDR
13 1
|
6天前
|
Arthas 监控 Java
JVM工作原理与实战(三十一):诊断内存泄漏的原因
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了诊断内存溢出的原因、MAT内存泄漏检测的原理等内容。
12 0
|
17天前
|
缓存 NoSQL 算法
【Redis系列笔记】内存淘汰及过期删除
Redis是一个内存键值对数据库,所以对于内存的管理尤为重要。Redis内部对于内存的管理主要包含两个方向,过期删除策略和数据淘汰策略。内存淘汰策略指在Redis内存使用达到一定阈值的时候,执行某种策略释放内存空间,以便于接收新的数据。数据过期删除策略是指在数据的有效时间到期后,如何从内存中删除这些数据的规则。
41 0
|
18天前
|
存储 缓存 NoSQL
Redis入门到通关之Redis内存淘汰(内存过期)策略
Redis入门到通关之Redis内存淘汰(内存过期)策略
32 3
|
19天前
|
存储 缓存 NoSQL
Redis 内存回收
Redis 内存回收
17 3
|
19天前
|
存储 NoSQL 安全
Redis内存碎片详解
Redis在存储数据时可能申请超过实际需求的内存,导致内存碎片。内存碎片率=used_memory_rss/used_memory,大于1.5时需清理。Redis 4.0-RC3后引入`activedefrag`配置来自动整理内存,可通过`config set`命令启用,并通过`active-defrag-ignore-bytes`和`active-defrag-threshold-lower`参数设定清理条件。内存清理可能影响性能,`active-defrag-cycle-min`和`active-defrag-cycle-max`参数调整CPU占用比例以缓解
45 0
|
26天前
|
缓存 NoSQL 中间件
redis内存溢出报错--OOM command not allowed when used memory > 'maxmemory'
该内容是关于Redis缓存服务器的使用指南。通过Xshell连接IP地址为25.218.153.193或206的主机,进入/data/iuap/middleware/redis-30001/bin目录,使用`redis-cli`连接到IP为206的30003端口。登录时需`auth yonyou*123`,可运行`info`和`info memory`查看状态,`flushall`清理缓存。在清理前,要备份/data/iuap/middleware/redis-30003/data/下的.aof和.rdb文件,利用tar命令打包并移至/tmp目录。
|
18天前
|
Linux
Linux rsyslog占用内存CPU过高解决办法
该文档描述了`rsyslog`占用内存过高的问题及其解决方案。
41 4
|
1月前
|
移动开发 运维 监控
掌握Linux运维利器:查看CPU和内存占用,轻松解决性能问题!
掌握Linux运维利器:查看CPU和内存占用,轻松解决性能问题!