Ceph MDS 状态机与 Monitor 中的状态流转分析

基于 Ceph 14.2.18源码(mds/MDSMap.h, mds/MDSMap.cc, mds/FSMap.h, mds/FSMap.cc, mon/MDSMonitor.cc)分析


一、MDS 状态定义

所有 MDS 状态定义在 mds/MDSMap.h 的枚举 DaemonState 中(L62-L100):

cpp 复制代码
// mds/MDSMap.h: L62-L100
typedef enum {
    // ---- 不持有 rank 的 daemon 状态 ----
    STATE_NULL             // 空值
    STATE_BOOT             // 进程已启动,向 Mon 宣告自己存在
    STATE_STANDBY          // 空闲,等待 Monitor 分配
    STATE_STANDBY_REPLAY   // 正在 replay 某个 active rank,随时可接管

    // ---- MDS rank 自身的状态(可能没有 daemon 持有)----
    STATE_STOPPED          // rank 曾存在,已正常停止,日志为空
    STATE_CREATING         // daemon 正在为新 rank 创建日志/元数据
    STATE_STARTING         // daemon 正在启动一个 stopped rank
    STATE_REPLAY           // 恢复场景:daemon 正在扫描之前失败实例的日志
    STATE_RESOLVE          // 恢复场景:消歧义分布式操作(import/rename等)
    STATE_RECONNECT        // 恢复场景:重新连接客户端
    STATE_REJOIN           // 恢复场景:重新 join 分布式缓存
    STATE_CLIENTREPLAY     // 重放客户端请求
    STATE_ACTIVE           // 正常工作状态
    STATE_STOPPING         // 正在导出元数据,准备退出
    STATE_DNE              // rank 不存在

    // ---- daemon 向 Mon 上报的特殊状态 ----
    STATE_DAMAGED          // 磁盘/日志损坏,需要离线修复
} DaemonState;

重要区分:rank 的隐式状态

MDSMap.h 注释(L91-L99)明确说明:rank 还有三个隐式状态 ,不通过 DaemonState 枚举表示,而是通过 MDSMap 中的集合来判断:

隐式状态 判断方法
FAILED rank ∈ mds_map.failed 且没有 daemon 持有该 rank
STOPPED rank ∈ mds_map.stopped 且没有 daemon 持有该 rank
DNE rank 既不在 failed 也不在 stopped

MDSMap 的核心数据结构(MDSMap.h L196-L201):

cpp 复制代码
std::set<mds_rank_t> in;              // 集群中已定义的 rank 集合
std::set<mds_rank_t> failed;          // 失败的 rank(等待新 standby 接管)
std::set<mds_rank_t> stopped, damaged;
std::map<mds_rank_t, mds_gid_t> up;   // rank → 持有该 rank 的 daemon gid
std::map<mds_gid_t, mds_info_t> mds_info; // gid → daemon 详细信息

ceph fs status 显示 failed,本质上是显示 mds_map.failed 集合中的 rank,而非某个 daemon 的 DaemonState


二、Monitor 中状态流转的完整路径

