专栏首页西郊手记Redis RDB文件离线分析
原创

Redis RDB文件离线分析

概述

Redis是一款键值内存数据库,支持丰富的数据类型,在极高的性能下,还支持数据的持久化存储。

持久化机制分为RDB的方式和AOF两种机制。AOF本质上是数据操作的redo log,和RDB相比,有更高的实时性,在Redis启动时也会优先加载AOF格式文件。而RDB则是数据内存的一个snapshots,在存储时使用带压缩的紧凑二进制结构,对比AOF,RDB机制导出的数据量更小,在存储、全量复制和数据离线分析中更好的选择。

今天我们就来重点说说RDB文件的离线分析。

RDB文件格式简述

RDB文件格式为优化读写性能,将内存结构尽可能对齐文件格式,并在能使用压缩都使用压缩以减少文件大小。

先看看官方文档,RDB的文件格式总览如下:

----------------------------# RDB is a binary format. There are no new lines or spaces in the file.
52 45 44 49 53              # Magic String "REDIS"
00 00 00 03                 # RDB Version Number in big endian. In this case, version = 0003 = 3
----------------------------
FE 00                       # FE = code that indicates database selector. db number = 00
----------------------------# Key-Value pair starts
FD $unsigned int            # FD indicates "expiry time in seconds". After that, expiry time is read as a 4 byte unsigned int
$value-type                 # 1 byte flag indicating the type of value - set, map, sorted set etc.
$string-encoded-key         # The key, encoded as a redis string
$encoded-value              # The value. Encoding depends on $value-type
----------------------------
FC $unsigned long           # FC indicates "expiry time in ms". After that, expiry time is read as a 8 byte unsigned long
$value-type                 # 1 byte flag indicating the type of value - set, map, sorted set etc.
$string-encoded-key         # The key, encoded as a redis string
$encoded-value              # The value. Encoding depends on $value-type
----------------------------
$value-type                 # This key value pair doesn't have an expiry. $value_type guaranteed != to FD, FC, FE and FF
$string-encoded-key
$encoded-value
----------------------------
FE $length-encoding         # Previous db ends, next db starts. Database number read using length encoding.
----------------------------
...                         # Key value pairs for this database, additonal database
                            
FF                          ## End of RDB file indicator
8 byte checksum             ## CRC 64 checksum of the entire file.

文件头部以“REDIS” 5个字节开头:52 45 44 49 53

后面4个字节是RDB的版本号,最新的版本5.0.3是9:00 00 00 09

之后2个字节是选择数据库选择数据,比如 FE 00, select 0

然后开始键值数据,每个Key结构包含4个部分:

  1. Key过期时间,这里和存储不一样的是存储的是绝对时间,不是相对时间。
  2. value-type是value的类型标记,具体如下:
  3. Key的值,按String的类型编码。
  4. Value的值,按2指示类型编码。

而其中value-type的编码如下:

  1. 0 = "String Encoding"
  2. 1 = "List Encoding"
  3. 2 = "Set Encoding"
  4. 3 = "Sorted Set Encoding"
  5. 4 = "Hash Encoding"
  6. 9 = "Zipmap Encoding"
  7. 10 = "Ziplist Encoding"
  8. 11 = "Intset Encoding"
  9. 12 = "Sorted Set in Ziplist Encoding"
  10. 13 = "Hashmap in Ziplist Encoding"

而各个value的编码由于复杂度和篇幅原因,这里不在阐述,可以进一步参考:https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format 一文。

RDB文件分析

rdb分析的应用场景较多,比如Redis数据差异对比,大Key的分析,键值的统计等。

