RUNBOOK — Fix Ceph Bug #70390 (BlueStore ESB) trên PUBC09
mClock client-first + Remove/Redeploy OSD giữ ID + Thay đĩa hỏng
Cụm đích: PUBC09 (Ceph Squid, cephadm-managed, pool
PUBC09-NVME-01size 2 / min_size 1).
Mục tiêu: redeploy các OSD do Squid tạo để loại bỏ metadata shared-blob hỏng (#70390), trong khi ưu tiên client tối đa (workload backup tạo/xoá snap hàng ngày rất nặng).
Tham chiếu bug: https://tracker.ceph.com/issues/70390
0. NGUYÊN TẮC AN TOÀN BAO TRÙM (đọc trước, áp suốt)
- HEALTH_OK trước khi bắt đầu. Tuyệt đối không remove/redeploy OSD khi cluster còn
HEALTH_ERR/degraded/inconsistent. Trên size 2 không có lớp đệm thứ ba. - PG
2.1f8 inconsistent(nếu còn) phải xử lý dứt điểm trước khi chạy bất kỳ bước remove nào. - Một OSD tại một thời điểm. Hết trọn vẹn một OSD (về
active+clean) mới sang con kế. Điều này vừa an toàn size 2, vừa đảm bảo khớp ID tất định (chỉ 1 slotdestroyedmỗi lúc). - Thay đĩa = luôn
--replace. Không bao giờ xoá hẳn (crush remove+osd rm+auth del) — xoá hẳn trả ID về pool trống → bị bốc số nhỏ nhất (đúng lỗi osd.4→0 đã gặp). destroyedlà entry logic trong CRUSH — tách rời khỏi khay vật lý, tên/dev/sdX, và việc node sống/chết. Nó chỉ giữ chỗ số ID.- Backfill phải BẬT trong lúc drain. Nếu
nobackfill/norecoverđang set thì drain sẽ đứng im. - Nghiệm thu fix bug = trên mỗi OSD mới:
bluestore_elastic_shared_blobs=falsevà OSD fsid đã đổi.
PHẦN A — mCLOCK: ƯU TIÊN CLIENT (làm MỘT LẦN trước cả đợt)
A0. Bối cảnh cơ chế (vì sao cấu hình như dưới)
- mClock chia 3 bucket: client / background_recovery / background_best_effort.
- Phân loại operation (quan trọng):
background_recovery= chỉ degraded object recovery (an toàn dữ liệu).background_best_effort= backfill (misplaced) + snap trim + scrub + PG deletion.- ⚠️ Khi reweight/redeploy, data chạy là misplaced → backfill → best_effort. Snaptrim của bạn cũng nằm trong best_effort → hai thứ chen chung một bucket.
res= sàn đảm bảo (không phải trần).lim= trần (0 = không giới hạn).wgt= chỉ chia phần dư trên reservation.- Squid: res/lim là TỶ LỆ 0.0–1.0 của OSD IOPS capacity. (Quincy/lab cũ dùng IOPS tuyệt đối — đừng bê số qua lại.)
- Khi mClock active (kể cả custom), các
*_sleep(osd_snap_trim_sleep, osd_recovery_sleep) bị khoá về 0 → không dùng sleep để ghìm snaptrim được; phải dùng concurrency knob.
A1. Dọn cấu hình lệch + kiểm tra capacity
# Gỡ profile lẻ của osd.31 (đang high_recovery_ops, lệch khỏi cả cluster)
ceph config rm osd.31 osd_mclock_profile
# Capacity NVMe-through-Ceph ~46k-69k IOPS là BÌNH THƯỜNG (không phải thủ phạm).
# Nhưng sequential bandwidth đang để default SATA 1200 MiB/s -> nâng cho NVMe:
ceph config set osd osd_mclock_max_sequential_bandwidth_ssd 3221225472 # ~3GB/s, đặt theo spec NVMe thật
A2. Chuyển profile custom — ĐÚNG THỨ TỰ (custom TRƯỚC, value SAU)
⚠️ Khi còn ở built-in profile (balanced…), mọi
osd_mclock_scheduler_*set vào bị revert về default của profile (báo success nhưng không lưu). Phảiprofile=customtrước thì value mới ăn.
# 1. Custom TRƯỚC
ceph config set osd osd_mclock_profile custom
ceph config get osd osd_mclock_profile # = custom
# 2. RỒI set value (giờ mới có hiệu lực)
# Client: sàn 0.5, không trần, weight cao
ceph config set osd osd_mclock_scheduler_client_res 0.5
ceph config set osd osd_mclock_scheduler_client_wgt 4
ceph config set osd osd_mclock_scheduler_client_lim 0
# Degraded recovery (an toàn dữ liệu): đừng bóp quá chặt
ceph config set osd osd_mclock_scheduler_background_recovery_res 0.1
ceph config set osd osd_mclock_scheduler_background_recovery_lim 0.4
ceph config set osd osd_mclock_scheduler_background_recovery_wgt 1
# Best-effort (backfill + snaptrim): VAN CHÍNH bảo vệ client
ceph config set osd osd_mclock_scheduler_background_best_effort_res 0.1
ceph config set osd osd_mclock_scheduler_background_best_effort_lim 0.3
ceph config set osd osd_mclock_scheduler_background_best_effort_wgt 1
Vì sao client_res = 0.5 chứ không 0.7: res là sàn, để quá cao ép best_effort luôn nhường → snaptrim không kịp drain → queue phình → lại sinh slow.
client_lim 0đã cho client dùng tới 100% khi rảnh.
A3. Ghìm song song bằng các knob ngoài mClock (vẫn hiệu lực)
# Snaptrim: hạ song song (mặc định 2x2=4 op/OSD -> 1x1=1)
ceph config set osd osd_pg_max_concurrent_snap_trims 1
ceph config set osd osd_max_trimming_pgs 1
# Backfill: trên prod đang override=true + max_backfills=12 + recovery_max_active=24 (RẤT MẠNH).
# Chọn 1 trong 2 hướng:
# Hướng khuyến nghị (client-first, ghìm cứng song song):
ceph config set osd osd_max_backfills 1
ceph config set osd osd_recovery_max_active_ssd 1
# (giữ override=true để 2 dòng trên có hiệu lực)
# Hướng "thuần mClock" (sạch hơn nhưng tin hoàn toàn vào capacity):
# ceph config set osd osd_mclock_override_recovery_settings false
A4. Verify (2 góc nhìn)
ceph config dump | grep mclock_scheduler # góc DB: đủ 9 dòng đã set
ceph tell osd.4 config show | grep mclock_scheduler # góc runtime: wgt=4, best lim=0.3, recovery res=0.1...
ceph tell osd.5 config show | grep mclock_scheduler # kiểm tra thêm vài OSD
Điều chỉnh động khi vận hành: giờ cao điểm hạ
best_effort_lim0.2–0.3; off-peak nâng 0.5 cho backfill/snap drain nhanh rồi hạ lại. Theo dõi nguồn slow:
ceph daemon osd.<id> dump_historic_slow_ops(client hay snaptrim?),ceph -s(SLOW_OPS / snaptrim backlog).
PHẦN B — REMOVE / REDEPLOY MỘT OSD (đĩa còn tốt — ca fix bug)
Dùng cho việc redeploy OSD do Squid tạo để xoá metadata ESB hỏng. Đĩa còn sống → drain an toàn, không mất data.
<id>= OSD đang xử lý;<host>= node chứa nó;<dev>= đĩa của nó.
Cách 1 (KHUYẾN NGHỊ) — orchestrator một lệnh
| Bước | Lệnh | Gate PASS (mới đi tiếp) |
|---|---|---|
| Tiền kiểm | ceph -s ; ceph health detail |
HEALTH_OK, all active+clean, không inconsistent/degraded |
| Ghi nhận | ./map-osd-disk.sh \| grep "osd.<id> " ; ceph osd tree \| grep "osd.<id> " |
Ghi lại đĩa + weight gốc (~13.97260) |
| ok-to-stop | ceph osd ok-to-stop osd.<id> |
Trả lời OK |
| Replace | ceph orch osd rm <id> --replace --zap |
"Scheduled OSD(s) for removal" |
| Theo dõi | ceph orch osd rm status |
STATE=done, PGS=0 |
| Verify destroyed | ceph osd tree \| grep -E 'osd.<id>\|destroyed' |
thấy <id> ... destroyed (ID không biến mất) |
| Redeploy | managed → tự tạo lại; unmanaged → ceph orch daemon add osd <host>:/dev/<dev> |
— |
| Verify ID | ceph osd tree \| grep "osd.<id> " ; ceph orch ps <host> --daemon-type osd |
up, đúng ID cũ, container ID mới + AGE nhỏ |
| Restore weight | ceph osd crush reweight osd.<id> <weight_gốc> |
weight đúng trị gốc |
| Chờ clean | ceph -s |
lại active+clean toàn bộ |
Cách 2 — manual từng bước (nếu cần kiểm soát từng nhịp)
ceph osd set noout
ceph osd crush reweight osd.<id> 0 # drain
# CHỜ: ceph -s hết misplaced/backfilling + PG trên osd.<id> = 0 (ceph osd df)
ceph osd safe-to-destroy osd.<id> # phải "safe to destroy"
ceph orch daemon stop osd.<id> # CHỜ STATUS=down (osd tree)
ceph osd destroy <id> --yes-i-really-mean-it # -> destroyed, GIỮ ID
ceph orch daemon rm osd.<id> --force
ceph orch device zap <host> /dev/<dev> --force # đối chiếu ĐÚNG đĩa trước khi zap!
ceph orch daemon add osd <host>:/dev/<dev> # nuốt ID destroyed
ceph osd crush reweight osd.<id> <weight_gốc> # nếu vào weight 0
# CHỜ active+clean trước khi sang OSD kế
❌ KHÔNG dùng chuỗi cũ
out → crush remove → osd rm → auth del → daemon rm: nó xoá hẳn ID → add lại nhảy số.
ceph osd destroythay cho cảcrush remove+osd rm+auth del, giữ ID ởdestroyed.
Nghiệm thu fix bug (BẮT BUỘC cho mỗi OSD mới)
ceph config get osd bluestore_elastic_shared_blobs # = false
ceph tell osd.<id> config show | grep elastic_shared_blobs # OSD mới = false
ceph-volume lvm list <id> # fsid PHẢI khác fsid cũ (chứng minh mkfs mới)
Vì sao redeploy là bắt buộc: metadata ESB hỏng nằm trong RocksDB/BlueStore on-disk. Tắt flag chỉ bảo vệ OSD mới tạo.
--zapxoá sạch BlueStore +mkfslại với flag=false = vứt bỏ tận gốc metadata hỏng; data lành backfill từ replica về.
PHẦN C — THAY ĐĨA HỎNG (giữ ID) — cho vận hành sau này
Cùng cơ chế destroyed, khác ở chỗ đĩa đã chết → không drain/zap được.
# 1. Đĩa hỏng -> replace, GIỮ ID. Bỏ --zap (đĩa chết không zap nổi), thêm --force nếu OSD down không drain
ceph orch osd rm <id> --replace --force
ceph osd tree | grep -E 'osd.<id>|destroyed' # "<id> ... destroyed"
# 2. (size 2) Ceph tự re-replicate từ bản sao NGAY khi OSD bị out.
# CHỜ ceph -s về active+clean (khôi phục redundancy) rồi mới thao tác vật lý.
# 3. DC rút đĩa hỏng, cắm đĩa MỚI (khay nào cũng được, miễn ĐÚNG HOST)
# 4. Xác định đĩa mới (đừng đoán theo /dev/sdX hay khay):
ceph orch device ls <host> --refresh # đĩa mới = Available=Yes
lsblk -o NAME,SERIAL,SIZE # khớp serial đĩa DC vừa lắp
# 5. Tạo lại OSD -> nuốt ID destroyed
# - Cluster 1 OSD/đĩa: managed tự tạo, HOẶC add tay:
ceph orch daemon add osd <host>:/dev/disk/by-id/<serial>
# - Cluster NHIỀU OSD/đĩa hoặc DB/WAL tách riêng: PHẢI để spec managed dựng (xem D3), KHÔNG add tay
# 6. Verify
ceph osd tree | grep osd.<id> # up, đúng ID, trên đĩa mới
ceph osd crush reweight osd.<id> <weight_gốc> # nếu cần
PHẦN D — THAM CHIẾU NHANH
D1. Khác biệt theo VERSION (đừng nhầm lab Quincy vs prod Squid)
| Việc | Squid (prod PUBC09) | Quincy (lab) |
|---|---|---|
| mClock res/lim | Tỷ lệ 0.0–1.0 | IOPS tuyệt đối (số nguyên; 0.5 báo strict_si_cast error) |
| Khoá auto-deploy | ceph orch set-unmanaged osd.<name> / set-managed |
Sửa YAML unmanaged: true/false rồi ceph orch apply -i |
Tên service ở orch ls |
ceph orch ls osd osd.<name> (có tiền tố osd.) |
giống |
Phần remove/destroy/zap/add giống nhau giữa hai version.
D2. Ba cách gắn OSD & khả năng kiểm soát ID
| Cách | Ép ID tùy ý? | Giữ ID cũ? | Stray? |
|---|---|---|---|
orch osd rm --replace → redeploy |
— | Có (qua destroyed) |
Không |
orch daemon add osd |
Không (bốc số trống nhỏ nhất) | Chỉ nếu ID đang destroyed |
Không |
ceph-volume lvm create --osd-id |
Có | — | Thường có; trên cephadm hay fail (Failed to connect to bus) |
Kết luận: trên cephadm, không có đường thủ công sạch để ép ID tùy ý. Muốn kiểm soát ID → dùng trạng thái
destroyed. Cần ép ID đặc biệt (nắn ID lệch) → dùng specosd_id_claims, không phải ceph-volume tay.
D3. unmanaged + spec nhiều OSD/đĩa
ceph orch daemon add osd host:/dev/X= 1 đĩa → 1 OSD, bỏ qua spec (không biếtosds_per_device: 2).- Cluster có 2 OSD/đĩa hoặc DB/WAL riêng → phải bật lại managed để cephadm dựng đúng spec, không add tay.
- Bật lại managed sẽ tóm mọi đĩa trống khớp spec → chỉ bật khi chắc không có đĩa trống ngoài ý muốn.
D4. Bảy điều đã chốt về destroyed / thay đĩa
- Đĩa mới nuốt đúng ID destroyed nếu chỉ 1 slot destroyed/host tại thời điểm đó; nhiều slot → làm tuần tự hoặc
osd_id_claims. - Node đầy khay vẫn thay được:
destroyedlà logic trong CRUSH, không chiếm khay; rút đĩa hỏng giải phóng khay. - Node down khi có slot destroyed → không sao; trạng thái lưu ở mon, bền qua down/up.
- DC cắm đĩa vào khay khác → vẫn được; Ceph chỉ cần đúng device, đúng host.
/dev/sdXđổi sau reboot → không hỏng OSD đã tạo (định danh qua LVM UUID); tên kernel chỉ quan trọng lúc add → luôndevice ls --refreshhoặc dùng/dev/disk/by-id/.- Spec 2 OSD/đĩa + add tay → không tạo đủ 2; phải để spec managed dựng.
--replacedùng cho cả redeploy (đĩa tốt) lẫn thay đĩa hỏng; cái giữ ID làdestroyed, không phải "cùng đĩa".
D5. Dọn dẹp & bảo mật
ceph osd unset noout # gỡ SAU KHI xong cả đợt
# Nếu từng scp admin keyring xuống node OSD để test -> XOÁ đi (bảo mật):
# rm -f /etc/ceph/ceph.client.admin.keyring /etc/ceph/*.keyring (trên node OSD)
CHECKLIST TỔNG (mỗi OSD)
[ ] cluster HEALTH_OK, không inconsistent (PG 2.1f8 đã sạch)
[ ] mClock custom đã verify (Phần A) — chỉ làm 1 lần đầu đợt
[ ] ghi đĩa + weight gốc của OSD
[ ] ok-to-stop OK
[ ] ceph orch osd rm <id> --replace --zap
[ ] osd rm status = done, PGS = 0
[ ] osd tree = destroyed (ID còn)
[ ] redeploy -> up, ĐÚNG ID, container mới
[ ] NGHIỆM THU: elastic_shared_blobs=false + fsid mới
[ ] restore weight
[ ] CHỜ active+clean -> mới sang OSD kế
[ ] (cuối đợt) unset noout