ceph心跳机制

知道,而且这是 Ceph 运维里非常关键的一对概念。

1) down:表示"当前不可达/不在工作"

  • 含义 :MON/OSD 心跳认为该 OSD 当前不在线(进程挂了、机器宕机、网络断了、严重卡顿导致心跳超时等)。

  • 谁设置 :通常由 MON 根据心跳自动判断(也可能管理员手工干预,但常见是自动)。

  • 直接影响

    • 该 OSD 上的 PG 对外服务会立刻受影响:

      • 副本数不足 (degraded),可能出现 peeringundersizedstale 等状态。
    • CRUSH 仍然认为它是"in"(如果它还没 out),所以它仍在 CRUSH 计算的"候选集合"里,只是因为不可达而无法实际提供 I/O。

  • 典型场景:短暂网络抖动、重启 OSD、主机维护等。你通常希望它能很快回来,而不是立刻触发大规模数据迁移。

2) out:表示"被从数据放置集合中移除"

  • 含义 :CRUSH/OSDMap 认为该 OSD 不再参与数据放置与承载(即使它物理上在线也不应该再接收/保存副本)。

  • 谁设置

    • 可以手工:ceph osd out <id>
    • 也可以自动:OSD 长时间 down 后,MON 依据 mon_osd_down_out_interval 把它 自动标记 out(你配置里该值是 2000 秒,约 33 分钟)。
  • 直接影响

    • 集群会开始把原本放在该 OSD 上的数据副本 迁移/重建到其他 OSD(recovery/backfill),以恢复副本数(size)。
    • 这会带来明显的后台 I/O、网络流量和恢复压力,也可能影响前台性能。
  • 典型场景:磁盘坏了、主机长期下线、你确认短期不会回来,或者你要永久下架该盘/该节点。

3) 二者关系与组合状态

  • downout 可以同时存在,也可以单独出现:

    • down + in:OSD 挂了,但集群暂时认为它仍是成员,通常会等待其恢复(直到 down 太久可能自动 out)。
    • up + out:OSD 进程在线,但被剔除出 CRUSH(常见于你手工 out 做维护/下架;此时它在线也不会被用于放置数据)。
    • down + out:既不可达,又被剔除;集群会把数据往别处迁移(或已经迁移中/迁移完)。

4) 运维上最重要的判断原则

  • 你只要把 OSD 标记 out,基本等价于告诉集群:"不要等它了,开始搬数据"。
  • 如果只是短时间维护或你不确定是否会很快恢复,通常先处理 down 的根因(网络/进程/主机),避免过早 out 引发大规模 backfill。

如果你愿意描述一下你的具体现象(例如:是单个 OSD down 还是整机多 OSD down、持续多久、是否已经触发 degraded/backfill、有没有设置 noout 标志),我可以按"最小扰动"原则给你一个处理顺序。

是的,你的理解是正确的。

down + in 的状态下,不会立刻触发数据迁移(recovery / backfill)。下面我用"机制层面 + 运维层面"把这点说清楚,避免常见误解。


一、为什么 down + in 不会立刻迁移数据(核心原因)

1️⃣ CRUSH 视角:OSD 仍然是"合法成员"

  • in 的含义是:

    该 OSD 仍然参与 CRUSH 数据放置计算

  • 所以从 OSDMap/CRUSH 的角度看:

    • PG 的 目标副本集合(acting set / up set)没有改变
    • 只是其中某个 OSD 暂时不可达

👉 CRUSH 没变,就没有"重新放置"的理由

👉 没有重新放置,就不会启动 backfill


2️⃣ Ceph 的设计目标:避免"短抖动=大迁移"

Ceph 明确区分:

  • 可恢复的短期故障(down)
  • 结构性成员变化(out)

如果 down 就立刻迁移:

  • 网络抖动、OSD 重启都会引发 TB 级 backfill
  • OSD 回来后还要 再迁移回来一次
  • 集群性能会被严重拖垮

所以:

只有当 OSD 被判定为"不再回来"时(out),才启动数据迁移。


二、down + in 状态下,集群实际会发生什么

