gtxyzz

数据库压缩到底怎么做?

gtxyzz 运维技术 2022-11-18 411浏览 0

数据库压缩到底怎么做?

redis

redis的压缩是针对key的压缩

只针对string和list的value

所有的压缩最终都会调用lzf_compress/lzf_decompress

需要配置文件配置rdb_compression rdb压缩才会生效

lzf压缩限制长度要大于20,即使是aaaaaaaaaaaaaaaaaaaa也压不了,大于20才能压。原因没有深究

rdb内部的压缩

  • 如何确认这个record是被压缩/解压的?

rdb解析每条数据,都有标识字段,压缩的record自然是单独的类型

ssize_trdbSaveLzfStringObject(rio*rdb,unsignedchar*s,size_tlen){
...
comprlen=lzf_compress(s,len,out,outlen);
if(comprlen==0){
zfree(out);
return0;
}
ssize_tnwritten=rdbSaveLzfBlob(rdb,out,comprlen,len);
...
}

ssize_trdbSaveLzfBlob(rio*rdb,void*data,size_tcompress_len,
size_toriginal_len){
...
/*Datacompressed!Let'ssaveitondisk*/
byte=(RDB_ENCVAL<<6)|RDB_ENC_LZF;
if((n=rdbWriteRaw(rdb,&byte,1))==-1)gotowriteerr;
nwritten+=n;
...
}

解压缩

void*rdbGenericLoadStringObject(rio*rdb,intflags,size_t*lenptr){
...
if(isencoded){
switch(len){
caseRDB_ENC_INT8:
caseRDB_ENC_INT16:
caseRDB_ENC_INT32:
returnrdbLoadIntegerObject(rdb,len,flags,lenptr);
caseRDB_ENC_LZF:
returnrdbLoadLzfStringObject(rdb,flags,lenptr);
default:
rdbReportCorruptRDB("UnknownRDBstringencodingtype%llu",len);
returnNULL;
}
}
...

void*rdbLoadLzfStringObject(rio*rdb,intflags,size_t*lenptr){
...

/*Loadthecompressedrepresentationanduncompressittotarget.*/
if(rioRead(rdb,c,clen)==0)gotoerr;
if(lzf_decompress(c,clen,val,len)!=len){
rdbReportCorruptRDB("InvalidLZFcompressedstring");
...
}

接口简单容易定位

所有的类型string/hash具体到底层,都是string,就会走这个压缩的过程rdbSaveRawString,内部来调用rdbSaveLzfStringObject

ssize_trdbSaveObject(rio*rdb,robj*o,robj*key,intdbid){
ssize_tn=0,nwritten=0;

if(o->type==OBJ_STRING){
/*Saveastringvalue*/
if((n=rdbSaveStringObject(rdb,o))==-1)return-1;
nwritten+=n;
}elseif(o->type==OBJ_LIST){

if(quicklistNodeIsCompressed(node)){
void*data;
size_tcompress_len=quicklistGetLzf(node,&data);
if((n=rdbSaveLzfBlob(rdb,data,compress_len,node->sz))==-1)return-1;
nwritten+=n;
}else{
if((n=rdbSaveRawString(rdb,node->zl,node->sz))==-1)return-1;
nwritten+=n;
}
node=node->next;
}
}else{
serverPanic("Unknownlistencoding");
}
。。。
}

quicklist的压缩

链表压缩可以选择深度,quicklist是redis list的底层数据结构

什么时候做压缩?

/*Insert'new_node'after'old_node'if'after'is1.
*Insert'new_node'before'old_node'if'after'is0.
*Note:'new_node'is*always*uncompressed,soifweassignitto
*headortail,wedonotneedtouncompressit.*/
REDIS_STATICvoid__quicklistInsertNode(quicklist*quicklist,
quicklistNode*old_node,
quicklistNode*new_node,intafter){
if(after){
new_node->prev=old_node;
if(old_node){
new_node->next=old_node->next;
if(old_node->next)
old_node->next->prev=new_node;
old_node->next=new_node;
}
if(quicklist->tail==old_node)
quicklist->tail=new_node;
}else{
new_node->next=old_node;
if(old_node){
new_node->prev=old_node->prev;
if(old_node->prev)
old_node->prev->next=new_node;
old_node->prev=new_node;
}
if(quicklist->head==old_node)
quicklist->head=new_node;
}
/*Ifthisinsertcreatestheonlyelementsofar,initializehead/tail.*/
if(quicklist->len==0){
quicklist->head=quicklist->tail=new_node;
}

/*Updatelenfirst,soin__quicklistCompressweknowexactlylen*/
quicklist->len++;

if(old_node)
quicklistCompress(quicklist,old_node);
}

也就是说,头尾不会压缩,其他的节点会压缩,在修改的时候同事把旧的节点给压缩了

这里有个问题,这里的节点压缩了,rdb存储的时候还要特别处理一下,判定已经压缩过,走rdbSaveLzfBlob

需要有个record头来记录一个compression的标记

rocksdb

类似redis,还是很好找的,UncompressData/CompressData

针对sst的压缩

调用关系

UncompressBlockContentsForCompressionType -> UncompressData

WriteBlock/BGWorkCompression -> CompressAndVerifyBlock -> CompressBlock -> CompressData

block本身有信息标记是否是压缩

写入的时候才压缩

blobdb

CompressBlobIfNeeded -> CompressData

GetCompressedSlice -> CompressData

总结

  • 需要文件本身知道自己是压缩的,有元信息记录
  • 在内存中是否压缩要考虑业务场景,比如redis这个quicklist 压缩,因为list最近访问的就是头尾,其他不重要

继续浏览有关 数据库运维 的文章
发表评论