Monitor 通过两种途径修改 MDS 状态:

  1. 被动响应 :处理 MDS daemon 主动上报的 beacon 消息(prepare_beacon()
  2. 主动检测 :定时 tick 检测 beacon 超时(tick()maybe_replace_gid()

2.1 MDS 主动驱动的状态变更:prepare_beacon()

mon/MDSMonitor.cc L536-L796,prepare_beacon() 是 Monitor 接收 MDS 心跳并处理状态变更请求的入口。

2.1.1 BOOT 流程(进程启动 → STANDBY)
cpp 复制代码
// MDSMonitor.cc L587-L634
if (state == MDSMap::STATE_BOOT) {
    // 1. 如果同名 MDS 已存在,先 fail 掉旧实例
    if (g_conf()->mds_enforce_unique_name) {
        while (mds_gid_t existing = pending.find_mds_gid_by_name(m->get_name())) {
            fail_mds_gid(pending, existing);  // 清除旧 gid
        }
    }
    // 2. 创建新的 mds_info,初始状态为 STATE_STANDBY
    MDSMap::mds_info_t new_info;
    new_info.state = MDSMap::STATE_STANDBY;
    pending.insert(new_info);
    // 3. 初始化该 gid 的 beacon 时间戳
    last_beacon[gid].stamp = mono_clock::now();
}

STATE_BOOT 是一个临时过渡状态,只出现在 MDS 向 Mon 发送的消息中,Monitor 处理后立即将其注册为 STATE_STANDBY,不会持久化 BOOT 状态。

2.1.2 MDS 上报状态变更(STANDBY → REPLAY → ... → ACTIVE)
cpp 复制代码
// MDSMonitor.cc L756-L778
} else if (info.state != MDSMap::STATE_STANDBY && state != info.state &&
           !MDSMap::state_transition_valid(info.state, state)) {
    // 非法状态转换,拒绝
    derr << "daemon reported invalid state transition" << dendl;
    return true;
} else {
    // 合法转换,直接记录 daemon 上报的新状态
    pending.modify_daemon(gid, [state, seq](auto& info) {
        info.state = state;
        info.state_seq = seq;
    });
}

关键约束 :状态转换合法性由 MDSMap::state_transition_valid() 验证(mds/MDSMap.cc L885-L909):

cpp 复制代码
bool MDSMap::state_transition_valid(DaemonState prev, DaemonState next)
{
    if (prev == MDSMap::STATE_REPLAY) {
        // REPLAY 只能转到 RESOLVE 或 RECONNECT
        if (next != MDSMap::STATE_RESOLVE && next != MDSMap::STATE_RECONNECT)
            state_valid = false;
    } else if (prev == MDSMap::STATE_REJOIN) {
        // REJOIN 只能转到 ACTIVE/CLIENTREPLAY/STOPPED
        if (next != STATE_ACTIVE && next != STATE_CLIENTREPLAY && next != STATE_STOPPED)
            state_valid = false;
    } else if (prev >= MDSMap::STATE_RESOLVE && prev < MDSMap::STATE_ACTIVE) {
        // RESOLVE/RECONNECT/REJOIN/CLIENTREPLAY:只能按序前进一步
        if (next != prev + 1)
            state_valid = false;
    }
    return state_valid;
}

这意味着:RESOLVE → RECONNECT → REJOIN → CLIENTREPLAY → ACTIVE 必须严格按顺序,每步只能前进一个状态。Monitor 不会主动驱动 MDS 从 REPLAY 走到 RESOLVE 等后续状态,这些状态变更完全由 MDS daemon 自己通过发送 beacon 上报触发

2.1.3 特殊状态处理
上报状态 Monitor 处理逻辑 来源
STATE_STOPPED 调用 fsmap.stop(gid):从 up 移除,加入 stopped,清理 standby-replay L686-L704
STATE_DAMAGED 调用 fsmap.damaged(gid, epoch):加入 damaged,blacklist IP L707-L732
STATE_DNE 调用 fail_mds_gid():走 erase() 逻辑,加入 failed L733-L749
2.1.4 laggy 标记清除
cpp 复制代码
// MDSMonitor.cc L673-L680
if (info.laggy()) {
    dout(1) << "prepare_beacon clearing laggy flag on " << addrs << dendl;
    pending.modify_daemon(info.global_id, [](auto& info) {
        info.clear_laggy();
    });
}

只要 MDS daemon 还能发来 beacon,无论状态如何,Monitor 都会清除 laggy 标记。


2.2 Monitor 主动检测:tick()maybe_replace_gid()

tick() 是 Monitor 的定时任务(MDSMonitor.cc L2001-L2089),每个 tick_interval 调用一次。

2.2.1 tick() 的执行流程
cpp 复制代码
void MDSMonitor::tick()
{
    // 1. 仅 active leader 执行
    if (!is_active() || !is_leader()) return;

    // 2. 检测 Mon 自身的延迟(选举等),重置 beacon 时间戳
    if (since_last > (mds_beacon_grace - mds_beacon_interval)) {
        for (auto &p : last_beacon) {
            p.second.stamp = now;   // 防止 Mon 自身慢导致误判
        }
    }
    last_tick = now;

    // 3. 确保 last_beacon 对所有已知 gid 都有初始值(首次 tick 时用当前时间初始化)
    for (auto &p : pending.mds_roles) {
        last_beacon.emplace(gid, {mono_clock::now(), 0});
    }

    // 4. 遍历所有 gid,检测 beacon 超时
    for (auto it = last_beacon.begin(); it != last_beacon.end(); ) {
        auto since_last = now - beacon_info.stamp;

        if (!pending.gid_exists(gid)) {
            it = last_beacon.erase(it);  // gid 不存在则清理
            continue;
        }

        if (since_last >= mds_beacon_grace) {
            // 超过 grace 时间没收到 beacon → 触发处理
            if (osdmap_writeable) {
                maybe_replace_gid(pending, gid, info, ...);
            }
        }
        ++it;
    }

    // 5. 尝试用 standby 补充 failed 的 rank
    for (auto &p : pending.filesystems) {
        maybe_promote_standby(pending, *p.second);
    }
}

注意第 3 步last_beacon.emplace 使用的是默认参数,只有当 last_beacon没有该 gid 的记录 时才插入(emplace 语义)。因此只有新出现的 gid 才会被以当前时间初始化,已有记录不受影响。

2.2.2 maybe_replace_gid() 详细逻辑

这是整个状态流转的核心函数(MDSMonitor.cc L1870-L1946):

cpp 复制代码
void MDSMonitor::maybe_replace_gid(FSMap &fsmap, mds_gid_t gid,
    const MDSMap::mds_info_t& info, bool *mds_propose, bool *osd_propose)
{
    // ── 步骤1:计算 may_replace 守卫 ──────────────────────────────────
    // 找到 last_beacon 中所有 MDS 里最新的一条 beacon 时间
    mono_time latest_beacon = mono_clock::zero();
    for (const auto &p : last_beacon) {
        latest_beacon = std::max(p.second.stamp, latest_beacon);
    }
    chrono::duration<double> since = now - latest_beacon;

    // may_replace = true 的条件:
    //   "集群中至少有某个 MDS 最近发来过 beacon"
    //   (距离最新一次任意 beacon 的时间 < max(beacon_interval, beacon_grace * 0.5))
    const bool may_replace = since.count() <
        std::max(g_conf()->mds_beacon_interval, g_conf()->mds_beacon_grace * 0.5);

    const bool frozen = info.is_frozen();

    // ── 步骤2:三路分支 ──────────────────────────────────────────────

    // 分支A:有 rank 的 daemon(REPLAY/RESOLVE/RECONNECT/REJOIN/ACTIVE/STOPPING 等)
    //        且 may_replace=true 且有可用 standby
    if (info.rank >= 0 &&
        info.state != STATE_STANDBY &&
        info.state != STATE_STANDBY_REPLAY &&
        may_replace &&
        !frozen &&
        !fsmap.test_flag(CEPH_MDSMAP_NOT_JOINABLE) &&
        (sgid = fsmap.find_replacement_for(...)) != MDS_GID_NONE)
    {
        // ✅ 触发 fail:移除旧 daemon,提升 standby
        fail_mds_gid(fsmap, gid);
        fsmap.promote(sgid, *fs, info.rank);
    }
    // 分支B:STANDBY 或 STANDBY_REPLAY 且 may_replace=true
    else if ((STATE_STANDBY_REPLAY || STATE_STANDBY) && may_replace && !frozen) {
        // ✅ 触发 fail:直接移除,不需要替代者
        fail_mds_gid(fsmap, gid);
    }
    // 分支C:以上均不满足(包括 may_replace=false 的情况)
    else if (!info.laggy()) {
        // ⚠️ 仅标记 laggy,不做任何 fail 操作
        fsmap.modify_daemon(info.global_id, [](auto& info) {
            info.laggy_since = ceph_clock_now();
        });
    }
    // 如果已经是 laggy,则什么都不做(静默)
}
2.2.3 fail_mds_gid()FSMap::erase()failed.insert()

只有调用了 fail_mds_gid() 才能将 rank 放入 failed 集合(MDSMonitor.cc L1140-L1162):

cpp 复制代码
bool MDSMonitor::fail_mds_gid(FSMap &fsmap, mds_gid_t gid)
{
    // 1. 对持有 rank 的非 STANDBY_REPLAY daemon,blacklist 其 IP
    if (info.rank >= 0 && info.state != STATE_STANDBY_REPLAY) {
        blacklist_epoch = mon->osdmon()->blacklist(info.addrs, until);
    }
    // 2. 调用 FSMap::erase()
    fsmap.erase(gid, blacklist_epoch);
    last_beacon.erase(gid);
    ...
}

FSMap::erase() 中的关键逻辑(mds/FSMap.cc L879-L907):

cpp 复制代码
void FSMap::erase(mds_gid_t who, epoch_t blacklist_epoch)
{
    auto &fs = filesystems.at(mds_roles.at(who));
    const auto &info = fs->mds_map.mds_info.at(who);

    if (info.state != MDSMap::STATE_STANDBY_REPLAY) {
        if (info.state == MDSMap::STATE_CREATING) {
            // CREATING 阶段失败:从 in 中移除(rank 从未真正存在过)
            fs->mds_map.in.erase(info.rank);
        } else {
            // 其他所有有 rank 的状态(包括 REPLAY/RESOLVE/RECONNECT/ACTIVE 等):
            // 将 rank 加入 failed 集合 ← 这就是 ceph fs status 显示 "failed" 的来源
            fs->mds_map.failed.insert(info.rank);
        }
        fs->mds_map.up.erase(info.rank);     // rank 不再被 daemon 持有
    }
    fs->mds_map.mds_info.erase(who);          // 删除 gid 记录
    fs->mds_map.last_failure_osd_epoch = blacklist_epoch;
    mds_roles.erase(who);
}

结论:STATE_RESOLVE 的 daemon 如果被 erase(),会走 else 分支,rank 进入 failed 集合,ceph fs status 显示 failed。但前提是 fail_mds_gid() 被调用。

2.2.4 maybe_promote_standby():处理 failed 集合
cpp 复制代码
// MDSMonitor.cc L1948-L1999
bool MDSMonitor::maybe_promote_standby(FSMap &fsmap, Filesystem& fs)
{
    // 遍历所有 failed rank,尝试找到 standby 接管
    set<mds_rank_t> failed;
    fs.mds_map.get_failed_mds_set(failed);
    for (const auto& rank : failed) {
        auto&& sgid = fsmap.find_replacement_for({fs.fscid, rank}, {});
        if (sgid) {
            // 找到 standby,promote → state = STATE_REPLAY,rank 从 failed 移出
            fsmap.promote(sgid, fs, rank);
        }
    }
}

三、完整状态流转图

复制代码
MDS 进程启动
    │
    ▼ (发送 BOOT beacon)
[STATE_BOOT]  ──────────────────────────────────────────────────────────────
    │ Monitor: prepare_beacon() 将 BOOT 处理为 STANDBY,插入 standby_daemons
    ▼
[STATE_STANDBY] ←─── 每次 tick last_beacon 刷新
    │ Monitor: maybe_resize_cluster() 或 maybe_promote_standby() 调用 promote()
    ▼ (rank 已有 failed 状态时)
[STATE_REPLAY] ──── daemon 自己通过 beacon 上报推进 ────────────────────────
    │ MDS daemon 完成日志扫描后,自行上报 STATE_RESOLVE
    ▼
[STATE_RESOLVE] ──── daemon 自己通过 beacon 上报推进 ───────────────────────
    │ MDS daemon 完成分布式操作消歧后,自行上报 STATE_RECONNECT
    ▼
[STATE_RECONNECT]
    │ MDS daemon 完成客户端重连后,自行上报 STATE_REJOIN
    ▼
[STATE_REJOIN]
    │ MDS daemon 完成缓存 rejoin 后,自行上报 STATE_ACTIVE/CLIENTREPLAY
    ▼
[STATE_ACTIVE] ←────────────────────────────────────────────────────────────
    │ Monitor: maybe_resize_cluster() 收缩时设置 STATE_STOPPING
    ▼
[STATE_STOPPING]
    │ MDS daemon 导出完元数据后,自行上报 STATE_STOPPED
    ▼
rank 进入 stopped 集合(no daemon holds it)

────────────── 故障路径 ───────────────────────────────────────────────────
[任意有 rank 的状态] + beacon 超时 + may_replace=true + 有 standby
    │ Monitor: maybe_replace_gid() → fail_mds_gid() → erase()
    ▼
rank 进入 [failed] 集合(ceph fs status 显示 "failed")
    │ Monitor: maybe_promote_standby() 找到 standby
    ▼
rank 重新进入 [STATE_REPLAY](由新 standby daemon 持有)

四、MDS 心跳(Beacon)对状态变化的影响

4.1 心跳的记录机制

cpp 复制代码
// MDSMonitor.cc L308-L317
void MDSMonitor::_note_beacon(MMDSBeacon *m)
{
    auto &beacon = last_beacon[gid];
    beacon.stamp = mono_clock::now();  // 记录收到 beacon 的时间
    beacon.seq = seq;
}

last_beacon 是一个 map<mds_gid_t, beacon_info_t> 的内存数据结构,记录每个 gid 最后一次收到 beacon 的时间。这个数据结构是 Monitor leader 独有的内存状态,不持久化到 Paxos。

_note_beacon() 在以下情况被调用:

  • preprocess_beacon() 中:beacon 需要更新 map(有状态变更/健康变更/laggy 清除)时
  • preprocess_beacon()reply: 标签处:无变更但需要回复时

4.2 心跳超时对状态的影响(核心)

maybe_replace_gid() 中的 may_replace 守卫是心跳影响状态流转的关键:

cpp 复制代码
// MDSMonitor.cc L1881-L1889
mono_time latest_beacon = mono_clock::zero();
for (const auto &p : last_beacon) {
    latest_beacon = std::max(p.second.stamp, latest_beacon);
    //              ↑ 取所有 MDS 中最新一次 beacon 的时间(不只是当前 gid)
}
mono_time now = mono_clock::now();
chrono::duration<double> since = now - latest_beacon;

const bool may_replace = since.count() <
    std::max(g_conf()->mds_beacon_interval, g_conf()->mds_beacon_grace * 0.5);

这段逻辑的含义是:may_replace 反映的不是"当前 gid 的心跳是否正常",而是"集群中是否至少有一个 MDS 最近发来过心跳"。

设计意图(代码注释 L1878-L1880):

"We will only take decisive action (replacing/removing a daemon) if we have some indication that some other daemon(s) are successfully getting beacons through recently."

如果所有 MDS 的 beacon 都超时了,可能是 Monitor 自身的网络/性能问题,不应草率地 fail 掉所有 MDS。

4.3 心跳对各状态的具体影响矩阵

MDS 当前状态 心跳正常 心跳超时 + may_replace=true 心跳超时 + may_replace=false
STATE_STANDBY 正常维护在 standby_daemons fail_mds_gid() → 从 standby 移除 仅标记 laggy
STATE_STANDBY_REPLAY 正常维护 fail_mds_gid() → 从 mds_info 移除 仅标记 laggy
STATE_REPLAY 正常,等 daemon 推进状态 fail_mds_gid() + 提升 standby → rank 进入 failed 再立即由新 standby 接管 仅标记 laggy
STATE_RESOLVE 同上 同上 ⚠️ 仅标记 laggy,rank 停留在 RESOLVE(laggy or crashed)
STATE_RECONNECT 同上 同上 ⚠️ 同上
STATE_ACTIVE 同上 同上 ⚠️ 同上
STATE_STOPPING 正常,等 daemon 推进到 STOPPED 同上 ⚠️ 同上

4.4 laggy 标记的作用与局限

maybe_replace_gid() 进入分支 C 时,只是设置 laggy_since

cpp 复制代码
fsmap.modify_daemon(info.global_id, [](auto& info) {
    info.laggy_since = ceph_clock_now();
});

laggy 标记的影响:

  1. ceph fs status 输出变化 :状态显示从 resolve 变为 resolve(laggy or crashed)FSMap.cc L186-L188)
  2. find_replacement_for() 中跳过 laggy standbyget_available_standby() 会跳过 laggy() 为 true 的 standby(FSMap.cc L719)
  3. 不影响 rank 的归属 :rank 仍然在 up 中,failed 集合中没有它