✔ 会发生的事情

  • PG 可能进入:

    • degraded
    • undersized
    • peering
  • 读写行为:

    • 有足够副本仍然在线 → 读写继续
    • 写入会受限(取决于 pool 的 size / min_size
  • MON 持续等待该 OSD 恢复

  • 不会产生大规模 backfill

❌ 不会发生的事情

  • ❌ 不会把该 OSD 上的数据副本迁移到其他 OSD
  • ❌ 不会改变 PG 的 CRUSH 归属
  • ❌ 不会马上恢复副本数

三、什么时候才会开始迁移?(关键触发点)

情况 1:OSD 被标记为 out

  • 手工:

    bash 复制代码
    ceph osd out <id>
  • 自动:

    ini 复制代码
    mon_osd_down_out_interval = 2000  # 你这里是约 33 分钟

    OSD down 超过该时间 → MON 自动 out

👉 一旦变成 out,立刻开始 backfill / recovery


情况 2:你主动干预

  • 设置:

    bash 复制代码
    ceph osd set noout

    即使 OSD down 很久,也不会自动 out(常用于维护窗口)


四、一个典型时间线(非常重要)

假设:

  • pool:size=3
  • OSD.12 异常

⏱ 时间轴

复制代码
T0    OSD.12 心跳丢失 → down + in
T0~T+33min  PG degraded,但不迁移
T+10min    OSD.12 恢复 → up + in(一切正常)

👉 没有任何 backfill,影响最小


如果 OSD 没回来:

复制代码
T0        down + in
T+33min   MON 自动 osd out 12
T+33min+ 开始 recovery/backfill

五、运维中的一句"黄金原则"

Down 是"状态判断",Out 是"结构决策"

  • down"我现在联系不上它"
  • out"我决定不再指望它了"

六、你这套配置下的特别说明(结合你前面给的参数)

你配置里:

ini 复制代码
mon_osd_down_out_interval = 2000
osd_recovery_max_active = 1
osd_recovery_sleep = 0.4

这意味着:

  • down 33 分钟内:不会迁移
  • 一旦 out:迁移会非常温和、慢,但对前台影响小

👉 这是一个非常保守、以业务稳定优先的策略组合。


如果你愿意,我可以:

  • 给你一个 OSD 维护的"标准操作流程(SOP)"
  • 或帮你判断:当前某个 down OSD 要不要立刻 out(基于 pool size / min_size / 当前 PG 状态)

你可以直接贴一段 ceph -sceph osd tree 的输出,我可以帮你判断风险。
mon_osd_min_up_ratioMON 侧的"安全阈值参数" ,用于在 OSD 大面积异常时,阻止集群进入破坏性状态 。它的作用经常被误解,下面我从定义 → 触发条件 → 实际影响 → 与相近参数对比四个层面把它讲清楚。


一、mon_osd_min_up_ratio 是做什么的(一句话版)

当处于 up 状态的 OSD 占比低于该阈值时,MON 会进入"保护模式",拒绝或限制一系列会导致集群雪崩的状态变更操作。

它的核心目标只有一个:
防止"半个集群挂了,还继续重平衡/选主/写入",从而把好好的数据弄坏。


二、什么叫 up ratio(非常关键)

先明确几个概念:

  • up:OSD 进程在线、能心跳、能通信

  • in:OSD 参与 CRUSH 数据放置

  • up ratio

    text 复制代码
    up_ratio = up_osds / total_osds

例如:

  • 总 OSD = 100
  • 当前 up = 35
    up_ratio = 0.35

三、mon_osd_min_up_ratio 的触发条件

假设配置:

ini 复制代码
mon_osd_min_up_ratio = 0.3

当:

text 复制代码
up_osds / total_osds < 0.3

即:

只有不到 30% 的 OSD 处于 up 状态

MON 就会认为:

"集群已经严重失常,不能再做任何可能造成不可逆破坏的动作"


四、触发后,MON 会"禁止"哪些行为(重点)

当低于 mon_osd_min_up_ratio 时,MON 会 拒绝或冻结 以下行为:

1️⃣ 禁止自动将 OSD 标记为 out

  • 即使 OSD 已经 down 很久
  • 即使超过 mon_osd_down_out_interval

👉 避免在大面积故障时触发海量 backfill


2️⃣ 禁止 PG 自动重映射(rebalancing / recovery)

  • 不再进行:

    • backfill
    • recovery
    • remap
  • PG 状态会停留在 degraded / undersized

👉 宁可服务降级,也不破坏数据结构


3️⃣ 禁止危险的 pool/OSDMap 变更

  • 比如:

    • 某些 CRUSH 相关更新
    • 可能导致 PG 大规模变动的操作

4️⃣ 写入可能被进一步限制(间接影响)

  • 如果:

    • pool 的 min_size 无法满足
    • 副本数不足
  • 写入会失败(这是 OSD/PG 层决定的,但该参数会让状态长期停留)


五、这个参数"不做什么"(常见误区)

它不会:

  • 不会自动把 OSD 标记为 down
  • 不会直接停止集群
  • 不会主动杀进程
  • 不会修复任何 OSD

它只是一个 "MON 决策刹车阀"


六、和几个容易混淆的参数对比(非常重要)

参数 控制维度 含义
mon_osd_min_up_ratio up 至少多少比例 OSD 在线
mon_osd_min_in_ratio in 至少多少比例 OSD 仍在 CRUSH
mon_osd_down_out_interval 时间 down 多久后自动 out
noout flag 人工 人为禁止 OSD out

一句话区分:

  • min_up_ratio

    "在线的 OSD 太少了,先别动结构"

  • min_in_ratio

    "参与数据放置的 OSD 太少了,别继续搞"


七、结合你前面给的配置(很重要)

你之前贴的配置里有:

ini 复制代码
mon_osd_min_in_ratio = 0.3

如果你同时有:

ini 复制代码
mon_osd_min_up_ratio = 0.3

那意味着:

  • 只要有 ≥30% 的 OSD 仍然 up 且 in

    • 集群允许继续恢复、out、backfill(但你又用 recovery 限流参数控制了速度)
  • 低于 30%

    • 集群进入"冻结保护状态"
    • 不再自动 out
    • 不再 rebalancing

👉 这是一个 典型的"容灾型保守配置",适合:

  • 硬件规模较大
  • 对误操作/雪崩极度敏感
  • 宁可短期不可写,也不愿冒数据结构风险的场景

八、一个非常现实的运维判断公式(送你)

是否应该让 MON 继续自动 out OSD?

看三个值:

text 复制代码
up_ratio
in_ratio
min_size / size
  • 如果:

    • up_ratio < mon_osd_min_up_ratio
    • in_ratio < mon_osd_min_in_ratio
  • 那么:

    任何"out"操作都应该非常谨慎,甚至暂停


九、总结一句话(可当速记)

mon_osd_min_up_ratio 是 MON 的"紧急刹车",
当在线 OSD 太少时,禁止一切可能导致 PG 大规模迁移或结构变化的自动决策。

如果你愿意,我可以:

  • 帮你判断 这个值在你当前 OSD 数量下是否合理
  • 或结合你某次真实故障(比如"掉了一半节点")推演 Ceph 实际会怎么反应

你可以直接告诉我:
总 OSD 数、当前 up/down 情况、主要跑 RBD 还是 CephFS。

下面按"机制---路径---参数---典型现象---调优要点"的顺序,把 Ceph 的心跳(liveness)机制讲清楚,重点覆盖你关心的两条链路:

  1. OSD ↔ OSD(数据面故障检测的主力)
  2. OSD ↔ MON(控制面汇总判定与发布 OSDMap)

并结合你前面贴过的参数(我会直接引用你配置里出现的那些项)。


0. 先把概念摆正:Ceph 里"谁在判定谁死了"

  • OSD ↔ OSD 心跳 :用于 OSD 彼此判断对端是否可达(快速、分布式、贴近数据路径)。

  • MON 的 down 判定:MON 最终对外宣布"OSD 是 up 还是 down",依据来自:

    • OSD 的 心跳/报告(beacon、osdmap report)
    • 其他 OSD 对某 OSD 的 down 报告(failure report)
    • 自身维护的超时逻辑

一句话:

OSD 之间先"发现",MON 再"裁决并广播"(通过 OSDMap)。


1) OSD ↔ OSD 的心跳机制(核心)

