Redis是一款键值内存数据库,支持丰富的数据类型,在极高的性能下,还支持数据的持久化存储。
持久化机制分为RDB的方式和AOF两种机制。AOF本质上是数据操作的redo log,和RDB相比,有更高的实时性,在Redis启动时也会优先加载AOF格式文件。而RDB则是数据内存的一个snapshots,在存储时使用带压缩的紧凑二进制结构,对比AOF,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个部分:
而其中value-type的编码如下:
而各个value的编码由于复杂度和篇幅原因,这里不在阐述,可以进一步参考:https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format 一文。
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')
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有