CEPH-0001 - Ceph RBD Volume Header Recovery
1. Background
1.1. Ceph
7h sáng, chợt bị đánh thức từ nhiều cuộc gọi từ sếp. Mình vội dậy để kiểm tra thì thấy 1 trong các hệ thống Ceph mình đang quản lý hiện gặp lỗi, khiến cho các volumes trên Ceph không thể thao tác được nữa.
Sau 1 hồi thì mình cũng fix được, tuy nhiên impact khá lớn, khiến cho Ceph bị mất 1 số objects quan trọng, gây ra việc các group of objects tạo nên các volumes không còn hoàn chỉnh. Trong đó có sự cố rbd_header object bị mất, khiến cho RBD không ánh xạ được data của volume, dù cho data đó vẫn còn tồn tại trên Ceph.
Các Volume được ánh xạ thông qua RBD (RADOS Block Device) interface. Bài viết này sử dụng Octopus version nên sẽ chỉ debug format 2 volumes.
Bài viết này sẽ mô tả cách khôi phục rbd_header object dựa trên thông tin dữ liệu còn lại dựa trên RBD.
1.2. Tóm tắt
RBD (RADOS Block Device) là cách mà Ceph ánh xạ các objects, và OS sẽ xem như một block storage thông thường. Các objects sẽ được nhóm lại tạo thành volume, mỗi volume này sẽ gồm các objects mô tả các thông tin tương ứng, đại diện cho chính volume đó.
Object Prefix | Mô tả |
---|---|
rbd_id.NAME | Object chứa ID để định danh cho các objects tương ứng với NAME của volume |
rbd_header.ID | Object chứa các metadata của các objects tương ứng (features, object_prefix, size, ..) |
rbd_data.ID | Gồm các objects chứa data của volume với prefix được defined trong header |
1.3. Ví dụ
- Ceph Pool: VNDATA-0001
- RBD Volume Name: image01
1.3.1. rbd_id.image01
$ sudo rados -p VNDATA-0001 get rbd_id.image01 - strings
291615ea562c04
1.3.2. rbd_header.291615ea562c04
$ sudo rados -p VNDATA-0001 listomapvals rbd_header.291615ea562c04
access_timestamp
value (8 bytes) :
00000000 8d 96 94 62 ba 03 a9 06 |...b....|
00000008
create_timestamp
value (8 bytes) :
00000000 8d 96 94 62 ba 03 a9 06 |...b....|
00000008
features
value (8 bytes) :
00000000 3d 00 00 00 00 00 00 00 |=.......|
00000008
modify_timestamp
value (8 bytes) :
00000000 8d 96 94 62 ba 03 a9 06 |...b....|
00000008
object_prefix
value (27 bytes) :
00000000 17 00 00 00 72 62 64 5f 64 61 74 61 2e 32 39 31 |....rbd_data.291|
00000010 36 31 35 65 61 35 36 32 63 30 34 |615ea562c04|
0000001b
order
value (1 bytes) :
00000000 16 |.|
00000001
size
value (8 bytes) :
00000000 00 00 00 80 02 00 00 00 |........|
00000008
snap_seq
value (8 bytes) :
00000000 00 00 00 00 00 00 00 00 |........|
00000008
Ở đây, chúng ta có thể thấy các thông tin metadata của volume image01 tương ứng với rbd_header có ID 291615ea562c04 như timestamp, features, rbd_data prefix, size, ..
Ngoài ra, chúng ta có thể xem các thông tin này với format “dễ nhìn” hơn, với rbd cli
:
$ sudo rbd -p VNDATA-0001 info image01
rbd image 'image01':
size 10 GiB in 2560 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: 291615ea562c04
block_name_prefix: rbd_data.291615ea562c04
format: 2
features: layering, exclusive-lock, object-map, fast-diff, deep-flatten
op_features:
flags:
create_timestamp: Mon May 30 17:03:57 2022
access_timestamp: Mon May 30 17:03:57 2022
modify_timestamp: Mon May 30 17:03:57 2022
2. RBD Volume Header Recovery
2.1. Xây dựng kịch bản
Pool VNDATA-0001 với 5 volumes tương ứng với các dung lượng lớn nhỏ khác nhau, với 3 trong số 5 volumes sẽ bị mất rbd_header object, trong đó có 2 volume bị mất cả rbd_id object.
Ở đây, mình sẽ giả lập ở tình huống thực tế rằng không xác định được dung lượng USED cụ thể của từng volume.
$ sudo rbd du -p VNDATA-0001
NAME PROVISIONED USED
image01 10 GiB 4.1 GiB
image02 100 GiB 70 GiB
image03 70 GiB 50 GiB
image04 5 GiB 60 MiB
image05 150 GiB 20 GiB
335 GiB 145 GiB
2.2. Missing Volume rbd_header
Để “giả lập” tình huống mất volume rbd_header, mình dùng lệnh sau:
$ sudo rados -p VNDATA-0001 get rbd_id.image02 - strings
12632c59ecee6c
$ sudo rados -p VNDATA-0001 rm rbd_header.12632c59ecee6c
2.2.1. Xác định lỗi
Lúc này, mình sẽ thấy RBD báo lỗi, có thể thấy 3 volumes bị biến mất đó là image02, image03, image04, nhưng chỉ RBD chỉ báo 1 dòng lỗi.
$ sudo rbd du -p VNDATA-0001
2022-06-01T12:05:48.487+0700 7fd7e2ffd700 -1 librbd::image::OpenRequest: failed to retrieve initial metadata: (2) No such file or directory
NAME PROVISIONED USED
image01 10 GiB 4.1 GiB
image05 150 GiB 20 GiB
160 GiB 24 GiB
Mặc dù khi mình dùng rbd ls thì vẫn thấy có tên của 3 volumes này trong list.
$ sudo rbd ls -p VNDATA-0001
image01
image02
image03
image04
image05
Có thể thấy, dòng lỗi đó là báo rằng không thể đọc được metadata của volume vì:
- RBD get được ID của volume từ rbd_id.VOLUME_NAME object.
- Nhưng khi đọc đến rbd_header.ID object thì object này không tồn tại.
2.2.2. Xác định cụ thể lỗi của từng volume
Tiếp theo, mình sẽ liệt kê từng volume bằng lệnh rbd info để tìm volume đang bị mất rbd_id object.
$ sudo rbd -p VNDATA-0001 info image02
2022-06-01T11:56:27.760+0700 7fc780ff9700 -1 librbd::image::OpenRequest: failed to retrieve initial metadata: (2) No such file or directory
rbd: error opening image image02: (2) No such file or directory
$ sudo rbd -p VNDATA-0001 info image03
rbd: error opening image image03: (2) No such file or directory
$ sudo rbd -p VNDATA-0001 info image04
rbd: error opening image image04: (2) No such file or directory
Lúc này, mình đã xác định được lỗi của của 3 volumes:
- image02 bị lỗi mất rbd_header object.
- image03, image04 bị lỗi mất rbd_header object và rbd_id object.
2.3. Recover rbd_header object
Để recovery được các object, mình phải thu thập các thông tin từ dữ liệu sẵn có để đi gần hơn đến các volumes lỗi.
2.3.1. Xác định ID của các volumes bị lỗi tương ứng
Bước này, mình sẽ xác định cụ thể ID của volume lỗi mất rbd_header object và 2 volumes lỗi mất rbd_header và rbd_id object.
$ sudo rbd -p VNDATA-0001 ls | xargs -n1 bash -c 'echo "$0: $(sudo rados -p VNDATA-0001 get rbd_id.$0 - strings)"'
image01: 163c90c86bdec6
image02: 12632c59ecee6c
error getting VNDATA-0001/rbd_id.image03: (2) No such file or directory
image03:
error getting VNDATA-0001/rbd_id.image04: (2) No such file or directory
image04:
image05: 12638ff6e985d4
Thông tin mình có hiện tại như sau:
- image02: 12632c59ecee6c (lỗi mất rbd_header)
- image03: không xác định được ID (lỗi mất rbd_header và rbd_id)
- image04: không xác định được ID (lỗi mất rbd_header và rbd_id)
2.3.2. Xác định ID của volume lỗi mất rbd_id
Dựa vào rbd_data object để loại trừ các ID đã biết để tìm ra ID còn sót lại.
$ sudo rados ls -p VNDATA-0001 | grep rbd_data | awk -F'.' '{print $1"."$2}' | sort | uniq
rbd_data.123fb15cd8a797
rbd_data.12632c59ecee6c (image02)
rbd_data.126368a06c08b7
rbd_data.12638ff6e985d4 (image05)
rbd_data.163c90c86bdec6 (image01)
Đoạn này mới khó, không có rbd_header và rbd_id, chỉ có 2 ID không rõ nguồn gốc, công việc của mình là phải gán đúng 2 ID này với 2 volumes đã bị mất rbd_id object. Bỗng nhiên, mình phát hiện mỗi 1 rbd_data object đều có size là 4194304 iB = 4 MiB.
$ sudo rados -p VNDATA-0001 ls | head -n 5 | xargs -n1 bash -c 'echo "$0: $(sudo rados -p VNDATA-0001 stat $0 | grep -Eo "size [0-9]+")"'
rbd_data.12632c59ecee6c.0000000000003582: size 4194304
rbd_data.123fb15cd8a797.0000000000002cb9: size 4194304
rbd_data.123fb15cd8a797.00000000000014f7: size 4194304
rbd_data.123fb15cd8a797.00000000000007b0: size 4194304
rbd_data.163c90c86bdec6.0000000000000382: size 4194304
Mình có thể dựa vào dữ kiện này để phân biệt 2 ID còn lại của 2 volumes nào.
$ echo "rbd_data.123fb15cd8a797: $(($(sudo rados -p VNDATA-0001 ls | grep rbd_data.123fb15cd8a797 | wc -l)*4/1024)) GiB"
rbd_data.123fb15cd8a797: 50 GiB
$ echo "rbd_data.126368a06c08b7: $(($(sudo rados -p VNDATA-0001 ls | grep rbd_data.126368a06c08b7 | wc -l)*4/1024)) GiB"
rbd_data.126368a06c08b7: 0 GiB
(0 GiB là do bash shell làm tròn, nên dung lượng used của volume này < 1 GiB)
Lúc này, mình biết được hiện đang còn lại 2 volumes với dung lượng provisioned tương ứng.
NAME PROVISIONED USED
image03 70 GiB xx
image04 5 GiB xx
Mình có thể thấy có 1 ID rbd_data.123fb15cd8a797 có dung lượng used là 50 GiB. Trong khi đó, volume image04 chỉ có dung lượng provisioned là 5 GiB, không thể chứa được 50 GiB dung lượng dữ liệu, nên ID này chỉ có thể thuộc về volume image03.
Lúc này mình đã biết được đầy đủ ID của các volumes lỗi:
- image02: 12632c59ecee6c
- image03: 123fb15cd8a797
- image04: 126368a06c08b7
2.3.3. Recover rbd_id object
Mình sử dụng lệnh rados get và rados put để gán lại ID cho các volumes đã bị mất rbd_id object.
# image03
$ sudo rados -p VNDATA-0001 get rbd_id.image01 rbd_id
$ sudo sed -i 's/163c90c86bdec6/123fb15cd8a797/g' rbd_id
$ sudo rados -p VNDATA-0001 put rbd_id.image03 rbd_id
# image04
$ sudo rados -p VNDATA-0001 get rbd_id.image01 rbd_id
$ sudo sed -i 's/163c90c86bdec6/126368a06c08b7/g' rbd_id
$ sudo rados -p VNDATA-0001 put rbd_id.image04 rbd_id
Kiểm tra lại xem rbd_id object đã được gán đúng ID chưa.
$ sudo rados -p VNDATA-0001 get rbd_id.image03 - strings
123fb15cd8a797
$ sudo rados -p VNDATA-0001 get rbd_id.image04 - strings
126368a06c08b7
2.3.4. Get các metadata từ rbd_header của volume không lỗi
Sử dụng lệnh rados listomapvals để lấy metadata của volume image01.
$ sudo rados -p VNDATA-0001 listomapvals rbd_header.163c90c86bdec6
Ở đây, mình chỉ phục hồi rbd_header object vừa đủ thông tin để có thể access vào volume và lấy dữ liệu, chứ không hướng đến việc phục hồi hoàn chỉnh rbd_header về lúc không lỗi, nên chỉ chú ý đến những metadata quan trọng:
- features:
3d 00 00 00 00 00 00 00
- object_prefix:
17 00 00 00 rbd_data.163c90c86bdec6
- Mình sẽ dùng object_prefix tương ứng:
17 00 00 00 rbd_data.12632c59ecee6c
(image02)
- Mình sẽ dùng object_prefix tương ứng:
- order:
16
- size:
00 00 00 80 02 00 00 00
- Mình có 100 GiB = 107374182400 iB (image02 có dung lượng 100 GiB)
- Đổi qua mã hex, mình có 1900000000
- Dịch qua mã hex 8 bytes mà máy có thể đọc hiểu:
00 00 00 00 19 00 00 00
- snap_seq:
00 00 00 00 00 00 00 00
2.3.5. Recover rbd_header object
Recover rbd_header object bằng rados setomapval để gán các giá trị của metadata mà mình thu thập được ở 2.3.4.. Ở đây, mình sẽ ví dụ bằng image02 với ID 12632c59ecee6c, 2 volumes kia tương tự cách làm (chỉ thay rbd_data với ID tương ứng).
$ echo -en \\x3d\\x00\\x00\\x00\\x00\\x00\\x00\\x00 | sudo rados -p VNDATA-0001 setomapval rbd_header.12632c59ecee6c features
$ echo -en \\x17\\x00\\x00\\x00rbd_data.12632c59ecee6c | sudo rados -p VNDATA-0001 setomapval rbd_header.12632c59ecee6c object_prefix
$ echo -en \\x16 | sudo rados -p VNDATA-0001 setomapval rbd_header.12632c59ecee6c order
$ echo -en \\x00\\x00\\x00\\x00\\x19\\x00\\x00\\x00 | sudo rados -p VNDATA-0001 setomapval rbd_header.12632c59ecee6c size
$ echo -en \\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00 | sudo rados -p VNDATA-0001 setomapval rbd_header.12632c59ecee6c snap_seq
2.3.6. Kết quả
Kiểm tra kết quả sau khi recovery rbd_header object của image02
$ sudo rados -p VNDATA-0001 listomapvals rbd_header.12632c59ecee6c
features
value (8 bytes) :
00000000 3d 00 00 00 00 00 00 00 |=.......|
00000008
object_prefix
value (27 bytes) :
00000000 17 00 00 00 72 62 64 5f 64 61 74 61 2e 31 32 36 |....rbd_data.126|
00000010 33 32 63 35 39 65 63 65 65 36 63 |32c59ecee6c|
0000001b
order
value (1 bytes) :
00000000 16 |.|
00000001
size
value (8 bytes) :
00000000 00 00 00 00 19 00 00 00 |........|
00000008
snap_seq
value (8 bytes) :
00000000 00 00 00 00 00 00 00 00 |........|
00000008
$ sudo rbd -p VNDATA-0001 info image02
rbd image 'image02':
size 100 GiB in 25600 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: 12632c59ecee6c
block_name_prefix: rbd_data.12632c59ecee6c
format: 2
features: layering, exclusive-lock, object-map, fast-diff, deep-flatten
op_features:
flags:
Dùng mount để kiểm tra data của volume.
$ sudo rbd -p VNDATA-0001 map image02 --name client.admin
/dev/rbd0
$ sudo mount /dev/rbd0 /mnt/
$ sudo df -hT /mnt/
Filesystem Type Size Used Avail Use% Mounted on
/dev/rbd0 ext4 98G 71G 28G 72% /mnt
Kiểm tra toàn bộ rbd_header sau khi đã recover rbd_header object cho toàn bộ volumes.
sudo rbd -p VNDATA-0001 du
NAME PROVISIONED USED
image01 10 GiB 4.1 GiB
image02 100 GiB 70 GiB
image03 70 GiB 50 GiB
image04 5 GiB 60 MiB
image05 150 GiB 20 GiB
335 GiB 145 GiB