1.1 心跳做什么

每个 OSD 会对同一 PG/邻近 CRUSH 关系中的一些 OSD 建立心跳会话,周期性发送"我还活着"的探测包。探测成功则维持对端为"可达";探测超时则触发"怀疑 down",进一步向 MON 报告。

1.2 心跳走哪条网络

Ceph 通常会在 front/publicback/cluster 两张网卡(或同一张网)上进行通讯;心跳消息属于 messenger 层消息,走 OSD 的网络通道(和数据复制同体系)。

你配置里:

  • public_network = 172.16.111.0/24
  • cluster_network = 172.16.111.0/24

意味着:你没有把 public 与 cluster 分离,心跳与复制/客户端 I/O 共享同一网段,拥塞时更容易出现"误判 down"的风险。

1.3 关键参数(你配置里有的)

osd_heartbeat_interval = 6
  • 含义:OSD 发送心跳探测的周期(秒)。
  • 影响:越小,故障发现更快;但网络与 CPU 开销更大。
osd_heartbeat_grace = 20
  • 含义:允许连续心跳失败/收不到响应的最大宽限时间(秒)。超过则认为对端异常,进入 failure 流程。
  • 直觉:大致相当于"允许丢多少秒的心跳"。

粗略理解:对端在 20 秒内一直不可达,就会被怀疑 down(实际还叠加消息重试、队列拥塞等因素)。

