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最近访问的就是头尾,其他不重要
转载请注明:IT运维空间 » 运维技术 » 数据库压缩到底怎么做?
发表评论