1.基本原理介紹
1.1 ceph中的對象(object)
在Ceph存儲中,一切數據最終都會以對象(Object)的形式存儲在硬盤(OSD)上,每個的Object默認大小為4M。
通過rados命令,可以查看一個存儲池中的所有object信息,例如下面的命令列出了存儲池中的所有object。
rados -p pool-842bd759258f4ec9843afd1e78549350 ls
1.2 rbd塊與object之間的對應關系
知道一切數據都會以object的形式存在于硬盤中后,我們還需要了解對象和rbd塊之間的對應關系是什么。在ceph存儲中,每個rbd塊都有一個block_name_prefix。這個值是唯一的,通過rbd info或rados命令可以查詢到,每個存儲rbd塊真實數據的對象會以這個作為名稱前綴。所以通過blocak_name_prefix我們可以找到rbd塊對應的對象有哪些。
1.3?rbd塊中object的先后順序如何區分
我們知道,一個object的大小為4M,因此一個rbd塊對應的object通常會有多個。那么我們如何知道一個object對應rbd塊中的哪一部分數據呢?要知道這個,我們就需要了解一下object的命令規則。
Object 名稱由三部分組成:
-
rbd_data.:這是 RBD 存儲卷的默認塊名稱前綴,用來標識這個 Object 存儲的是一個 RBD 存儲卷。
-
115ea266096aee.:這是 RBD 存儲卷的 ID,用來唯一標識一個 RBD 存儲卷。每個 RBD 存儲卷有一個唯一的 ID,可以通過 rbd info 命令查看。
-
0000000000000c45:這是塊的序號,用于標識這個 Object 存儲的是 RBD 存儲卷中的第幾個塊。在 RBD 存儲卷中,每個塊都有一個唯一的序號。采用的是16進制
所以通過objec的序號,我們可以知道object中保存了rbd塊中哪個位置的數據。
2.object操作工具介紹
ceph-objectstore-tool是ceph提供的一個能對osd中存儲的object進行增刪改查的工具。該工具只能操作處于停止狀態的osd。
下面的命令列出osd2中所有的object,包括object所屬的pg和位置信息
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-2 --op list
下面的命令是根據上一條命令獲取的信息將object導出到本地的文件test.raw中
ceph-objectstore-tool?--data-path?/var/lib/ceph/osd/ceph-2/?--type?bluestore?--pgid?$pgid?‘$Object_attr’?get-bytes?>?test.raw
?
3.離線導出數據實戰
3.1數據導出整體流程
-
通過rbd的name,獲取rbd塊的object前綴
-
停止掉一臺服務器上的全部osd,通過object前綴找出rbd相關的所有對象數據并導出。三副本故障域為服務器的情況下,如果ceph集群有四臺或以上存儲服務器的話,一臺服務器上可能不具備一個rbd塊的完整副本,需要將多個節點的osd上導出的數據拼成一個完整的副本。
-
通過dd命令將所有對象數據拼接成一個完整的rbd卷
3.2手動導出數據
rados -p $pool-name listomapvals rbd_directory|grep $rbd_name -C 5 ##獲取rbd塊的blocak_name_prefix信息
通過上圖可以看到rbd的id為59adb9d46665c,可以得到blocak_name_prefix為rbd_data.59adb9d46665c
接著查詢osd2中與rbd塊相關的對象,查詢前需要先將osd2停,輸出的結果中一行為一個對象。
systemctl stop ceph-osd@2
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-2 --op list 2>/dev/null | grep rbd_data.59adb9d46665c
再通過查詢到的object信息,將object數據導出到本地
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-$i/ --type bluestore --pgid $PGID '$OBJECT_JSON' get-bytes > $RBD_PREFIX/$OID
通過dd命令創建一個新卷,再將object中的數據復制到新卷中,復制對象中的數據時,要根據object的位置調整數據寫入的位置,即seek的值。object數據復制操作要執行多次,直到所有object中的數據都復制到創建的新卷中,數據導出操作完成。
dd if=/dev/zero of=rbd_data.1cabc42df0c8c4.raw bs=1 count=0 seek=2147483648 ##創建一個空文件,用來放對象的中的數據
echo $(( 0x00000000000000ff )) ##16進制轉十進制,獲取對象在rbd塊中的位置信息
dd?if=rbd_data.1cabc42df0c8c4.0000000000000000?of=rbd_data.1cabc42df0c8c4.raw?seek=0?bs=4M?count=1?conv=notrunc???##將對象中的數據復制到之前創建的空文件中。
?
數據導出完成后,默認是一個raw格式的文件,可以根據需要轉換成qcow2或其他格式的文件。
?
qemu-img convert -f raw -O qcow2 -p rbd_data.115ea266096aee.build.raw restore.qcow2
3.3通過腳本導出數據
手動導出rbd數據是一個十分繁瑣的操作,因此下面提供了兩個腳本,可以完成導出對象數據,以及將對象數據合并成一個新卷的操作。
數據導出腳本,將某個rbd中的對象從osd中導出到本地。腳本執行前有兩個地方需要修改。RBD_PREFIX的值修改為要導出rbd的blocak_name_prefix。declare osds的值修改為要執行腳本服務器上所有的osd id。
#!/bin/bash
# Export rbd_data.xxxxxxxxx to local file from all inactive osds
# Number of concurrent
N=64
RBD_PREFIX=rbd_data.39c97c1ed6026c
mkdir $RBD_PREFIX
#all osd id in one ceph node
declare osds=(8 9 10 11)
for i in ${osds[@]}
do
(echo $RBD_PREFIX in osd $i
echo "Export object..."
for j in $(ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-$i --op list 2>/dev/null|grep $RBD_PREFIX)
do
echo $j
PGID=$(echo $j|jq ".[0]" -r)
OBJECT_JSON=$(echo $j | jq ".[1]")
OID=$(echo $j | jq ".[1].oid" -r)
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-$i/ --type bluestore --pgid $PGID "$OBJECT_JSON" get-bytes > $RBD_PREFIX/$OID
done
) &
if [[ $(jobs -r -p | wc -l) -ge $N ]]; then
wait
fi
done
wait
echo?"All?done."
數據合并腳本。將導出到本地的對象中的數據復制到一個新卷中。腳本在執行前需要將RBD_PREFIX的值修改為要導出rbd的blocak_name_prefix。
#!/bin/bash
RBD_PREFIX=rbd_data.3262b63ba984f7
IMAGE_NAME=$RBD_PREFIX.build.raw
rm -f $IMAGE_NAME
dd if=/dev/zero of=$IMAGE_NAME bs=1 count=0 seek=2147483648
for i in $(ls ./$RBD_PREFIX | sort)
do
idx=$(echo $i|awk -F '.' '{print $3}')
idxOct=$(echo $((0x$idx)))
dd if=./$RBD_PREFIX/$i of=$IMAGE_NAME seek=$idxOct bs=4M count=1 conv=notrunc
done
4 總結
ceph本身提供了rbd export命令用來導出rbd塊。用命令導出數據的方式更簡單直接。本文主要針對某些osd無法啟動、rbd命令無法執行的場景,可以通過文中的方式來進行數據導出。同時通過這種導出對象的方式,我們也能了解ceph數據存儲的更多細節。
5 參考資料
https://docs.ceph.com/en/pacific/man/8/ceph-objectstore-tool/