熟话说工欲善其事,必先利其器,虽然上述部分我们简单阐述了rdb的文件格式,但要自己写从零写一个分析器还是有较大的工作量。好在开源社区里已经有不少RDB文件分析组件了。其中最著名的莫过于redis-rdb-tools(https://github.com/sripathikrishnan/redis-rdb-tools),支持多个rdb文件数据对比,内存报告,key分析能特性并支持将数据导出为JSON格式。

redis-rdb-tools使用python开发,同时可以运行在python2和python3上。

安装

由于rdb为压缩格式,需要python-lzf,先安装python-lzf:

pip install rdbtools python-lzf

从源码里安装:

git clone https://github.com/sripathikrishnan/redis-rdb-tools
cd redis-rdb-tools
sudo python setup.py install

使用

将数据转为JSON格式:

> rdb -c json /var/redis/6379/dump.rdb

[{
"Citat":["B\u00e4ttre sent \u00e4n aldrig","Bra karl reder sig sj\u00e4lv","Man ska inte k\u00f6pa grisen i s\u00e4cken"],
"bin_data":"\\xFE\u0000\u00e2\\xF2"}]

生成内存报告:

> 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

查看单个key的内存使用情况:

> redis-memory-for-key person:1

> redis-memory-for-key -s localhost -p 6379 -a mypassword person:1

Key 			person:1
Bytes				111
Type				hash
Encoding			ziplist
Number of Elements		2
Length of Largest Element	8

多个RDB的对比

> rdb --command diff /var/redis/6379/dump1.rdb | sort > dump1.txt
> rdb --command diff /var/redis/6379/dump2.rdb | sort > dump2.txt
> kdiff3 dump1.txt dump2.txt

将rdb转为aof格式流

> rdb --c protocol /var/redis/6379/dump.rdb

*4
$4
HSET
$9
users:123
$9
firstname
$8
Sripathi

如果这些工具还不能满足你的使用需求的话,redis-rdb-tools还提供了高度抽象的Parser供定制使用:

直接上代码:

from rdbtools import RdbParser, RdbCallback
from rdbtools.encodehelpers import bytes_to_unicode

class MyCallback(RdbCallback):
    ''' Simple example to show how callback works.
        See RdbCallback for all available callback methods.
        See JsonCallback for a concrete example
    '''

    def __init__(self):
        super(MyCallback, self).__init__(string_escape=None)

    def encode_key(self, key):
        return bytes_to_unicode(key, self._escape, skip_printable=True)

    def encode_value(self, val):
        return bytes_to_unicode(val, self._escape)

    def set(self, key, value, expiry, info):
        print('%s = %s' % (self.encode_key(key), self.encode_value(value)))

    def hset(self, key, field, value):
        print('%s.%s = %s' % (self.encode_key(key), self.encode_key(field), self.encode_value(value)))

    def sadd(self, key, member):
        print('%s has {%s}' % (self.encode_key(key), self.encode_value(member)))

    def rpush(self, key, value):
        print('%s has [%s]' % (self.encode_key(key), self.encode_value(value)))

    def zadd(self, key, score, member):
        print('%s has {%s : %s}' % (str(key), str(member), str(score)))


callback = MyCallback()
parser = RdbParser(callback)
parser.parse('/var/redis/6379/dump.rdb')

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • NoSQL篇 | NoSQL从小白到码神 之 Redis篇

    课程目录: - NoSQL背景 - NoSQL简介 - NoSQL和关系型数据库对比 - Redis简介 - Redis下载安装配置(Linux环境) - R...

    码神联盟
  • 分析redis key大小的几种方法

    当redis被用作缓存时,有时我们希望了解key的大小分布,或者想知道哪些key占的空间比较大。本文提供了几种方法。

    跑马溜溜的球
  • 2017 Openstack Days China | 腾讯的Openstack实践与创新

    本文转载自CSDN 2017年7月24日~25日,2017 OpenStack Days China官方盛典在北京国家会议中心盛大召开。腾讯技术工程事业群企业I...

    腾讯高校合作
  • 2017 Openstack Days China | 腾讯的Openstack实践与创新

    本文转载自CSDN 2017年7月24日~25日,2017 OpenStack Days China官方盛典在北京国家会议中心盛大召开。腾讯技术工程事业群企业...

    腾讯技术工程官方号
  • 1、Redis服务搭建 2、为功能添加缓存功能

    2.redis介绍 2.1.什么是redis Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应...

    爱明依
  • Redis学习笔记 -- 1

    redis作为内存非关系型数据库,是一种key - value 缓存产品,但它同时还支持数据持久化,常常和一些老牌关系型数据库配合使用 下文将作为学习笔记介绍一...

    用户1637228
  • spring及springboot整合redis前言:一、整合前提:二、spring整合redis:三、springboot整合redis:总结:

    redis是一种nosql数据库,以<key,value>的形式存储数据,其速度相比于MySQL之类的数据库,相当于内存读写与硬盘读写的差别,所以常常用作缓存。...

    贪挽懒月
  • 4 种姿势让你彻底掌握 Redis 的导入导出以及数据迁移

    闲着无事,在家里无聊。两天前,我搞了一个《2020-nCoV 新型肺炎确诊患者相同行程查询工具 V1.3》,在朋友圈里疯狂转发!我兴奋极力了,这让我感受到了作为...

    业余草
  • Django 2.1.7 Celery 4.3.0 配置

    Celery使用简单,配置也非常简单。Celery有很多配置选项能够使得celery能够符合我们的需要,但是默认的几项配置已经足够应付大多数应用场景了。

    Devops海洋的渔夫
  • 如何做到 Redis 开发规范中的拒绝 bigkey

    代码中的问题,光靠 Code Review 是不够的。Code Review 主要是解决规范问题,当然也能排查出一些 bug。

    业余草

扫码关注云+社区

领取腾讯云代金券