关键局限laggy 标记一旦设置,且 may_replace 持续为 false,则:

  • 下次 tick 检测时,因为 info.laggy() 已为 true,进入分支 C 的 else if (!info.laggy()) 判断为 false
  • 整个 maybe_replace_gid() 什么都不做,彻底静默
cpp 复制代码
// 后续 tick 中,如果 laggy 已设置且 may_replace 仍为 false:
// 分支A: may_replace=false → 不进入
// 分支B: 不是 STANDBY/STANDBY_REPLAY → 不进入
// 分支C: info.laggy() == true → !info.laggy() = false → 不进入
// 结果:完全静默,状态永远不变

五、针对现网问题的根因分析

问题场景还原

复制代码
1. 主 MDS 机器挂掉
2. 备 MDS 顶上,调用 FSMap::promote(),state = STATE_REPLAY
3. daemon 通过 beacon 推进:REPLAY → RESOLVE
   Monitor 收到 beacon,记录 state = STATE_RESOLVE
4. 此时 systemctl 重启失败,19/28号 MDS 进程已停止
5. MDS 停止发送 beacon
6. tick() 检测到 beacon 超时,调用 maybe_replace_gid()

关键问题:may_replace 的计算

cpp 复制代码
mono_time latest_beacon = mono_clock::zero();
for (const auto &p : last_beacon) {
    latest_beacon = std::max(p.second.stamp, latest_beacon);
}