与之强相关(你配置里也出现了 messenger 线程/节流)
  • ms_async_op_threads = 16:messenger 处理线程,过小会让心跳消息在队列里排队,造成"假超时"。
  • ms_dispatch_throttle_bytes = 419430400:分发节流,拥塞时会延迟处理消息,同样可能放大心跳延迟。
  • ms_max_backoff = 2:退避上限,影响拥塞/失败时的重试节奏。

典型现象

  • 网络瞬时拥塞、OSD 负载打满、messenger 队列积压 → 心跳消息延迟 → 可能出现短暂 down 抖动。

2) OSD ↔ MON 的"心跳/汇报"机制(控制面)

OSD 与 MON 之间不是简单"互 ping",而是一组更完整的"定期汇报 + 超时判定"机制。它的目标是:让 MON 持续掌握 OSD 的存活与状态变化,并形成一致的 OSDMap。

2.1 OSD 向 MON 的定期动作

(A) Beacon("我还在"的固定节奏)

你配置里:

  • osd_beacon_report_interval = 6

含义:OSD 以该间隔向 MON 发送 beacon/状态心跳类消息(实现细节会随版本略变,但作用一致:维持 OSD 的存活存在感)。

(B) OSDMap/PG 统计报告(状态同步)

你配置里:

  • osd_mon_heartbeat_interval = 3
  • osd_mon_report_interval_max = 20
  • osd_pg_stat_report_interval_max = 20

含义(按功能分组理解):

  • osd_mon_heartbeat_interval:OSD 与 MON 的联络/保活节奏更密(3 秒),用于更快故障感知或会话维护。
  • osd_mon_report_interval_max:OSD 向 MON 上报自身状态(容量、标志、心跳、一些运行统计等)的最大间隔。
  • osd_pg_stat_report_interval_max:PG 统计上报的最大间隔(PG 状态变化、degraded 等)。

2.2 MON 侧如何判定 OSD "可能不正常"

你配置里:

  • mon_osd_report_timeout = 25

含义:如果 MON 在该时间窗口内 收不到某 OSD 的报告/心跳类信息,会认为该 OSD 状态可疑,结合其他 OSD 的 failure report 来最终判定 down。

再配合:

  • mon_tick_interval = 2:MON 做超时检查的主循环粒度。

直觉化:

OSD 如果 25 秒都没"跟 MON 打招呼",MON 会开始认为它不对劲(但是否立刻 down,要看 failure 报告/裁决逻辑)。


3) "OSD 判定 OSD down"如何变成"MON 宣布 OSD down"

这一步是很多人真正困惑的地方:为什么我看见某个 OSD 在某些节点上"看起来 down",但 MON 过一会儿才宣布?

3.1 failure report(OSD → MON 报告"我觉得它死了")

当某 OSD 多次探测不到对端,达到 osd_heartbeat_grace 等阈值后,会向 MON 发送 failure report。

MON 不会立刻只听一个人的。

3.2 MON 的"仲裁阈值"(防止误判)

你配置里:

  • mon_osd_min_down_reporters = 2
  • mon_osd_reporter_subtree_level = rack

含义:

  • mon_osd_min_down_reporters = 2:至少需要 2 个独立报告者都说"它 down 了",MON 才更倾向接受该结论。
  • mon_osd_reporter_subtree_level = rack:报告者的拓扑层级要求/约束(希望报告来自不同故障域/符合某种 CRUSH 子树逻辑),降低"同机架交换机抖一下导致机架内互相误报"的概率。

结果:

你会看到:OSD 之间先怀疑并上报,MON 收集到足够"可信、多源"的报告后,才更新 OSDMap,把该 OSD 标成 down


4) down、out 与心跳的联动(你之前问过的那条链路)

