redis压缩是针对key压缩只针对string和listvalue所有压缩最终都会调用lzf_compress/lzf_decompress需要配置文件配置rdb_compressionrdb压缩才会生效lzf压缩限制长度必须大于20,即使aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa只能如果大于20,则按下。原因是没有研究rdb的内部压缩。如何确认这条记录被压缩/解压?Rdb解析每一条数据,都有一个标识字段。压缩记录自然是一个单独的类型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_original_len){.../*数据压缩!Let'ssaveitondisk*/byte=(RDB_EN??CVAL<<6)|RDB_EN??C_LZF;if((n=rdbWriteRaw(rdb,&byte,1))==-1)gotowritererr;nwritten+=n;...}解压缩void*rdbGenericLoadStringObject(rio*rdb,intflags,size_t*lenptr){...if(isencoded){switch(len){caseRDB_EN??C_INT8:caseRDB_EN??C_INT16:caseRDB_EN??C_INT32:returnrdbLoadIntegerObject(rdb,len,flags,lenptr);casefbrrdb_ENC_LZF:return,flags,lenptr);默认值: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,内部调用rdbSaveLzfStringObjectssize_trdbSaveObject(rio*rdb,robj*o,robj*key,intdbid){ssize_tn=0,nwritten=0;if(o->type==OBJ_STRING){/*保存字符串值*/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的compressed链表压缩可以选择深度。quicklist是redislist的底层数据结构。什么时候压缩?/*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;}/*如果这个insert创建了迄今为止唯一的元素,初始化head/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时,需要一个记录头来记录一个压缩标记。rocksdb和redis类似,还是很好找的。UncompressData/CompressDataforsstcompression调用关系UncompressBlockContentsForCompressionType->UncompressDataWriteBlock/BGWorkCompression->CompressAndVerifyBlock->CompressBlock->CompressDatablock本身有信息flags写的时候是否压缩blobdbCompressBlobIfNeeded->CompressDataGetCompressedSlice->CompressData总结要求文件自己知道是压缩后,元信息记录在内存中。压缩不压缩取决于业务场景,比如redis的quicklist压缩,因为最近访问的list是head和tail,其他的不重要
