精品一区二区三区在线成人,欧美精产国品一二三区,Ji大巴进入女人66h,亚洲春色在线视频

山洪災害后的 Ceph 慘案:PG incomplete 到 RBD 鏡像消失

存儲 數據管理
在一次山洪災害后,機房的服務器全部斷電,等供電恢復后進入系統發現所有的虛擬機文件系統損壞了,并且查看ceph集群有個pg出現inactive和incomplete狀態,上傳新的鏡像io也會卡住,以下是恢復過程。

背景

在一次山洪災害后,機房的服務器全部斷電,等供電恢復后進入系統發現所有的虛擬機文件系統損壞了,并且查看ceph集群有個pg出現inactive和incomplete狀態,上傳新的鏡像io也會卡住,以下是恢復過程。

圖片圖片

圖片

排查過程

incomplete和inactive狀態含義解釋

inactive
  • 含義:PG 處于不可用狀態。
  • 表現:客戶端對這個 PG 的讀寫請求都會被阻塞。
  • 原因可能包括:

這個 PG 沒有足夠的 OSD 存活來提供服務。

PG 沒有被分配到合適的 OSD 上。

OSD 沒有完成 peering(對等協商)過程。

換句話說,inactive 就是 PG 不能對外提供正常的 IO 服務。

incomplete
  • 含義:PG 在 peering 時發現缺少必需的數據副本,導致無法達到一致性。
  • 表現:PG 中的數據不完整,無法對外提供讀寫。
  • 常見原因:

某些 OSD 宕機或丟失數據,導致 PG 的對象副本無法湊齊。

新 OSD 加入或者數據遷移時丟失了必要的副本。

硬盤故障或誤刪導致數據確實丟失。

通常 incomplete 比 inactive 更嚴重, inactive只是PG 暫時不可用,但數據可能還在,只是沒有滿足對外服務條件。  incomplete出現時說明peering 過程中無法收集到足夠的、權威的一致數據副本,意味著有的數據副本確實不存在了,需要人工干預才能恢復。往往出現在peering的過程中服務器異常斷電, 在斷電前 PG 的日志還沒來得及落盤, 所有副本上的 PG log 都不完整,導致無法確定哪些對象是最新的 。

嘗試對pg進行修復

查看集群所有的osd,發現都是up的

圖片圖片

嘗試常規修復發現沒什么用

ceph pg repair 2.1c

后查看pg上的對象數和丟失的對象數,發現pg上的對象數為0

ceph pg ls | grep 2.1c
ceph pg 2.1c list_unfound

圖片圖片

嘗試回滾pg舊版本和重啟pg副本所在的osd服務后重新修復均無效

ceph pg 2.1c mark_unfound_lost revert
ceph pg repair 2.1c

將pg副本的osd out再in后狀態仍沒有變化

ceph osd out <id>
ceph osd in <id>

使用ceph-objectstore-tool操作pg副本

集群狀態一直無法恢復,準備使用ceph-objectstore-tool工具操作pg副本,只保留一份pg的副本,將其他兩份的副本刪除,并基于剩余的pg副本做回填,最后將剩下的pg副本標記為complete狀態。

準備操作
#查看pg副本所在的osd
ceph pg map 2.1c
#防止副本操作期間觸發數據重新均衡
ceph osd set noout
# 臨時降低 min_size
ceph osd pool set libvirt-pool min_size 1
備份導出pg副本

可以看到導出的副本大小都是十幾K,數據基本查看其他正常的pg,對象數量平均是在6000多個

systemctl stop ceph-osd@8
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-8  --type bluestore --pgid 2.1c --op export --file /opt/2.1c.obj_osd_8
systemctl stop ceph-osd@14
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-14  --type bluestore --pgid 2.1c --op export --file /opt/2.1c.obj_osd_14
systemctl stop ceph-osd@11
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-11  --type bluestore --pgid 2.1c --op export --file /opt/2.1c.obj_osd_11

圖片圖片

圖片圖片

圖片

刪除兩個osd節點上的故障pg副本
systemctl stop ceph-osd@8
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-8/ --type bluestore --pgid 2.1c --op remove --force
systemctl stop ceph-osd@11
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-11/ --type bluestore --pgid 2.1c --op remove --force

