前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FileStore压缩存储(优化篇)

FileStore压缩存储(优化篇)

作者头像
腾讯云TStack
发布2018-03-21 17:47:01
2.5K0
发布2018-03-21 17:47:01
举报

前言

前面已经分析过RBD在Ceph的文件分布,就是将一个完整的块设备,映射成大小相同的数据块,然后通过Crush算法进行Map,最后存储在文件中。FileStore承担了文件的存储工作,其实就是将文件安装PG进展组织,然后分目录存储。

原理和动机

文件从filename依次会进行以下三个步骤进行,最后落到磁盘,如下:

•filename -> object_id: filename通过hash函数直接转换成一个objectid

•object_id -> pg: object_id其实是一个整数,通过 object_id%pg)num, 对应到相应的pg, 这是一个简单暴力的映射,当pg数发生变化时,将会有大量的pg会重新映射,因此在运营过程中,尽量避免调整pg数。

•pg -> osd: pg到osd的映射,是ceph区别于其他分布式文件系统核心所在,在这个过程中,采用的是如雷贯耳的crush算法,crush算法是可以根据机架,机房等进行可以干预的伪一致性hash,而hash的依据是CrushMap。

通过上面三个步骤,真正的文件会落到{pool_id}.{pg_id_}_head的目录下,存储的是原始文件,并没有任何的修改。考虑到之前做个文件压缩方面的相关工作,如果文件先压缩后存储,是否会比裸存储会更快呢,从之前的实验表明,也有磁盘性能和CPU的性能差异巨大,如果压缩算法选择较好,压缩+存储的时间有可能会小于裸存储的时间。

压缩算法对比:

压缩算法这里不详细介绍,早期用的是LZO算法,当时觉得LZO算法是最快最好的压缩算法了,后面Google出了snappy算法,网上有对比,居然比LZO更快,而且在hadoop中广泛应用,所有本次采用了snappy算法。网上的性能对比如下:

:来自《HBase: The Definitive Guide》

•GZIP的压缩率最高,但是其实CPU密集型的,对CPU的消耗比其他算法要多,压缩和 解压速度也慢;

•LZO的压缩率居中,比GZIP要低一些,但是压缩和解压速度明显要比GZIP快很多,其 中解压速度快的更多;

•Zippy/Snappy的压缩率最低,而压缩和解压速度要稍微比LZO要快一些。

系统设计

在Ceph中,默认块大小是4M(可以修改), 每次从OSD中传输到FileStore中的数据块大小也为4M,那我们安装块大小的方式进行压缩存储,比较符合Ceph的默认行为,由于压缩以后,块大小并不统一,因此需要有个表来记录数据块的大小和偏移。那我们在文件的头部,设计了1KB大小的数据空间,来存储数据表。如下:

block_size: 文件的压缩前的真实大小

block_num: 文件压缩以后的块数

offset : 第x块的offset

block_len : 第x块的长度

为了支持超大文件和数据对齐,这里全部采用了64bit进行长度存储。那么如果头部设置了1KB,最多存储的块数是63块,按照4MB每块,最大文件为4MBx63=252MB,当然,头部大小是可以设置的。

数据结构设计

1、 宏定义:

1. #define HEADER_BLOCK_SIZE 1024 // 头部大小

2. #define HEADER_BOCK_NUM (HEADER_BLOCK_SIZE/16-1) //最大块数

2、 块描述:

1. struct BlockMeta {
2. uint64_t offset; // 偏移
3. uint64_t block_len; // 长度
4. }

3、 文件头描述:

1. class FileHeader {
2. public:
3. size_t block_size;
4. uint64_t block_num; // 为了对齐,采用64bit
5. BlockMeta block_list[HEADER_BOCK_NUM]; // 块描述列表
6. FDRef fd;
7.
8. FileHeader(FDRef fd);
9. uint64_t _get_size();
10. bool init();
11. bool save();
12. void add_block(uint64_toffset, uint64_tlen);
13. }

实现描述

实现主要涉及到FileStore.cc中的两个函数FileStore::_write和FileStore::read两个函数,主要修改如下:

FileStore::_write

1. if(cid==meta) // 判断是不是meta,不是meta才进行压缩
2. is_meta = true;
3.
4. r = lfn_open(cid, oid, true, &fd); // 打开文件
5. if (r < 0) {
6. ...
7. goto out;
8. }
9.
10. if(!is_meta){ // 打开文件头
11. fh = new FileHeader(fd);
12. fh->init();
13. offset = convert_offset(fh, offset, len); // 这边很关键,转换offset
14. }
15.
16. // seek
17. actual = ::lseek64(**fd, offset, SEEK_SET);
18. if (actual < 0) {
19. ...
20. }
21.
22. if(!is_meta){
23. // write
24. size_t len_bz;
25. string out_bz;
26. string tmp;
27. // 由于bufferlist和snappy的compress的类型有差异,需要先将buffer拷贝到string中
28. // 后续看是否能够优化
29. bl.copy(0, len, tmp);
30. // 采用snanny压缩
31. len_bz = snappy::Compress(tmp.c_str(), len, &out_bz);
32.
33. // 压缩后的数据写入文件
34. r = safe_pwrite(**fd, out_bz.c_str(), len_bz, offset);
35. if (r == 0){
36. // 更新文件头
37. r = len_bz;
38. fh->add_block(offset, len_bz);
39. fh->save();
40. }
41. }else{
42. // write
43. r = bl.write_fd(**fd);

44. if (r == 0)
45. r = bl.length();
46. }