心跳只负责"活不活"。当 OSD 被 MON 宣布 down 后,是否进一步变成 out 触发迁移,取决于另一组参数(你配置里也有):

  • mon_osd_down_out_interval = 2000(约 33 分钟):down 持续多久自动 out
  • mon_osd_auto_mark_in = True:回来后是否自动 in

因此典型时间线是:

  1. OSD ↔ OSD 心跳失败 → failure report
  2. MON 收集足够报告 → OSDMap 标记 down
  3. 只要仍然 in不会立刻迁移
  4. down 超过 mon_osd_down_out_interval:MON 可能标记 out → 开始 backfill/recovery

5) 最常见的"心跳误判"根因与如何用参数定位

5.1 网络共享导致拥塞(你这类配置更容易踩)

public 与 cluster 同网段时:

  • 客户端突发 I/O、恢复流量、scrub、backfill 都在同一网络竞争
  • 心跳包延迟上升,可能触发 osd_heartbeat_grace 误判

定位建议(不改参数也能先验证)

  • 看是否在高吞吐/恢复期出现 down 抖动
  • 看 OSD 日志是否有 "heartbeat no reply / slow ops" 同时出现
  • 看是否出现大面积同机架/同交换机下的 OSD 同时抖动(对应 reporter_subtree_level 的价值)

5.2 OSD 线程/队列被打满(messenger 处理不过来)

  • ms_async_op_threads 太小或 CPU 打满
  • ms_dispatch_throttle_bytes 节流导致处理延迟
    会造成"消息收到了但处理太晚",效果和丢包类似。

5.3 grace 与 interval 配比不合理

经验上:

  • interval 太大 + grace 太小:容易误判
  • interval 太小 + grace 太大:开销高、故障发现慢

你的配比(6s/20s)属于相对常见的"稳健型"区间,但在网络不隔离+负载峰值大的场景仍可能抖动。


6) 你这套参数在一起如何"读"

把你配置里与心跳最相关的几项合在一起看:

  • OSD↔OSD:

    • osd_heartbeat_interval=6
    • osd_heartbeat_grace=20
  • OSD→MON:

    • osd_mon_heartbeat_interval=3
    • osd_beacon_report_interval=6
    • osd_mon_report_interval_max=20
  • MON 判定:

    • mon_osd_report_timeout=25
    • mon_osd_min_down_reporters=2
    • mon_osd_reporter_subtree_level=rack
  • 迁移触发:

    • mon_osd_down_out_interval=2000

综合含义是:

  • OSD 层面较快发现问题(20s 级)
  • MON 不会轻易宣布 down(至少 2 个报告者 + 拓扑约束 + 25s 超时)
  • 即便 down,也会等较久才 out(33 分钟),减少误判导致的迁移风暴

这是典型"稳定优先"的配置思路。


如果你希望我把这套机制讲得更"落地到排障",你可以贴任意一段(无需全量):

  • ceph -s
  • ceph health detail
  • 某个 OSD 的日志里与 heartbeat 相关的几行

我可以据此把"是网络拥塞、CPU 排队、还是单盘 I/O 卡死导致心跳超时"这种路径给你一条条对上,并指出应该先看哪些指标、哪些参数不建议轻易动。

这是一个非常关键、而且经常被"半懂"的问题。结论我先给你一句绝对不模糊的话,然后再把机制拆开解释。


一、先给结论(非常重要)

一个 OSD 仅仅变成 down(仍然是 in)时,
Ceph 不会进行真正意义上的数据迁移(backfill)。

但要注意两点容易混淆的地方:

  1. 可能会看到 recovery 字样(但它不等于 backfill)
  2. 只有 OSD 被标记为 out,才一定会触发 backfill

下面我们把这几个词严格区分开。


二、为什么 down + in 不会迁移数据(机制层)

1️⃣ CRUSH 没变 → 放置没变

  • in 表示:

    这个 OSD 仍然参与 CRUSH 计算

  • PG 的 目标副本集合(acting set)仍然包含这个 OSD

因此:

  • Ceph 没有理由去"换地方放数据"
  • 不会产生大规模数据拷贝

三、那为什么有时候会看到 recovery

这是最容易混淆的点

先给你一个严格定义表(重点)

名词 本质含义 是否拷贝大量对象
recovery 恢复副本一致性(补缺、追日志) ❌ 不一定
backfill 重新放置副本(OSD 变化导致) ✅ 一定
scrub 校验一致性