圖片圖片

從剩余節點導入pg副本到其他兩個osd節點
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-11/ --type bluestore --pgid 2.1c --op import --file /opt/2.1c.obj_osd.14
ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-8/ --type bluestore --pgid 2.1c --op import --file /opt/2.1c.obj_osd.14
systemctl start ceph-osd@11
systemctl start ceph-osd@8

圖片圖片

將剩余節點的pg副本標記為complete

執行常規恢復操作發現集群還是處于incomplete狀態

ceph pg repair 2.1c

將剩余節點的pg副本標記為complete

systemctl stop ceph-osd@14
# 標記 complete
ceph-objectstore-tool --type bluestore --data-path /var/lib/ceph/osd/ceph-14 --pgid 2.1c --op mark-complete
ceph osd pool set libvirt-pool min_size 2
ceph osd unset noout
systemctl start ceph-osd@14

之后集群顯示健康狀態正常了

圖片圖片

但是發現rbd查看鏡像發現全沒了,存儲大小沒有變化

圖片圖片

對rbd鏡像列表數據進行恢復

查看鏡像頭對象,發現還在,但是根據ID查詢存儲池中的鏡像已經查不到了

rados -p libvirt-pool ls | grep '^rbd_header\.' | head
rbd -p libvirt-pool --image-id <id> info

圖片圖片

檢查header對象的元數據,發現還在,說明只是目錄對象丟失了

rados -p libvirt-pool listomapkeys rbd_header.d8b1996ee6b524 | head

圖片圖片

使用rados查看鏡像發現能查詢到

rados -p libvirt-pool stat rbd_header.d8b1996ee6b524

圖片圖片

搭建測試環境復現

搭建好測試環境后修復好后再在生產環境修復,先設置osd暫停恢復/回填,且把存儲池 min_size 暫時降到 1

ceph osd set noout
ceph osd set norecover
ceph osd set nobackfill
ceph osd pool set libvirt-pool min_size 1

只保留 主副本 的osd在線,停掉另外兩個副本

systemctl stop ceph-osd@4
systemctl stop ceph-osd@5

刪除總目錄對象,再刪每個鏡像的 id 映射條目

rados -p libvirt-pool rm rbd_directory
for img in $(rbd ls -p libvirt-pool 2>/dev/null); do
  rados -p libvirt-pool rm rbd_id.$img || true
done

讓另外兩個副本上線并恢復回填

systemctl start ceph-osd@4
systemctl start ceph-osd@5

ceph osd unset noout
ceph osd unset norecover
ceph osd unset nobackfill

驗證復現結果,目錄對象確實丟了,但是數據還在

rados -p libvirt-pool stat rbd_directory
rbd ls -p libvirt-pool
rados -p libvirt-pool ls | grep '^rbd_header\.' | head

圖片圖片

圖片圖片

恢復rbd的目錄對象

從網上找了兩個腳本,一個腳本可以根據header的ID反查鏡像名,另一個是根據鏡像名和header的ID來恢復rbd鏡像目錄

#!/bin/bash
# 用法: ./find_rbd_name.sh <IMAGE_ID>
# 例子: ./find_rbd_name.sh 3c456b8b4567

set -euo pipefail

POOL="libvirt-pool"