此时遍历的是 last_beacon map 中所有 gid 的记录。如果整个集群的 MDS 都处于异常状态(其他 MDS 也可能故障),没有任何 MDS 在正常发 beacon,则:

  • latest_beacon = 很久之前的时间
  • since.count() = 很大的值
  • may_replace = false

进入分支 C:else if (!info.laggy()) → 只标记 laggy_since

之后的每次 tick:三个分支都不满足,完全静默

为什么不显示 failed

因为 fail_mds_gid() 从未被调用,所以 FSMap::erase() 从未执行,所以 rank 从未进入 mds_map.failed 集合。ceph fs status 读取的正是 failed 集合,所以显示的不是 failed

实际显示的是:resolve(laggy or crashed) ← state=RESOLVE + laggy=true

完整问题路径图

复制代码
MDS 19/28 进程停止
    │
    ▼ tick() beacon 超时检测
maybe_replace_gid()
    │
    ├── 计算 may_replace
    │   集群中所有 MDS 都不健康,latest_beacon 很旧
    │   → may_replace = FALSE
    │
    ├── 分支A:may_replace=false → ✗ 不进入
    ├── 分支B:state=RESOLVE,非 STANDBY → ✗ 不进入
    └── 分支C:!info.laggy() → ✓ 首次进入,设置 laggy_since
                                       后续 tick:info.laggy()=true → ✗ 不进入

