前言

之前有个想法,是不是有办法找到rbd中的文件与对象的关系,想了很久但是一直觉得文件系统比较复杂,在fs 层的东西对ceph来说是透明的,并且对象大小是4M,而文件很小,可能在fs层进行了合并,应该很难找到对应关系,最近看到小胖有提出这个问题,那么就再次尝试了,现在就是把这个实现方法记录下来

这个提取的作用个人觉得最大的好处就是一个rbd设备,在文件系统层被破坏以后,还能够从rbd提取出文件,我们知道很多情况下设备的文件系统一旦破坏,无法挂载,数据也就无法读取,而如果能从rbd中提取出文件,这就是保证了即使文件系统损坏的情况下,数据至少不丢失

本篇是基于xfs文件系统情况下的提取,其他文件系统有时间再看看,因为目前使用的比较多的就是xfs文件系统

本篇也回答了一个可能会经常被问起的问题,能告诉我虚拟机里面的文件在后台存储在哪里么,看完本篇就知道存储在哪里了

XFS文件系统介绍

[root@lab8106 ~]# mkfs.xfs -f /dev/rbd0p1
warning: device is not properly aligned /dev/rbd0p1
meta-data=/dev/rbd0p1 isize=256 agcount=9, agsize=162816 blks
= sectsz=512 attr=2, projid32bit=1
= crc=0 finobt=0
data = bsize=4096 blocks=1310475, imaxpct=25
= sunit=1024 swidth=1024 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=0
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=8 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0

XFS文件系统采取是AG管理的,每个AG维护自己的inode和数据,所以XFS文件系统是一种很容易扩展的文件系统,本篇里面主要用到的命令是xfs_bmap这个命令

[root@lab8106 ~]# xfs_bmap -lvp /etc/fstab
/etc/fstab:
EXT: FILE-OFFSET BLOCK-RANGE AG AG-OFFSET TOTAL FLAGS
0: [0..7]: 26645424..26645431 1 (431024..431031) 8 00000

一个文件最小就是8个block(512b),也就是4k,这个因为上面默认的xfs的格式化就是data bsize=4K,这个值可以自行调整的,本篇尽量用默认常规的参数来讲例子

查看man xfs_bmap这个命令可以看到:

Holes are marked by replacing the startblock..endblock with hole. All the file offsets and disk blocks are in units of 512-byte blocks, no matter what the filesystem's block size is.

意思是这个查询到的里面的计数单位都是512-byte,不管上层设置的block大小是多少,我们知道文件系统底层的sector就是512-byte,所以这个查询到的结果就可以跟当前的文件系统的sector的偏移量联系起来,这里强调一下,这个偏移量的起始位子为当前文件系统所在分区的偏移量,如果是多分区的情况,在计算整个偏移量的时候就要考虑分区的偏移量了,这个会在后面用实例进行讲解的

rbd的对象是不清楚内部分区的偏移量,所以在rbd层进行提取的时候是需要得到的是分区当中的文件相对整个磁盘的一个sector的偏移量

rbd的对象结构

[root@lab8106 ~]# rados -p rbd ls|grep data
rbd_data.25a636b8b4567.00000000000009ff
rbd_data.25a636b8b4567.00000000000001dd
rbd_data.25a636b8b4567.0000000000000000
rbd_data.25a636b8b4567.000000000000009f
rbd_data.25a636b8b4567.0000000000000459
rbd_data.25a636b8b4567.000000000000027e
rbd_data.25a636b8b4567.00000000000004ff
rbd_data.25a636b8b4567.000000000000027c
rbd_data.25a636b8b4567.000000000000027d
rbd_data.25a636b8b4567.0000000000000001
rbd_data.25a636b8b4567.000000000000013e
rbd_data.25a636b8b4567.00000000000003ba
rbd_data.25a636b8b4567.000000000000031b
rbd_data.25a636b8b4567.00000000000004f8

rbd被xfs格式化以后会产生一些对象,这些对象是以16进制名称的方式存储在后台的,也就是rbd大小一定的情况下对象数目是一定的,也就是名称也是一定的

[root@lab8106 ~]# parted -s /dev/rbd0 unit s print
Model: Unknown (unknown)
Disk /dev/rbd0: 20971520s
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: Number Start End Size File system Name Flags
1 1953s 10485759s 10483807s xfs primari
2 10485760s 20963327s 10477568s primari

上面可以看到rbd0的sector个数为20971520s

20971520s*512byte=10737418240byte=10485760KB=10240MB

sector的大小一定,总rbd大小一定的情况下sector的数目也是一定的,本篇实例的rbd大小

[root@lab8106 ~]# rbd info zp
rbd image 'zp':
size 10000 MB in 2500 objects
order 22 (4096 kB objects)
block_name_prefix: rbd_data.25a776b8b4567
format: 2
features: layering
flags:
create_timestamp: Sat Jul 22 18:04:12 2017

sector和ceph object的对应关系的查询

这个就像个map一样,需要把这个关系给找到,一个sector的区间对应到object的map,这里我用python写个简单的方法来做查询,也可以自己用其他语言来实现