if [ $# -ne 1 ]; then
  echo "用法: $0 <IMAGE_ID>"
  exit 1
fi

ID="$1"

found=0
for obj in $(rados -p "$POOL" ls | grep '^rbd_id\.'); do
  got=$(rados -p "$POOL" get "$obj" - 2>/dev/null | tr -d '\n\r')
  if [ "$got" = "$ID" ]; then
    echo "發現: $obj  -> name = ${obj#rbd_id.}"
    found=1
  fi
done

if [ $found -eq 0 ]; then
  echo "未找到 ID=$ID 對應的鏡像"
  exit 2
fi

通過直接改寫 pool 里的 rbd_directory 對象的 OMAP 鍵值 來恢復

  • 每個 RBD 鏡像都有一個頭對象:rbd_header.<ID>,鏡像的各種元數據都掛在它的 omap 上。
  • rbd ls 并不是去遍歷所有 rbd_header.*,而是讀 **rbd_directory** 這個對象的 omap

name_<NAME> → 值為 <ID>

id_<ID> → 值為 <NAME>

  • 值的編碼不是裸字符串,而是:小端 4 字節長度(LE uint32) + 字符串本體。
    例如 name_foo 的值若為 "abc123",實際二進制是:06 00 00 00 61 62 63 31 32 33
  • 只要把這兩條映射補上,rbd ls 就能重新列出 <NAME>rbd info <NAME> 也能通過目錄映射定位到頭對象 <ID>
#!/usr/bin/env bash
# 用法: ./fix_rbd_mapping.sh <NAME> <ID>
# 例子: ./fix_rbd_mapping.sh windows_7sp1_x86_dvd677486.img 2557396b8b4567

set -euo pipefail

POOL="libvirt-pool"

if [ $# -ne 2 ]; then
  echo "用法: $0 <NAME> <ID>"
  exit 1
fi

NAME="$1"
ID="$2"

# 0)(可選)先確保池已初始化過 RBD 目錄對象;冪等,安全
rbd pool init "$POOL"

# 1) 備份一下目前這兩條(如果不存在會報錯但不影響繼續)
rados -p "$POOL" getomapval rbd_directory "name_$NAME" /tmp/old_name_val.bin 2>/dev/null || true
rados -p "$POOL" getomapval rbd_directory "id_$ID"   /tmp/old_id_val.bin   2>/dev/null || true

# 2) name_<name> -> <id> (值為:LE4長度 + 字符串ID)
python3 - <<'PY' | rados -p "$POOL" setomapval rbd_directory "name_$NAME"
import sys,struct
img_id="$ID"
sys.stdout.buffer.write(struct.pack("<I", len(img_id)))
sys.stdout.buffer.write(img_id.encode())
PY

# 3) id_<id> -> <name> (值為:LE4長度 + 字符串NAME)
python3 - <<'PY' | rados -p "$POOL" setomapval rbd_directory "id_$ID"
import sys,struct
name="$NAME"
sys.stdout.buffer.write(struct.pack("<I", len(name)))
sys.stdout.buffer.write(name.encode())
PY

# 4) 校驗兩條鍵寫好了
rados -p "$POOL" listomapvals rbd_directory | egrep 'name_$NAME|id_$ID' -n

# 5) 看列表與信息
rbd -p "$POOL" ls | grep -F -- "$NAME" || true
rbd -p "$POOL" info "$NAME"

圖片圖片

查看恢復后的鏡像列表發現已經恢復

圖片圖片


責任編輯:武曉燕 來源: 運維開發故事
相關推薦

2017-04-19 15:57:21

Ceph RBD mi原理分析

2023-05-16 08:30:53

QuincyReef

2018-07-19 15:00:41

衛星圖像

2021-01-12 05:06:35

存儲Kubernetes鏡像

2022-06-06 07:56:12

LUKSLUKS2PBKDF2

2023-12-01 08:01:59

鏡像Ceph

2015-10-23 10:47:35

喬布斯蘋果

2022-05-27 14:06:43

kvm虛擬機磁盤LUKS

2018-08-02 08:42:57

分布式存儲Ceph

2021-02-01 09:00:34

Ceph octopu集群運維

2021-11-01 17:29:02

Windows系統Fork

2017-08-22 15:58:56

2022-10-19 08:01:17

QuincyCephPG

2021-04-30 17:24:35

人工智能AI深度學習

2018-10-08 15:08:42

物聯網水災害IOT

2017-08-24 17:37:18

DNS緩存分析

2018-05-03 07:44:33

物聯網災害預防傳感器

2021-08-06 22:43:54

中斷架構傳遞

2013-07-29 15:52:14

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 绵阳市| 苍梧县| 清徐县| 永顺县| 阜新| 兖州市| 若羌县| 青海省| 桑日县| 新密市| 灵台县| 永平县| 民县| 济阳县| 罗甸县| 合作市| 长阳| 玉门市| 犍为县| 工布江达县| 汉阴县| 北票市| 奉化市| 天柱县| 镇远县| 双峰县| 高州市| 龙井市| 保亭| 巴东县| 浙江省| 深泽县| 荃湾区| 德兴市| 葵青区| 武汉市| 泾阳县| 贞丰县| 德庆县| 保康县| 雷州市|