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 是"安全的",还是已经进入"搬数据阶段"

你可以随便选一个。

相关推荐
BingoGo1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack4 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1235 天前
matlab画图工具
开发语言·matlab
dustcell.5 天前
haproxy七层代理
java·开发语言·前端