首先查询到rbd的对象数目

[root@lab8106 ~]# rbd info zp
rbd image 'zp':
size 10000 MB in 2500 objects
order 22 (4096 kB objects)
block_name_prefix: rbd_data.25a776b8b4567
format: 2
features: layering
flags:
create_timestamp: Sat Jul 22 18:04:12 2017

处理脚本如下:

vim getsecob.py

添加下面内容

#! /bin/python
# *-* conding=UTF-8 *-* import commands def main():
getmap(2500) def getmap(object):
sector=int(object)*4096*1024/512
print "object:"+str(object)
print "sector:"+str(sector)
incre=sector/object
for item in range(int(object)):
a=int(item*8192)
b=int((item+1)*8192-1)
print str([a,b])+" --> "+"%016x" %item if __name__ == '__main__':
main()

其中getmap后面为对象数目

输出是这个形式的:

[root@lab8106 ~]# python getsecob.py
object:2500
sector:20480000
[0, 8191] --> 0000000000000000
[8192, 16383] --> 0000000000000001
[16384, 24575] --> 0000000000000002
[24576, 32767] --> 0000000000000003
[32768, 40959] --> 0000000000000004
[40960, 49151] --> 0000000000000005
···

对rbd0进行分区,分区后的结果如下

[root@lab8106 ~]# parted -s /dev/rbd0 unit s print
Model: Unknown (unknown)
Disk /dev/rbd0: 20480000s
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: Number Start End Size File system Name Flags
1 1953s 10240000s 10238048s primari
2 10248192s 20471807s 10223616s primari

这个是个测试用的image,大小为10G分成两个5G的分区,现在我们在两个分区里面分别写入两个测试文件,然后经过计算后,从后台的对象中把文件读出

mount /dev/rbd0p1 /mnt1
mount /dev/rbd0p2 /mnt2
cp /etc/fstab /mnt1
cp /etc/hostname /mnt2

首先获取文件在分区上的sector的偏移量

[root@lab8106 ~]# xfs_bmap -lvp /mnt1/fstab
/mnt1/fstab:
EXT: FILE-OFFSET BLOCK-RANGE AG AG-OFFSET TOTAL FLAGS
0: [0..7]: 8224..8231 0 (8224..8231) 8 01111

可以得到是(8224..8231)共8个sector

从上面的分区1的start的sector可以知道起始位置是1953,那么相对于磁盘的偏移量就变成了

(8224+1953..8231+1953) = (10177..10184)

这里说下,这个地方拿到偏移量后,直接通过对rbd设备进行dd读取也可以把这个文件读取出来,这个顺带讲下,本文主要是从对象提取:

dd if=/dev/rbd0 of=a bs=512 count=8 skip=10177

bs取512是因为sector的单位就是512b

这样就把刚刚的fstab文件读取出来了,skip就是文件的sector相对磁盘的起始位置,count就是文件所占的block数目

继续我们的对象提取方式,上面的(10177..10184)这个我们根据上面那个脚本输出的对象列表来找到对象

[8192, 16383] --> 0000000000000001

获取名称,这个因为我的是测试环境,就只有一个匹配,多个image的时候要过滤出对用的rbd的对象,用prifix过滤即可

[root@lab8106 ~]# rados -p rbd ls|grep 0000000000000001
rbd_data.25a776b8b4567.0000000000000001

下载对象

[root@lab8106 ~]# rados -p rbd get rbd_data.25a776b8b4567.0000000000000001 rbd_data.25a776b8b4567.0000000000000001

根据偏移量计算对象中的偏移量

(10177..10184)
[8192, 16383] --> 0000000000000001

得到

10177-8192=1985

dd if=rbd_data.25a776b8b4567.0000000000000001 of=a bs=512 count=8 skip=1985

得到的文件a的内容即为之前文件的内容

准备取第二个分区的文件

[root@lab8106 ~]# xfs_bmap -lvp /mnt2/hostname
/mnt2/hostname:
EXT: FILE-OFFSET BLOCK-RANGE AG AG-OFFSET TOTAL FLAGS
0: [0..7]: 8224..8231 0 (8224..8231) 8 01111

8224+10248192..8231+10248192=10256416..10256423

从磁盘方式

[root@lab8106 ~]# dd if=/dev/rbd0 of=a bs=512 count=8 skip=10256416

从对象方式

10256416..10256423 对应

[10256384, 10264575] --> 00000000000004e4

对象偏移量

10256416-10256384=32
rados -p rbd get
[root@lab8106 ~]# rados -p rbd get rbd_data.25a776b8b4567.00000000000004e4 rbd_data.25a776b8b4567.00000000000004e4

获取文件

[root@lab8106 ~]# dd if=rbd_data.25a776b8b4567.00000000000004e4 of=a bs=512 count=8 skip=32

如果文件比较大的情况,可能出现就是文件是跨对象的,那么还是跟上面的提取方法一样,然后进行提取后的文件进行合并即可

总结