结果:fail_mds_gid() 从未调用
      → FSMap::erase() 从未调用
      → failed.insert() 从未调用
      → rank 不在 failed 集合中
      → ceph fs status 显示 resolve(laggy or crashed)
      → 永远不会自动恢复

这是一个真实的 BUG

may_replace 的保守策略在单个或少量 MDS 异常 时是合理的保护,但在整集群 MDS 都处于异常状态 时,会导致任何有 rank 的 daemon 都无法被 fail 掉。

尤其对于已经处于 RESOLVE 等恢复中间状态的 MDS,进程停止后:

  • 不能自动流转到 failedmaybe_replace_gidmay_replace=false 阻止)
  • 不会被新的 standby 接管(maybe_promote_standby 只处理 failed 集合中的 rank)
  • ceph fs status 永远显示 resolve(laggy or crashed),直到人工干预

根本修复方向 :对于 laggy_since 已超过某个阈值(例如 mds_beacon_grace 的若干倍)的 daemon,即使 may_replace=false,也应强制执行 fail_mds_gid()。或者区分"没有 standby 可替换"(需要保守)和"集群整体异常"(需要激进清理)两种场景。


六、相关配置参数

参数 默认值 说明
mds_beacon_interval 4s MDS 发送 beacon 的周期
mds_beacon_grace 15s beacon 超时阈值,超过后触发 maybe_replace_gid()
mon_mds_blacklist_interval 1天 fail 后 blacklist 持续时间

