当前位置:首页 >百科 >数据库压缩到底怎么做? 只针对string和list的库压value

数据库压缩到底怎么做? 只针对string和list的库压value

2024-06-30 16:43:34 [百科] 来源:避面尹邢网

数据库压缩到底怎么做?

作者:佚名 运维 数据库运维 redis的数据缩压缩是针对key的压缩,只针对string和list的库压value,需要配置文件配置rdb_compression rdb压缩才会生效。数据缩

redis

redis的库压压缩是针对key的压缩

数据库压缩到底怎么做? 只针对string和list的库压value

只针对string和list的value

数据库压缩到底怎么做? 只针对string和list的库压value

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

数据库压缩到底怎么做? 只针对string和list的库压value

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

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

rdb内部的数据缩压缩

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

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

  1. ssize_t rdbSaveLzfStringObject(rio *rdb, unsigned char *s, size_t len) {  
  2. ... 
  3.     comprlen = lzf_compress(s, len, out, outlen); 
  4.     if (comprlen == 0) {  
  5.         zfree(out); 
  6.         return 0; 
  7.     } 
  8.     ssize_t nwritten = rdbSaveLzfBlob(rdb, out, comprlen, len); 
  9. ... 
  10.  
  11. ssize_t rdbSaveLzfBlob(rio *rdb, void *data, size_t compress_len, 
  12.                        size_t original_len) {  
  13. ... 
  14.     /* Data compressed! Let's save it on disk */ 
  15.     byte = (RDB_ENCVAL<<6)|RDB_ENC_LZF; 
  16.     if ((n = rdbWriteRaw(rdb,&byte,1)) == -1) goto writeerr; 
  17.     nwritten += n; 
  18. ... 

解压缩

  1. void *rdbGenericLoadStringObject(rio *rdb, int flags, size_t *lenptr) {  
  2. ... 
  3.     if (isencoded) {  
  4.         switch(len) {  
  5.         case RDB_ENC_INT8: 
  6.         case RDB_ENC_INT16: 
  7.         case RDB_ENC_INT32: 
  8.             return rdbLoadIntegerObject(rdb,len,flags,lenptr); 
  9.         case RDB_ENC_LZF: 
  10.             return rdbLoadLzfStringObject(rdb,flags,lenptr); 
  11.         default: 
  12.             rdbReportCorruptRDB("Unknown RDB string encoding type %llu",len); 
  13.             return NULL; 
  14.         } 
  15.     } 
  16.  ... 
  17.   
  18.  void *rdbLoadLzfStringObject(rio *rdb, int flags, size_t *lenptr) {  
  19. ... 
  20.  
  21.     /* Load the compressed representation and uncompress it to target. */ 
  22.     if (rioRead(rdb,c,clen) == 0) goto err; 
  23.     if (lzf_decompress(c,clen,val,len) != len) {  
  24.         rdbReportCorruptRDB("Invalid LZF compressed string"); 
  25. ... 

接口简单容易定位

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

  1. ssize_t rdbSaveObject(rio *rdb, robj *o, robj *key, int dbid) {  
  2.     ssize_t n = 0, nwritten = 0; 
  3.  
  4.     if (o->type == OBJ_STRING) {  
  5.         /* Save a string value */ 
  6.         if ((n = rdbSaveStringObject(rdb,o)) == -1) return -1; 
  7.         nwritten += n; 
  8.     } else if (o->type == OBJ_LIST) {  
  9.  
  10.                 if (quicklistNodeIsCompressed(node)) {  
  11.                     void *data; 
  12.                     size_t compress_len = quicklistGetLzf(node, &data); 
  13.                     if ((n = rdbSaveLzfBlob(rdb,data,compress_len,node->sz)) == -1) return -1; 
  14.                     nwritten += n; 
  15.                 } else {  
  16.                     if ((n = rdbSaveRawString(rdb,node->zl,node->sz)) == -1) return -1; 
  17.                     nwritten += n; 
  18.                 } 
  19.                 node = node->next; 
  20.             } 
  21.         } else {  
  22.             serverPanic("Unknown list encoding"); 
  23.         } 
  24. 。。库压。数据缩 

quicklist的库压压缩

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

什么时候做压缩?

  1. /* Insert 'new_node' after 'old_node' if 'after' is 1. 
  2.  * Insert 'new_node' before 'old_node' if 'after' is 0. 
  3.  * Note: 'new_node' is *always* uncompressed, so if we assign it to 
  4.  *       head or tail, we do not need to uncompress it. */ 
  5. REDIS_STATIC void __quicklistInsertNode(quicklist *quicklist, 
  6.                                         quicklistNode *old_node, 
  7.                                         quicklistNode *new_node, int after) {  
  8.     if (after) {  
  9.         new_node->prev = old_node; 
  10.         if (old_node) {  
  11.             new_node->next = old_node->next; 
  12.             if (old_node->next) 
  13.                 old_node->next->prev = new_node; 
  14.             old_node->next = new_node; 
  15.         } 
  16.         if (quicklist->tail == old_node) 
  17.             quicklist->tail = new_node; 
  18.     } else {  
  19.         new_node->next = old_node; 
  20.         if (old_node) {  
  21.             new_node->prev = old_node->prev; 
  22.             if (old_node->prev) 
  23.                 old_node->prev->next = new_node; 
  24.             old_node->prev = new_node; 
  25.         } 
  26.         if (quicklist->head == old_node) 
  27.             quicklist->head = new_node; 
  28.     } 
  29.     /* If this insert creates the only element so far, initialize head/tail. */ 
  30.     if (quicklist->len == 0) {  
  31.         quicklist->head = quicklist->tail = new_node; 
  32.     } 
  33.  
  34.     /* Update len first, so in __quicklistCompress we know exactly len */ 
  35.     quicklist->len++; 
  36.  
  37.     if (old_node) 
  38.         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最近访问的就是头尾,其他不重要

 

责任编辑:张燕妮 来源: 王很水的博客 数据库架构技术

(责任编辑:百科)

    推荐文章
    热点阅读