• 从ceph对象中提取RBD中的指定文件


    前言

    之前有个想法,是不是有办法找到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
  • 相关阅读:
    【算法设计与分析基础】8、背包问题
    【算法设计与分析基础】8、穷举 旅行商问题
    【算法设计与分析基础】7、蛮力求平面中距离最近的两点
    【算法设计与分析基础】6、蛮力字符匹配
    【算法设计与分析基础】5、冒泡排序与选择排序
    【算法设计与分析基础】4、伪随机数
    【算法设计与分析基础】3、斐波拉契数列
    【算法设计与分析基础】2、矩阵相乘
    【算法设计与分析基础】1、埃拉托色尼筛选法
    【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列
  • 原文地址:https://www.cnblogs.com/zphj1987/p/13575450.html
Copyright © 2020-2023  润新知