在存储系统上面存储的文件必然会对应到底层磁盘的sector,而sector也是会一一对应到后台的对象的,这个在本文当中得到了验证,所以整个逻辑就是,在文件系统层找到文件对应的sector位置,然后再在底层把sector和对象关系找好,就能从找到文件在对象当中的具体的位置,也就能定位并且能提取了,本篇是基于xfs的,其他文件系统只要能定位文件的sector,就可以在底层找到文件,这个以后会补充其他文件系统进来

变更记录

Why Who When
创建 武汉-运维-磨渣 2017-07-22

从ceph对象中提取RBD中的指定文件的更多相关文章

  1. SACD ISO镜像中提取DSDIFF(DFF)、DSF文件

                      听语音 | 浏览:5620 | 更新:2015-08-25 11:46 | 标签:硬件 1 2 3 4 5 分步阅读 现在有一种比较流行的无损音乐传输介质是SACD ...

  2. python学习笔记——爬虫中提取网页中的信息

    1 数据类型 网页中的数据类型可分为结构化数据.半结构化数据.非结构化数据三种 1.1 结构化数据 常见的是MySQL,表现为二维形式的数据 1.2 半结构化数据 是结构化数据的一种形式,并不符合关系 ...

  3. fortran中提取字符串中可见字符的索引

    fortran中常常需要提取字符串中可见字符的索引,下面是个小例子: !============================================================= su ...

  4. python中提取字典中的键值

    1 # 字典如下 2 movie = { 3 '妖猫传':['黄','染'], 4 '无问西东':['章','王'], 5 '超时空':['雷','佟'] 6 } 7 name = input('请输 ...

  5. C# 中提取表中的某一项数据

  6. sublime text3中sass编译后保存到指定文件夹

    第一步: tools->builde system->new build system 第二步: 粘贴如下代码到新建文档中: { "cmd": ["sass& ...

  7. 根据Excel文件中的内容,修改指定文件夹下的文件名称

    问题:根据Excel文件中内容,把文件名称由第2列,改为第1列.比如:把文件“123.jpg”修改为“1.jpg”.

  8. android中保存Bitmap图片到指定文件夹中的方法

    /** 保存方法 */  public void saveBitmap() {   Log.e(TAG, "保存图片");   File f = new File("/s ...

  9. Windows PE3.0制作方法(从Win7中提取制作)

    Windows PE3.0制作方法(从Win7中提取制作 在d:新建文件夹winpe,在winpe中新建sources.pe3和new文件夹,把附件中提供的工具imagex连文件夹一起放到winpe目 ...

随机推荐

  1. net core 微服务 快速开发框架

    dymDemo github 地址:https://github.com/duyanming/dymDemo dym 分布式开发框架 Demo 熔断 限流 事件总线(包括基于内存的.rabbitmq的 ...

  2. ansible使用file模块管理受控机的目录与文件(ansible2.9.5)

    一,ansible的file模块的用途 file 模块实现对文件的基本操作. 例如: 创建文件或目录 删除文件或目录 修改文件权限等 说明:刘宏缔的架构森林是一个专注架构的博客,地址:https:// ...

  3. git学习(八) git stash操作

    git stash命令的作用就是将目前还不想提交的但是已经修改的内容进行保存至堆栈中,后续可以在某个分支上恢复出堆栈中的内容.git stash作用的范围包括工作区和暂存区中的内容,没有提交的内容都会 ...

  4. elasticsearch mysql配置

    1,开启bin-log 2,binglog_foramt格式必须为row 3,配置server_id为1001 4,binlog-row-image 必须为full log-bin=mysql-bin ...

  5. java 封装多态继承

    java 面向对象思想 封装多态继承 面向过程与面向对象 编程分为面向对象编程和面向对象编程,汇编,C语言是面向过程写代码,C++/Java是面向对象 其实面向过程和面向对象在本质都是一样写代码,然后 ...

  6. 强网杯web之假的反序列化漏洞

    说明 打强网杯的时候一直在写论文, 做林逸师傅的培训题目. 现在得空,还是看了一部分的题目和wp. 源码 源码一共三部分, 这里只写下我知识盲区的一部分,作为自己的记录. <?php highl ...

  7. VMware Workstation Pro 虚拟机安装CentOS-7

    一.下载CentOS-7镜像 我是通过阿里开源镜像站下载的, 下载url:https://mirrors.aliyun.com/centos/7/isos/x86_64/ 下载CentOS-7-x86 ...

  8. Mybatis初学经验----------------(2)

    至于myBatis的配置,上篇文章中有,就不说了.今天谈谈myBatis编写Dao层时的用法. 传统Dao层代码需求 1.在Dao层实现类中,存在大量的模板方法,能否提取模板方法,减少我们的工作量. ...

  9. 关于cookie与本地 存储的区别的问题。

    关于cookie与本地 存储的区别的问题. 1. cookie在浏览器和服务器间来回传递.而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存. 2. coo ...

  10. 【总结】spring aop

    1.aop简介 AOP的全称是Aspect Oriented Programming,面向切面编程.它的主要思想是在程序正常执行的某一个点切进去加入特定的逻辑.AOP框架中对AOP支持最完整的是Asp ...