基于Dedup的数据打包技术
基于Dedup的数据打包技术
0、引言
Tar, winrar, winzip是最为常见的数据打包工具软件,它们把文件集体封装成一个单独的数据包,从而方便数据的分布、传输、归档以及持久保存等目的。这类工具通常都支持数据压缩技术,从而有效减少数据的存储空间,常用压缩算法有Huffman编码、Z77/z78、LZW等。压缩算法的原理是通过对数据的重新编码,高频率数据片段采用较短的编码,低频率数据片段采用较长的编码,从而获得全局的上数据量较小的文件表示。
1、Dedup原理
Deduplication,即重复数据删除,它是一种非常新的且流行度很高的存储技术,可以大大减少数据的数量。重复数据删除技术,通过数据集中重复的数据,从而消除冗余数据。借助dedup技术,可以提高存储系统的效率,有效节约成本、减少传输过程中的网络带宽。同时它也是一种绿色存储技术,能有效降低能耗(存储空间小了,所需要存储系统磁盘也就少了,自然所需要电能就减少了)。
dedup按照消重的粒度可以分为文件级和数据块级。文件级的dedup技术也称为单一实例存储(SIS, Single Instance Store),数据块级的重复数据删除,其消重粒度更小,可以达到4-24KB之间。显然,数据块级的可以提供更高的数据消重率,因此目前主流的dedup产品都是数据块级的。重复数据删除原理如下图所示。将文件都分割成数据块(可以是定长或变长的数据块),采用MD5或SHA1等Hash算法(可以同时使用两种或以上hash算法,或CRC校验等,以获得非常小概率的数据碰撞发生)为数据块计算FingerPrint。具有相同FP指纹的数据块即可认为是相同的数据块,存储系统中仅需要保留一份。这样,一个物理文件在存储系统中就对应一个逻辑表示,由一组FP组成的元数据。当进行读取文件时,先读取逻辑文件,然后根据FP序列,从存储系统中取出相应数据块,还原物理文件副本。
重复数据删除目前主要应用于数据备份,因此对数据进行多次备份后,存在大量重复数据,非常适合dedup技术。事实上,dedup技术可以用于很多场合,包括在线数据、近线数据、离线数据存储系统,甚至可以在文件系统、卷管理器、NAS、SAN中实施。还可以用于网络数据传输,当然也可以应用于数据打包技术。dedup技术可以帮助众多应用降低数据存储量,节省网络带宽,提高存储效率、减小备份窗口,绿色节能。这里,基于dedup实现一种数据打包技术。
2、基于Dedup的数据打包模型
数据包文件的数据布局:
Header |
Unique block data |
File metadata |
数据包由三部分组成:文件头(header)、唯一数据块集(unique block data)和逻辑文件元数据(file metadata)。其中,header为一个结构体,定义了数据块大小、唯一数据块数量、数据块ID大小、包中文件数量、元数据在包中的位置等元信息。文件头后紧接就存储着所有唯一的数据块,大小和数量由文件头中元信息指示。在数据块之后,就是数据包中文件的逻辑表示元数据,由多个实体组成,结构如下所示,一个实体表示一个文件。解包时根据文件的元数据,逐一提取数据块,还原出当初的物理文件。
逻辑文件的元数据表示:
Entry header |
pathname |
Entry data |
Last block data |
逻辑文件的实体头中记录着文件名长度、数据块数量、数据块ID大小和最后一个数据块大小等信息。紧接着是文件名数据,长度在实体头中定义。文件名数据之后,存储着一组唯一数据块的编号,编号与唯一数据块集中的数据块一一对应。最后存储着文件最后一个数据块,由于这个数据块大小通常比正常数据块小,重复概率非常小,因此单独保存。
3、原型实现
基于上面的数据布局,就可以实现支持重复数据删除的数据打包方法。本人在Linux系统上实现了一个原型,实现中使用了hashtable来记录和查询唯一数据块信息,使用MD5算法计算数据块指纹,并使用zlib中的z77压缩算法对删除了重复数据后的数据包进行压缩。hashtable, MD5, z77算法和实现,这里不作介绍,有兴趣的读者可以参考相关资源。下面给出dedup.h, dedup.c undedup.c源码文件。目前实现的原型还相对比较粗糙。
/* dedup.h */
- #ifndef _DEDUP_H
- #define _DEDUP_H
- #include "md5.h"
- #include "hash.h"
- #include "hashtable.h"
- #include "libz.h"
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * deduplication file data layout
- * --------------------------------------------------
- * | header | unique block data | file metadata |
- * --------------------------------------------------
- *
- * file metedata entry layout
- * -----------------------------------------------------------------
- * | entry header | pathname | entry data | last block data |
- * -----------------------------------------------------------------
- */
- typedef unsigned int block_id_t;
- #define BLOCK_SIZE 4096 /* 4K Bytes */
- #define BACKET_SIZE 10240
- #define MAX_PATH_LEN 255
- #define BLOCK_ID_SIZE (sizeof(block_id_t))
- /* deduplication package header */
- #define DEDUP_MAGIC_NUM 0x1329149
- typedef struct _dedup_package_header {
- unsigned int block_size;
- unsigned int block_num;
- unsigned int blockid_size;
- unsigned int magic_num;
- unsigned int file_num;
- unsigned long long metadata_offset;
- } dedup_package_header;
- #define DEDUP_PKGHDR_SIZE (sizeof(dedup_package_header))
- /* deduplication metadata entry header */
- typedef struct _dedup_entry_header {
- unsigned int path_len;
- unsigned int block_num;
- unsigned int entry_size;
- unsigned int last_block_size;
- int mode;
- } dedup_entry_header;
- #define DEDUP_ENTRYHDR_SIZE (sizeof(dedup_entry_header))
- #ifdef __cplusplus
- }
- #endif
- #endif
/* dedup.c */
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <dirent.h>
- #include <unistd.h>
- #include <getopt.h>
- #include <fcntl.h>
- #include <dirent.h>
- #include <errno.h>
- #include "dedup.h"
- /* unique block number in package */
- static unsigned int g_unique_block_nr = 0;
- /* regular file number in package */
- static unsigned int g_regular_file_nr = 0;
- /* block length */
- static unsigned int g_block_size = BLOCK_SIZE;
- /* hashtable backet number */
- static unsigned int g_htab_backet_nr = BACKET_SIZE;
- void show_md5(unsigned char md5_checksum[16])
- {
- int i;
- for (i = 0; i < 16; i++)
- {
- printf("%02x", md5_checksum[i]);
- }
- }
- void show_pkg_header(dedup_package_header dedup_pkg_hdr)
- {
- printf("block_size = %d/n", dedup_pkg_hdr.block_size);
- printf("block_num = %d/n", dedup_pkg_hdr.block_num);
- printf("blockid_size = %d/n", dedup_pkg_hdr.blockid_size);
- printf("magic_num = 0x%x/n", dedup_pkg_hdr.magic_num);
- printf("file_num = %d/n", dedup_pkg_hdr.file_num);
- printf("metadata_offset = %lld/n", dedup_pkg_hdr.metadata_offset);
- }
- int dedup_regfile(char *fullpath, int prepos, int fd_bdata, int fd_mdata, hashtable *htable, int debug)
- {
- int fd;
- char *buf = NULL;
- unsigned int rwsize, pos;
- unsigned char md5_checksum[16 + 1] = {0};
- unsigned int *metadata = NULL;
- unsigned int block_num = 0;
- struct stat statbuf;
- dedup_entry_header dedup_entry_hdr;
- if (-1 == (fd = open(fullpath, O_RDONLY)))
- {
- perror("open regulae file");
- return errno;
- }
- if (-1 == fstat(fd, &statbuf))
- {
- perror("fstat regular file");
- goto _DEDUP_REGFILE_EXIT;
- }
- block_num = statbuf.st_size / g_block_size;
- metadata = (unsigned int *)malloc(BLOCK_ID_SIZE * block_num);
- if (metadata == NULL)
- {
- perror("malloc metadata for regfile");
- goto _DEDUP_REGFILE_EXIT;
- }
- buf = (char *)malloc(g_block_size);
- if (buf == NULL)
- {
- perror("malloc buf for regfile");
- goto _DEDUP_REGFILE_EXIT;
- }
- pos = 0;
- while (rwsize = read(fd, buf, g_block_size))
- {
- /* if the last block */
- if (rwsize != g_block_size)
- break;
- /* calculate md5 */
- md5(buf, rwsize, md5_checksum);
- /* check hashtable with hashkey */
- unsigned int *bindex = (block_id_t *)hash_value((void *)md5_checksum, htable);
- if (bindex == NULL)
- {
- bindex = (unsigned int *)malloc(BLOCK_ID_SIZE);
- if (NULL == bindex)
- {
- perror("malloc in dedup_regfile");
- break;
- }
- /* insert hash entry and write unique block into bdata*/
- *bindex = g_unique_block_nr;
- hash_insert((void *)strdup(md5_checksum), (void *)bindex, htable);
- write(fd_bdata, buf, rwsize);
- g_unique_block_nr++;
- }
- metadata[pos] = *bindex;
- memset(buf, 0, g_block_size);
- memset(md5_checksum, 0, 16 + 1);
- pos++;
- }
- /* write metadata into mdata */
- dedup_entry_hdr.path_len = strlen(fullpath) - prepos;
- dedup_entry_hdr.block_num = block_num;
- dedup_entry_hdr.entry_size = BLOCK_ID_SIZE;
- dedup_entry_hdr.last_block_size = rwsize;
- dedup_entry_hdr.mode = statbuf.st_mode;
- write(fd_mdata, &dedup_entry_hdr, sizeof(dedup_entry_header));
- write(fd_mdata, fullpath + prepos, dedup_entry_hdr.path_len);
- write(fd_mdata, metadata, BLOCK_ID_SIZE * block_num);
- write(fd_mdata, buf, rwsize);
- g_regular_file_nr++;
- _DEDUP_REGFILE_EXIT:
- close(fd);
- if (metadata) free(metadata);
- if (buf) free(buf);
- return 0;
- }
- int dedup_dir(char *fullpath, int prepos, int fd_bdata, int fd_mdata, hashtable *htable, int debug)
- {
- DIR *dp;
- struct dirent *dirp;
- struct stat statbuf;
- char subpath[MAX_PATH_LEN] = {0};
- if (NULL == (dp = opendir(fullpath)))
- {
- return errno;
- }
- while ((dirp = readdir(dp)) != NULL)
- {
- if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
- continue;
- sprintf(subpath, "%s/%s", fullpath, dirp->d_name);
- if (0 == lstat(subpath, &statbuf))
- {
- if (debug)
- printf("%s/n", subpath);
- if (S_ISREG(statbuf.st_mode))
- dedup_regfile(subpath, prepos, fd_bdata, fd_mdata, htable,debug);
- else if (S_ISDIR(statbuf.st_mode))
- dedup_dir(subpath, prepos, fd_bdata, fd_mdata, htable, debug);
- }
- }
- closedir(dp);
- return 0;
- }
- int dedup_package(int path_nr, char **src_paths, char *dest_file, int debug)
- {
- int fd, fd_bdata, fd_mdata, ret = 0;
- struct stat statbuf;
- hashtable *htable = NULL;
- dedup_package_header dedup_pkg_hdr;
- char **paths = src_paths;
- int i, rwsize, prepos;
- char buf[1024 * 1024] = {0};
- if (-1 == (fd = open(dest_file, O_WRONLY | O_CREAT, 0755)))
- {
- perror("open dest file");
- ret = errno;
- goto _DEDUP_PKG_EXIT;
- }
- htable = create_hashtable(g_htab_backet_nr);
- if (NULL == htable)
- {
- perror("create_hashtable");
- ret = errno;
- goto _DEDUP_PKG_EXIT;
- }
- fd_bdata = open("./.bdata", O_RDWR | O_CREAT, 0777);
- fd_mdata = open("./.mdata", O_RDWR | O_CREAT, 0777);
- if (-1 == fd_bdata || -1 == fd_mdata)
- {
- perror("open bdata or mdata");
- ret = errno;
- goto _DEDUP_PKG_EXIT;
- }
- g_unique_block_nr = 0;
- g_regular_file_nr = 0;
- for (i = 0; i < path_nr; i++)
- {
- if (lstat(paths[i], &statbuf) < 0)
- {
- perror("lstat source path");
- ret = errno;
- goto _DEDUP_PKG_EXIT;
- }
- if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode))
- {
- if (debug)
- printf("%s/n", paths[i]);
- /* get filename position in pathname */
- prepos = strlen(paths[i]) - 1;
- if (strcmp(paths[i], "/") != 0 && *(paths[i] + prepos) == '/')
- {
- *(paths[i] + prepos--) = '/0';
- }
- while(*(paths[i] + prepos) != '/' && prepos >= 0) prepos--;
- prepos++;
- if (S_ISREG(statbuf.st_mode))
- dedup_regfile(paths[i], prepos, fd_bdata, fd_mdata, htable, debug);
- else
- dedup_dir(paths[i], prepos, fd_bdata, fd_mdata, htable, debug);
- }
- else
- {
- if (debug)
- printf("%s is not regular file or directory./n", paths[i]);
- }
- }
- /* fill up dedup package header */
- dedup_pkg_hdr.block_size = g_block_size;
- dedup_pkg_hdr.block_num = g_unique_block_nr;
- dedup_pkg_hdr.blockid_size = BLOCK_ID_SIZE;
- dedup_pkg_hdr.magic_num = DEDUP_MAGIC_NUM;
- dedup_pkg_hdr.file_num = g_regular_file_nr;
- dedup_pkg_hdr.metadata_offset = DEDUP_PKGHDR_SIZE + g_block_size * g_unique_block_nr;
- write(fd, &dedup_pkg_hdr, DEDUP_PKGHDR_SIZE);
- /* fill up dedup package unique blocks*/
- lseek(fd_bdata, 0, SEEK_SET);
- while(rwsize = read(fd_bdata, buf, 1024 * 1024))
- {
- write(fd, buf, rwsize);
- memset(buf, 0, 1024 * 1024);
- }
- /* fill up dedup package metadata */
- lseek(fd_mdata, 0, SEEK_SET);
- while(rwsize = read(fd_mdata, buf, 1024 * 1024))
- {
- write(fd, buf, rwsize);
- memset(buf, 0, 1024 * 1024);
- }
- if (debug)
- show_pkg_header(dedup_pkg_hdr);
- _DEDUP_PKG_EXIT:
- close(fd);
- close(fd_bdata);
- close(fd_mdata);
- unlink("./.bdata");
- unlink("./.mdata");
- hash_free(htable);
- return ret;
- }
- void usage()
- {
- printf("Usage: dedup [OPTION...] <target file> <source files ...>/n");
- printf("/nPackage files with deduplicaton technique./n");
- printf("Mandatory arguments to long options are mandatory for short options too./n");
- printf(" -z, --compress filter the archive through compress/n");
- printf(" -b, --block block size for deduplication, default is 4096/n");
- printf(" -t, --hashtable hashtable backet number, default is 10240/n");
- printf(" -d, --debug print debug messages/n");
- printf(" -h, --help give this help list/n");
- printf("/nReport bugs to <Aigui.Liu@gmail.com>./n");
- }
- int main(int argc, char *argv[])
- {
- char tmp_file[] = "./.dedup/0";
- int bz = 0, bhelp = 0, bdebug = 0;
- int ret = -1, c;
- struct option longopts[] =
- {
- {"compress", 0, &bz, 'z'},
- {"block", 1, 0, 'b'},
- {"hashtable", 1, 0, 't'},
- {"debug", 0, &bdebug, 'd'},
- {"help", 0, &bhelp, 'h'},
- {0, 0, 0, 0}
- };
- /* parse options */
- while ((c = getopt_long (argc, argv, "zb:t:dh", longopts, NULL)) != EOF)
- {
- switch(c)
- {
- case 'z':
- bz = 1;
- break;
- case 'b':
- g_block_size = atoi(optarg);
- break;
- case 't':
- g_htab_backet_nr = atoi(optarg);
- break;
- case 'd':
- bdebug = 1;
- break;
- case 'h':
- case '?':
- default:
- bhelp = 1;
- break;
- }
- }
- if (bhelp == 1 || (argc - optind) < 2)
- {
- usage();
- return 0;
- }
- if (bz)
- {
- /* dedup and compress */
- ret = dedup_package(argc - optind -1 , argv + optind + 1, tmp_file, bdebug);
- if (ret == 0)
- {
- ret = zlib_compress_file(tmp_file, argv[optind]);
- unlink(tmp_file);
- }
- }
- else
- {
- /* dedup only */
- ret = dedup_package(argc - optind - 1, argv + optind + 1, argv[optind], bdebug);
- }
- return ret;
- }
/* undedup.c */
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <getopt.h>
- #include <fcntl.h>
- #include <errno.h>
- #include "dedup.h"
- /* block length */
- static unsigned int g_block_size = BLOCK_SIZE;
- void show_pkg_header(dedup_package_header dedup_pkg_hdr)
- {
- printf("block_size = %d/n", dedup_pkg_hdr.block_size);
- printf("block_num = %d/n", dedup_pkg_hdr.block_num);
- printf("blockid_size = %d/n", dedup_pkg_hdr.blockid_size);
- printf("magic_num = 0x%x/n", dedup_pkg_hdr.magic_num);
- printf("file_num = %d/n", dedup_pkg_hdr.file_num);
- printf("metadata_offset = %lld/n", dedup_pkg_hdr.metadata_offset);
- }
- int prepare_target_file(char *pathname, char *basepath, int mode)
- {
- char fullpath[MAX_PATH_LEN] = {0};
- char path[MAX_PATH_LEN] = {0};
- char *p = NULL;
- int pos = 0, fd;
- sprintf(fullpath, "%s/%s", basepath, pathname);
- p = fullpath;
- while (*p != '/0')
- {
- path[pos++] = *p;
- if (*p == '/')
- mkdir(path, 0755);
- p++;
- }
- fd = open(fullpath, O_WRONLY | O_CREAT, mode);
- return fd;
- }
- int undedup_regfile(int fd, dedup_entry_header dedup_entry_hdr, char *dest_dir, int debug)
- {
- char pathname[MAX_PATH_LEN] = {0};
- block_id_t *metadata = NULL;
- unsigned int block_num = 0;
- char *buf = NULL;
- char *last_block_buf = NULL;
- long long offset, i;
- int fd_dest, ret = 0;
- metadata = (block_id_t *) malloc(BLOCK_ID_SIZE * dedup_entry_hdr.block_num);
- if (NULL == metadata)
- return errno;
- buf = (char *)malloc(g_block_size);
- last_block_buf = (char *)malloc(g_block_size);
- if (NULL == buf || NULL == last_block_buf)
- {
- ret = errno;
- goto _UNDEDUP_REGFILE_EXIT;
- }
- read(fd, pathname, dedup_entry_hdr.path_len);
- read(fd, metadata, BLOCK_ID_SIZE * dedup_entry_hdr.block_num);
- read(fd, last_block_buf, dedup_entry_hdr.last_block_size);
- fd_dest = prepare_target_file(pathname, dest_dir, dedup_entry_hdr.mode);
- if (fd_dest == -1)
- {
- ret = errno;
- goto _UNDEDUP_REGFILE_EXIT;
- }
- if (debug)
- printf("%s/%s/n", dest_dir, pathname);
- /* write regular block */
- block_num = dedup_entry_hdr.block_num;
- for(i = 0; i < block_num; ++i)
- {
- offset = DEDUP_PKGHDR_SIZE + metadata[i] * g_block_size;
- lseek(fd, offset, SEEK_SET);
- read(fd, buf, g_block_size);
- write(fd_dest, buf, g_block_size);
- }
- /* write last block */
- write(fd_dest, last_block_buf, dedup_entry_hdr.last_block_size);
- close(fd_dest);
- _UNDEDUP_REGFILE_EXIT:
- if (metadata) free(metadata);
- if (buf) free(buf);
- if (last_block_buf) free(last_block_buf);
- return ret;
- }
- int undedup_package(char *src_file, char *dest_dir, int debug)
- {
- int fd, i, ret = 0;
- dedup_package_header dedup_pkg_hdr;
- dedup_entry_header dedup_entry_hdr;
- unsigned long long offset;
- if (-1 == (fd = open(src_file, O_RDONLY)))
- {
- perror("open source file");
- return errno;
- }
- if (read(fd, &dedup_pkg_hdr, DEDUP_PKGHDR_SIZE) != DEDUP_PKGHDR_SIZE)
- {
- perror("read dedup_package_header");
- ret = errno;
- goto _UNDEDUP_PKG_EXIT;
- }
- if (debug)
- show_pkg_header(dedup_pkg_hdr);
- offset = dedup_pkg_hdr.metadata_offset;
- for (i = 0; i < dedup_pkg_hdr.file_num; ++i)
- {
- if (lseek(fd, offset, SEEK_SET) == -1)
- {
- ret = errno;
- break;
- }
- if (read(fd, &dedup_entry_hdr, DEDUP_ENTRYHDR_SIZE) != DEDUP_ENTRYHDR_SIZE)
- {
- ret = errno;
- break;
- }
- ret = undedup_regfile(fd, dedup_entry_hdr, dest_dir, debug);
- if (ret != 0)
- break;
- offset += DEDUP_ENTRYHDR_SIZE;
- offset += dedup_entry_hdr.path_len;
- offset += dedup_entry_hdr.block_num * dedup_entry_hdr.entry_size;
- offset += dedup_entry_hdr.last_block_size;
- }
- _UNDEDUP_PKG_EXIT:
- close(fd);
- return ret;
- }
- void usage()
- {
- printf("Usage: undedup [OPTION...] <source file>/n");
- printf("/nUnpackage files with deduplicaton technique./n");
- printf("Mandatory arguments to long options are mandatory for short options too./n");
- printf(" -z, --uncompress filter the archive through uncompress/n");
- printf(" -c, --directory change to directory, default is PWD/n");
- printf(" -d, --debug print debug messages/n");
- printf(" -h, --help give this help list/n");
- printf("/nReport bugs to <Aigui.Liu@gmail.com>./n");
- }
- int main(int argc, char *argv[])
- {
- char tmp_file[] = "./.dedup/0";
- char path[MAX_PATH_LEN] = "./0";
- int bz = 0, bhelp = 0, bdebug = 0;
- int ret = -1, c;
- struct option longopts[] =
- {
- {"compress", 0, &bz, 'z'},
- {"directory", 1, 0, 'c'},
- {"debug", 0, &bdebug, 'd'},
- {"help", 0, &bhelp, 'h'},
- {0, 0, 0, 0}
- };
- while ((c = getopt_long (argc, argv, "zc:dh", longopts, NULL)) != EOF)
- {
- switch(c)
- {
- case 'z':
- bz = 1;
- break;
- case 'c':
- sprintf(path, "%s", optarg);
- break;
- case 'd':
- bdebug = 1;
- break;
- case 'h':
- case '?':
- default:
- bhelp = 1;
- break;
- }
- }
- if (bhelp == 1 || (argc - optind) < 1)
- {
- usage();
- return 0;
- }
- if (bz)
- {
- /* uncompress and undedup */
- ret = zlib_decompress_file(argv[optind], tmp_file);
- if (ret == 0)
- {
- ret = undedup_package(tmp_file, path, bdebug);
- unlink(tmp_file);
- }
- }
- else
- {
- /* only undedup */
- ret = undedup_package(argv[optind], path, bdebug);
- }
- return ret;
- }
/* dedup usage */
Usage: dedup [OPTION...] <target file> <source files ...>
Package files with deduplicaton technique.
-z, --compress filter the archive through compress
-b, --block block size for deduplication, default is 4096
-t, --hashtable hashtable backet number, default is 10240
-d, --debug print debug messages
-h, --help give this help list
/* undedup usage */
Usage: undedup [OPTION...] <source file>
Unpackage files with deduplicaton technique.
-z, --uncompress filter the archive through uncompress
-c, --directory change to directory, default is PWD
-d, --debug print debug messages
-h, --help give this help list
4、初步测试
这里使用linux最新的kernel源码进行测试,并与tar工具进行比较。从www.kernel.org 下载linux-2.6.32.tar.gz文件,并解压出源文件,然后分别使用tar和dedup工具进行打包,分别得到以下几个文件。
Filename |
File size |
commands |
linux-2.6.32.tar |
382392320 (365MB) |
tar cvf linux-2.6.32.tar linux-2.6.32/ |
linux-2.6.32.tar.dd |
380381944 (363M) |
dedup linux-2.6.32.tar.dd linux-2.6.32.tar |
linux-2.6.32.dd |
357325910 (341MB) |
dedup linux-2.6.32.dd linux-2.6.32/ |
linux-2.6.32.tar.gz |
84322110 (81MB) |
gzip -c linux-2.6.32.tar > linux-2.6.32.tar.gz |
linux-2.6.32.tar.dd.gz |
83978234 (81MB) |
gzip -c linux-2.6.32.tar.dd > linux-2.6.32.tar.dd.gz |
linux-2.6.32.dd.gz |
83674306 (80MB) |
gzip -c linux-2.6.32.dd > linux-2.6.32.dd.gz |
linux-2.6.32.tar.gz解压出来的kernel源码文件数据很多,使用这个文件来测试应该具有普遍的意义。通过初步的测试结果,我们可以看出,即使在这样不明确数据是否具备较高重复率的情况下,dedup技术也能较明显地减少数据包的数据量。在数据重复率很高的测试用例下,比如全0或全1的大文件,dedup要远远优于tar。比如,全0的64MB文件,tar+gzip的结果为65KB,而dedup的结果才有286字节。
5、TODO
1、变长数据块。目前是定长数据块的实现,技术上较为简单,变长数据块可能会获得更高的数据压缩率。
2、相似文件识别。如果两个文件只有很小的差别,比如在某处插入了若干字节,找出这些数据块并单独处理,可能会提高数据压缩率。
原文博客地址:
http://blog.csdn.net/liuaigui/article/details/5166538
(转)
基于Dedup的数据打包技术的更多相关文章
- 基于Web的数据推送技术(转)
基于Web的数据推送技术 对于实时性数据显示要求比较高的系统,比如竞价,股票行情,实时聊天等,我们的解决方案有以下几种.1. HTTP请求发送模式,一般可以基于ajax的请求,比如每3秒一次访问下服务 ...
- (转)基于RTP的H264视频数据打包解包类
最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包.解包的文档和代码.功夫不负有心人,找到不少有价值的文档和代码.参考这些资料,写了H264 RTP打包类.解包类,实现 ...
- 客户端技术的一点思考(数据存储用SQLite, XMPP通讯用Gloox, Web交互用LibCurl, 数据打包用Protocol Buffer, socket通讯用boost asio)
今天看到CSDN上这么一篇< 彻底放弃没落的MFC,对新人的忠告!>, 作为一个一直在Windows上搞客户端开发的C++程序员,几年前也有过类似的隐忧(参见 落伍的感觉), 现在却有一些 ...
- 字节跳动数据平台技术揭秘:基于 ClickHouse 的复杂查询实现与优化
更多技术交流.求职机会.试用福利,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 ClickHouse 作为目前业内主流的列式存储数据库(DBMS)之一,拥有着同类型 DBMS 难以企及 ...
- NoSQL 数据建模技术(转)
本文转载自:http://coolshell.cn/articles/7270.html ================================================ 全文译自墙外 ...
- NoSQL数据建模技术
原文来自“NoSQL Data Modeling Techniques”,由酷壳网陈皓编译<NoSQL数据建模技术>.这篇文章看完之后,你可能会对NoSQL的数据结构会有些感觉.我的感觉是 ...
- 推文《阿里凑单算法首次公开!基于Graph Embedding的打包购商品挖掘系统解析》笔记
推文<阿里凑单算法首次公开!基于Graph Embedding的打包购商品挖掘系统解析>笔记 从17年5月份开始接触Graph Embedding,学术论文读了很多,但是一直不清楚这技术是 ...
- 一种基于HBase韵海量图片存储技术
针对海量图片存储,已有若干个基于Hadoop的方案被设计出来.这些方案在系统层小文件合并.全局名字空间以及通用性方面存在不足.本文基于HBase提出了一种海量图片存储技术,成功解决了上述问题.本文将介 ...
- 徒手打造基于Spark的数据工厂(Data Factory):从设计到实现
在大数据处理和人工智能时代,数据工厂(Data Factory)无疑是一个非常重要的大数据处理平台.市面上也有成熟的相关产品,比如Azure Data Factory,不仅功能强大,而且依托微软的云计 ...
随机推荐
- errno之我见
Errno能帮我们找到系统函数的错误信息. 比方open函数,假设正常返回时,其返回值是一个非负的整数. 异常时会返回-1.同一时候该系统函数会设置errno的值.让我们能够了解错误的原因. Errn ...
- 更改Android应用程序的图标
对于android应用程序的开发.默认的图标是一个小机器人,图片名称为ic_launcher.png. 可是,大多数开发人员是会将这个图标在开发过程中改为自己设计的icon. 把apk图标更改为自己设 ...
- navicat 快速复制表所有字段
查询-新建查询-查询创建工具-选择表-全选字段-查询编辑器
- php 利用转转法去除重复数组
w3scool学习地址 http://www.w3school.com.cn/tiy/s.asp?f=demo_php_func_array_flip 利用array键名不能重复的原理,使用两次 ar ...
- Latex算法伪代码使用总结
Latex伪代码使用总结 algorithmicx例子 相应代码: \documentclass[11pt]{ctexart} \usepackage[top=2cm, bottom=2cm, lef ...
- python科学计算基础知识
1.导入基本函数库 import numpy as np 2.获取矩阵元素字节数 a=np.array([1,2,3],dtype=np.float32) a.itemsizeoutput: 4 3. ...
- ubuntu常用的一些命令
1 添加root用户 其实ubuntu在安装时已经添加了root用户,只是屏蔽了.所以只需要激活即可.打开终端ctrl+alt+t,输入sudo passwd root,然后输入要添加给root的密码 ...
- C 指针改变变量值
/** *通过指针改变局部变量值 **/ #include"stdio.h"#include"stdlib.h" void work(char* chuck){ ...
- 配置 Sliverlight 跨域访问策略
Silverlight程序在访问非本域资源时,需要在相应的域根目录下建立跨域访问策略文件才能进行访问. 文件名:clientaccesspolicy.xml 文件内容: <?xml versio ...
- centos升级glibc动态库
glibc是gnu发布的libc库,即c运行库,glibc是linux系统中最底层的api,几乎其它任何运行库都会依赖于glibc.glibc除了封装linux操作系统所提供的系统服务外,它本身也提供 ...