may_replace 的阈值 = max(mds_beacon_interval, mds_beacon_grace * 0.5) = max(4, 7.5) = 7.5 秒 。即:如果 7.5 秒内集群中没有任何 MDS 发来 beacon,may_replace 就为 false。

相关推荐
yyyyy_abc1 天前
ceph学习笔记
笔记·ceph·学习
自由且自律3 天前
ceph实战,基于docker部署
运维·ceph·docker·容器·云计算
老wang你好5 天前
Ceph存储全攻略:RBD、CephFS与RGW详解
ceph
珂玥c7 天前
Ceph集群新增osd
ceph
老wang你好8 天前
Ceph分布式存储系统全解析
ceph
一个行走的民21 天前
分布式系统中 Map 增量(Delta)是否需要持久化
ceph
一个行走的民23 天前
BlueStore 核心原理与关键机制
ceph
奋斗的小青年I25 天前
Proxmox VE Ceph 超融合集群落地实战
windows·ceph·vmware·pve·超融合·proxmox
一个行走的民25 天前
深度剖析 Ceph PG 分裂机制:原理、底层、实操、影响、线上避坑(最全完整版)
ceph·算法
一个行走的民25 天前
Ceph 核心概念精讲:彻底搞懂 PG、PGP、pg_num、pgp_num
ceph