제 홈랩 Proxmox 노드 5대는 한 달에 두 번씩 정해진 날짜에 하나씩 돌아가며 재부팅됩니다. 그 위에서 CephFS 3개가 Kubernetes 파드들에게 파일을 내주고 있고요. 노드가 하나 내려갈 때마다 그 노드의 MDS(메타데이터 서버)도 같이 내려가니, 파일시스템 입장에서는 2~4일마다 한 번씩 MDS 장애가 나는 셈입니다.
이번 글은 그 MDS들을 어디에 둘지 정한 기록입니다. 목표는 두 가지였습니다.
- failover 때 파드들이 겪는 메타데이터 멈춤을 최소로
- 어떤 노드가 내려가도 무거운 active MDS 두 개가 한 노드에 몰리지 않게
🧭 환경
- Proxmox 노드 5대(pve1~5), Ceph Squid 19.2.5
- CephFS 3개, 각각
max_mds 1(active 1개) - 노드별 고정 날짜로 순환 재부팅: pve5 → pve1 → pve2 → pve3 → pve4 → pve5 …
| 파일시스템 | 용도 | 규모 | active MDS 메모리 |
|---|---|---|---|
cephfs-user-tier | 큰 사용자 데이터 (EC 풀) | inode 약 123만 | 약 4.3 GiB |
cephfs-userdata-nvme | Nextcloud 사용자 데이터, 매시 스냅샷 | inode 약 97만, 클라이언트 26 | 약 1.5 GiB |
cephfs-userdata-snapshotless | 스냅샷 없는 작은 데이터 | 거의 비어 있음 | 수십 MiB |
앞의 둘이 “무거운” 파일시스템이고, 마지막 하나는 “가벼운” 파일시스템입니다. (배치와 메모리 수치는 2026-10-14에 다시 확인한 값으로 갱신했습니다.)
🔍 먼저 알아둘 것: standby-replay는 작고, 넘겨받으면 커진다
MDS에는 standby가 두 종류 있습니다.
- standby: 그냥 대기합니다. 넘겨받을 때 저널을 처음부터 읽고 캐시를 다시 채워야 해서 느립니다.
- standby-replay: 특정 파일시스템의 active를 따라가며 저널 끝부분을 계속 재생합니다. 넘겨받을 때 거의 바로 이어받습니다.
재미있는 건 메모리입니다. 지금 standby-replay들은 210~335 MiB밖에 안 씁니다. active가 4.3 GiB인데 말이죠. 처음 봤을 땐 설정이 잘못된 줄 알았는데, 정상입니다. standby-replay는 클라이언트 capability를 하나도 들고 있지 않고 저널 끝부분만 재생하니까요. ceph fs status에서 상태가 standby-replay로 나오면 맞게 도는 겁니다.
대신 넘겨받는 순간 active 크기로 부풀어 오릅니다. 메모리 계획은 평소 숫자가 아니라 failover 후 숫자로 해야 합니다. 실제로 이 클러스터에서 MDS 캐시가 불어나 19 GB에서 OOM kill된 적이 있습니다. 지금은 mds_cache_memory_limit을 4 GiB로 잡아두었습니다.
🗺️ 배치
| 노드 | MDS | 역할 |
|---|---|---|
| pve1 | pve1-1 / pve1-2 | user-tier active / snapshotless active |
| pve2 | pve2-1 / pve2-2 | userdata-nvme active / snapshotless replay |
| pve3 | pve3-1 / pve3-2 | 일반 standby / 일반 standby |
| pve4 | pve4-1 | userdata-nvme replay |
| pve5 | pve5-1 | user-tier replay |
규칙은 세 가지입니다.
- 무거운 active 두 개(user-tier, userdata-nvme)는 서로 다른 노드(pve1, pve2)에 둡니다.
- 그 둘의 standby-replay도 또 다른 두 노드(pve5, pve4)에 따로 둡니다. 무거운 FS 하나에 노드 2개씩, 네 노드가 전부 다릅니다.
- 한 노드에 MDS가 둘이면 반드시 무거운 것 + 가벼운 것 조합입니다.
그리고 pve3에는 active도 replay도 두지 않았습니다. 이 노드는 한동안 팬 고장, 메모리 부족, 불안정한 SSD로 자주 멈췄는데, 덕분에 pve3가 멈춰도 어떤 파일시스템도 failover하지 않습니다.
🔄 재부팅마다 무슨 일이 일어나나
| 내려가는 노드 | 일어나는 일 | 결과 |
|---|---|---|
| pve1 | user-tier → pve5-1, snapshotless → pve2-2 | pve2 = nvme active + snapshotless active (무거움 + 가벼움) |
| pve2 | userdata-nvme → pve4-1 | pve4 = nvme active 하나 |
| pve3 | 없음 | standby만 잠시 줄어듦 |
| pve4 | 없음 | nvme가 잠시 replay를 잃음 → standby가 대신 |
| pve5 | 없음 | user-tier가 잠시 replay를 잃음 → pve3-1이 대신 |
어느 경우에도 무거운 active 두 개가 한 노드에 겹치지 않습니다. 겹치려면 두 무거운 FS가 같은 노드로 failover해야 하는데, 각자의 standby-replay가 서로 다른 노드에 있으니 불가능합니다.
🎯 이게 확실하게 동작하는 이유: failover는 결정적이다
이 배치는 “이 FS가 죽으면 저 노드로 간다”는 게 매번 같아야 의미가 있습니다. 다행히 Ceph는 그렇게 동작합니다. active가 죽으면 모니터는 그 랭크를 따라가던 standby-replay를 가장 먼저 승격시킵니다. 아무 standby나 고르지 않습니다.
어느 MDS가 어느 FS를 따라갈지는 데몬마다 mds_join_fs로 고정합니다.
ceph config set mds.pve1-1 mds_join_fs cephfs-user-tier
ceph config set mds.pve5-1 mds_join_fs cephfs-user-tier
ceph config set mds.pve2-1 mds_join_fs cephfs-userdata-nvme
ceph config set mds.pve4-1 mds_join_fs cephfs-userdata-nvme
ceph config set mds.pve1-2 mds_join_fs cephfs-userdata-snapshotless
ceph config set mds.pve2-2 mds_join_fs cephfs-userdata-snapshotless
...헷갈렸던 부분 몇 가지입니다.
mds_join_fs는 데몬별 설정입니다. 같은 FS를 맡은 active와 replay 양쪽에 같은 값을 넣습니다. 순서나 우선순위 개념이 아닙니다.- 데몬 이름 뒤의
-1,-2는 Ceph에게 아무 의미가 없습니다. 제가 붙인 이름일 뿐입니다. standby_count_wanted는 health 경고만 띄웁니다. 이걸 올린다고 standby를 다시 배치해주지 않습니다.- standby-replay를 쓰려면 파일시스템마다
allow_standby_replay를 켜야 합니다.
ceph fs set cephfs-userdata-nvme allow_standby_replay true🧹 재부팅할 때의 작은 요령
MDS가 갑자기 죽으면 모니터는 비컨이 끊긴 뒤 mds_beacon_grace(기본 15초)를 기다리고 나서야 failover를 시작합니다. 그동안 그 FS의 메타데이터 요청이 멈춥니다. 재부팅을 미리 알고 있다면 먼저 깨끗하게 내리는 게 낫습니다.
systemctl stop ceph-mds@pve2-1 # 깨끗하게 내리면 15초 대기 없이 바로 넘어감
ceph fs status # pve4-1 이 active 가 됐는지 확인
reboot노드가 돌아오면 그 MDS는 standby로 들어옵니다. 원래 자리(홈)로 active를 되돌리고 싶으면 지금 active를 한 번 fail 시킵니다.
ceph mds fail cephfs-userdata-nvme:0그러면 그 FS의 standby-replay인 돌아온 데몬이 다시 active가 됩니다. 안 되돌려도 규칙이 깨지지는 않습니다. 이 배치는 대칭이라 replay 자리에 있던 데몬이 active가 돼도 같은 성질이 유지됩니다.
📝 정리
- standby-replay는 평소 수백 MiB지만 넘겨받으면 active 크기로 커집니다. 메모리는 failover 후 기준으로 계획합니다.
- 무거운 FS마다 노드 두 개(active, replay)를 주고, 그 노드들이 서로 겹치지 않게 하면 어떤 재부팅에서도 무거운 active 두 개가 만나지 않습니다.
- standby-replay가 있으면 failover 대상이 결정적입니다.
mds_join_fs를 양쪽 데몬에 같이 넣습니다. - 한 노드에 둘을 둬야 하면 무거운 것 + 가벼운 것으로 짝짓습니다.
- 계획된 재부팅이면 MDS를 먼저
systemctl stop해서 15초 비컨 대기를 건너뜁니다.
노드 drain 글도 같은 원리인데, 재부팅 순서가 고정이면 장애를 “예측 가능한 이벤트”로 바꿀 수 있습니다. MDS도 마찬가지였습니다. ㅎㅎ

답글 남기기