FileStore::read

1. if(cid==meta) // 判断是不是meta,不是meta才进行压缩
2. is_meta = true;
3.
4. int r = lfn_open(cid, oid, false, &fd);
5. if (r < 0) {
6. ...
7. return r;
8. }
9.
10. if(!is_meta){
11. fh = new FileHeader(fd); // 获取文件头
12. fh->init();
13. if (len == 0) {
14. len = fh->get_block_size();
15. }
16. }else{
17. if (len == 0) {
18. ...
19. len = st.st_size;
20. }
21. }
22.
23. if(!is_meta){
24. // 由于文件启用了压缩,需要对offset和len进行转换
25. uint64_t offset_bz = convert_offset(fh, offset, len);
26. uint64_t len_bz = convert_len(fh, offset, len);
27. bufferptr bptr_bz(len_bz);
28. // 读取压缩后的文件到buffsetlist
29. got = safe_pread(**fd, bptr_bz.c_str(), len_bz, offset_bz);
30.
31. if (got < 0) {
32. ...
33. return got;
34. }
35.
36. // 解压buffer
37. string out_unbz;
38. size_t len_unbz;
39. snappy::GetUncompressedLength(bptr_bz.c_str(), len_bz, &len_unbz);
40. snappy::Uncompress(bptr_bz.c_str(), len_bz, &out_unbz);
41. // 这里也进行了一次拷贝,后面考虑优化一下
42. bufferptr bptr(out_unbz.c_str(), len_unbz);
43. bptr_bz.set_length(len_unbz); // properly size the buffer
44. bl.push_back(bptr); // put it in the target bufferlist
45. }else{
46.
47. bufferptr bptr(len); // prealloc space for entire read
48. got = safe_pread(**fd, bptr.c_str(), len, offset);
49. if (got < 0) {
50. ...
51. return got;

52. }
53. bptr.set_length(got); // properly size the buffer
54. bl.push_back(bptr); // put it in the target bufferlist
测试

测试方法:

采用rados bench进行测试,向test pool中写入数据,时间30s,对比各项指标。

测试机器:

本次测试在vmware虚拟机上进行,配置如下:

cpu: i7-4790 CPU @ 3.60GHz * 4

_内存: 8G

磁盘: 20G * 4 (4个虚拟磁盘)

Ceph OSD配置:

1. [root@centos7 os]# ceph osd tree
2. # id weight type name up/down reweight
3. -1 4 root default
4. -3 4 rack rack01
5. -2 4 host node01
6. 0 1 osd.0 up 1

7. 1 1 osd.1 up 1
8. 2 1 osd.2 up 1
9. 3 1 osd.3 up 1

测试过程:

a、在没有启用压缩的Ceph集群上测试结果如下:

1. [root@centos7 ~]# rados bench -p test 30 write --no-cleanup
2. Maintaining 16 concurrent writes of 4194304bytes for up to 30 seconds
or 0 objects
3. Object prefix: benchmark_data_centos7_4889
4. sec Cur ops started finished avg MB/s cur MB/s last lat avg
lat
5. 0 0 0 0 0 0 - 0
6. 1 16 26 10 39.9737 40 0.793068 0.492239
7. 2 16 39 23 45.9619 52 1.49245 0.981307
8. ...
9. 31 16 181 165 21.2693 0 - 2.52853
10. 32 16 182 166 20.7295 2 5.26863 2.54504
11. 33 16 182 166 20.1013 0 - 2.54504
12. 34 16 182 166 19.5105 0 - 2.54504
13. Total time run: 34.639023
14. Total writes made: 182
15. Write size: 4194304
16. Bandwidth (MB/sec): 21.017
17.
18. Stddev Bandwidth: 19.3491
19. Max bandwidth (MB/sec): 64
20. Min bandwidth (MB/sec): 0
21. Average Latency: 3.03429

22. Stddev Latency: 2.70649
23. Max latency: 10.2387
24. Min latency: 0.104269

注: 上面结果均测试了3次,取了一次中间结果。

测试结果:

:上面的优化结果是采用[压缩存储数值]/[原始存储数值], (+)表示提升,(-)表示下降。

结果分析:

从上面的结果来看,吞吐率提高了1倍多,延迟降低超过50%,无论是吞吐率的方差,还是延迟的方差,都有很明显的下降,说明采用了压缩以后,系统性能稳定了很多,尤其是延迟方差,降低了将近80%。当然,由于测试的数据压缩比率比较高,性能偏好,在实际应用的时候,会受数据可压缩率的影响。

总结

本文从可FileStore层面,对Ceph做了压缩存储的优化,从测试效果来看,还是非常理想的,几乎提升了1倍多的性能。但是在实际应用中会受数据可压缩性的影响,启用压缩存储,对一些日志行的数据存储,是非常理想的选择。此工作只是一个优化的开始,其实后续还有很多的优化空间,比如,对数据进行动态选择压缩,或者在压缩的路径上进行优化,可以避免每个osd都重复压缩。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-05-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TStack 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档