四、逐个讲清楚 recovery / backfill 到底是什么


4.1 recovery 是什么(很多人误会)

Recovery = "把副本追到一致状态"

常见触发场景:

  • OSD 短暂 down 后 又回来了

  • 在 down 期间:

    • 其他副本继续接收了写入
  • 回来的 OSD:

    • 数据是"旧的"

这时 Ceph 会:

  • 对比 PG 日志(pg log)
  • 缺失的对象或对象片段 同步回来
  • 目标是:让副本再次一致

👉 这是"修复",不是"迁移"

特征:

  • 数据量通常 远小于全量 PG
  • 不涉及 CRUSH 重算
  • 不改变副本位置
  • 发生在 OSD 回来之后(up)

4.2 backfill 是什么(真正的数据迁移)

Backfill = "你不在了,我换地方放"

触发前提(任意一个):

  • OSD 被标记为 out
  • CRUSH map 变化(加/删 OSD、权重变化)
  • pool 的 size / CRUSH rule 改变

Ceph 会:

  • 重新计算 PG 的目标 OSD 集合
  • 完整对象 从旧位置复制到新 OSD
  • 直到满足副本数

👉 这才是你直觉里理解的"数据迁移"

特征:

  • 数据量大
  • 网络/磁盘 I/O 明显
  • 对前台影响明显
  • 持续时间长

五、时间线对比(非常关键)

情况 A:OSD down 10 分钟,又回来了

复制代码
T0      OSD down + in
T0~T10  PG degraded(不迁移)
T10     OSD up + in
T10~    recovery(追写入期间的差异)

✔ 无 backfill

✔ 只有 recovery

✔ 影响小


情况 B:OSD down 很久 → out

复制代码
T0      OSD down + in
T0~T33m PG degraded(不迁移)
T33m    MON osd out
T33m+   backfill / recovery

✔ 有 backfill

✔ 有 recovery

✔ 影响明显


六、PG 状态字样如何对应(实战非常重要)

你在 ceph -s / ceph pg dump 里看到的状态:

PG 状态 含义
degraded 副本数不足(常见于 down + in)
undersized 副本 < min_size
recovering 正在做 recovery
backfilling 正在做 backfill
active+clean 完全正常

重点

recovering ≠ 一定在迁移数据
backfilling = 确实在搬数据


七、结合你之前的配置(你这套很"稳")

你有:

ini 复制代码
mon_osd_down_out_interval = 2000
osd_recovery_max_active = 1
osd_recovery_sleep = 0.4

这意味着:

  • down 33 分钟内:不会 backfill
  • 回来的话:只做 recovery,而且非常温和
  • 真的 out 了:backfill 也会被严格限速

👉 这是典型的:

"宁可短时间 degraded,也不轻易搬数据" 策略


八、一句"工程级"总结(你可以记这个)

Down ≠ 搬数据
Out = 开始搬数据
Recovery = 补差
Backfill = 换地方


如果你愿意,我可以:

  • 用一个 3 副本、3 OSD 的具体例子,一步步画出 PG 在 down / up / out 各阶段到底拷了什么数据
  • 或直接根据你真实集群的 ceph -s 输出,告诉你:现在看到的 recovery 是"安全的",还是已经进入"搬数据阶段"

你可以随便选一个。

相关推荐
阿里嘎多学长2 小时前
2025-12-25 GitHub 热点项目精选
开发语言·程序员·github·代码托管
Oxye2 小时前
服务器内存不足导致程序没完全起起来,报错Required type must not be null
java·开发语言
乾元2 小时前
自动化补丁评估与策略回滚:网络设备固件 / 配置的风险管理
运维·开发语言·网络·人工智能·架构·自动化
2501_916766542 小时前
【Java】static关键字与类的加载顺序
java·开发语言
山峰哥2 小时前
SQL查询优化秘籍:从Explain分析到性能飞跃
开发语言·数据库·sql·oracle·性能优化·系统优化
世转神风-2 小时前
qt-通信协议基础-QStirng转QByteArray-与字节序互动
开发语言·qt
资生算法程序员_畅想家_剑魔2 小时前
Java常见技术分享-14-多线程安全-锁机制-常见的锁以及底层实现-synchronized
java·开发语言
江沉晚呤时2 小时前
构建智能代理的利器:深入解析 Microsoft Agent Framework
开发语言·c#
走粥2 小时前
JavaScript Promise
开发语言·前端·javascript