我让大模型以流式方式返回一段 JSON,想着边收到边解析更快,结果每次拿到的都是残缺的半截 JSON 解析直接报错,而且流到一半模型出错时前面已经发给用户的内容根本收不回来的深度复盘

我做了个功能让大模型返回一段结构化 JSON,为了更快用了流式(streaming),模型一边生成一边把 token 一段段推给我,我想着边收到边解析更流畅,于是每收到一段就 JSON.parse 一下累积的内容。结果问题百出:大部分时候 JSON.parse 直接报 Unexpected end of JSON input,因为我拿到的是 {"name": "张 这样残缺的半截 JSON;偶尔更糟,流传到一半模型那边出错/网络断了,可我前面已经把半截内容渲染给用户看了,既没法补全也收不回来。复盘才理解流式的本质:它是把结果一小段一小段陆续推送,在流结束前你手里永远是到目前为止的不完整片段;而 JSON 这种结构化数据必须完整才有意义、才能解析,残缺的 JSON 不是不太完整的 JSON 而是无法解析的非法字符串。根因是我把流式过程中的不完整片段当成了已经完整可用的结果。这篇复盘从故障现场讲到流式的本质、能增量消费与必须完整才有效的区分,再到结构化累积到流结束再整体解析、纯文本才边收边展示、用容错解析器、处理中途中断、区分展示与消费的完整正解,以及其他把中间态当完整结果的坑,和形成中的中间态不完整不确定不可依赖、需要确定性的操作必须基于已完成的结果态、别急于消费还在变化的过程态的认知。

我让大模型以流式方式返回一段 JSON,想着边收到边解析更快,结果每次拿到的都是残缺的半截 JSON 解析直接报错,而且流到一半模型出错时前面已经发给用户的内容根本收不回来:一次误把流式增量输出当成完整结果来用的深度复盘

那个"JSON 解析时灵时不灵、还偶尔把半截脏数据展示给了用户"的 bug,让我重新理解了 LLM 的流式输出。我做了个功能:让大模型返回一段结构化的 JSON(比如一个包含多个字段的分析结果),为了"更快",我用了流式(streaming)方式——模型一边生成、一边把 token 一段段地推给我,我想着"边收到边解析,体验更流畅"。于是我在每收到一段流式数据时,就 JSON.parse 一下累积的内容。结果一运行,问题百出:大部分时候 JSON.parse 直接报错(Unexpected end of JSON input)——因为我拿到的是 {"name": "张 这样残缺的半截 JSON;偶尔还更糟:流传到一半,模型那边出错了/网络断了,可我前面已经把半截内容渲染给用户看了,这下既没法补全、也收不回来。复盘这件事,我才真正理解了流式输出的本质,以及我犯的认知错误:问题出在我把"流式增量到达的、还没结束的部分内容",当成了"已经完整、可以拿去用的结果"。流式输出的本质是:模型把结果一小段一小段(token by token)地、随着生成陆续推送给你,在"流结束(done)"之前,你手里的永远只是"到目前为止的不完整片段";JSON 这种结构化数据,是"必须完整才有意义、才能解析"的——一个缺了后半截、括号没闭合的 JSON,不是"一个不太完整的 JSON",而是"一段无法解析的非法字符串";所以我在流还没结束时就去 JSON.parse 累积的片段,自然解析失败;而把半截内容直接展示/使用,更是把"过程中的临时状态"当成了"最终结果",一旦中途出错就覆水难收。根本原因是:流式输出是增量、陆续到达的,在流结束前手里始终是不完整片段;而 JSON 等结构化数据必须完整才能解析/使用;我误把"流式过程中的不完整片段"当成"完整结果"去解析和展示,导致解析报错、以及中途出错时半截内容无法收回。问题的根,是误用流式输出——把增量、未结束的不完整片段当成完整结果去解析(JSON 须完整)和展示,既解析失败,又在中途出错时把半截脏数据暴露给了用户。这篇就把这次"流式输出处理不当"的坑,从头到尾复盘一遍。

故障现场:边收边解析,拿到的全是半截 JSON

问题在于把流式过程中的不完整片段当完整 JSON 解析:

// 我的错误写法: 流式接收, 每收到一段就尝试 JSON.parse(以为"边收边解析更快")
let buffer = "";
for await (const chunk of llmStream) {        // 流式: 一段段陆续到达
  buffer += chunk.delta;                       // 累积
  const obj = JSON.parse(buffer);              // ✗ 此刻buffer往往是残缺的半截JSON!
  render(obj);                                 // ✗ 还把半截/临时内容展示给用户
}

/*
为什么报错 / 出问题:
  1. 流式输出是"一段段陆续到达"的: 某一刻 buffer 可能是 '{"name": "张三", "age":'
     ——一个【还没传完、括号没闭合】的残缺JSON;
  2. JSON 必须【完整】才能解析: 残缺的JSON不是"不太完整的JSON", 而是"非法字符串";
     → JSON.parse('{"name": "张') → SyntaxError: Unexpected end of JSON input;
  3. 我在"流没结束"时就去parse → 绝大多数时候都在解析半截 → 报错;
  4. 更糟: 我还把过程中的内容render给用户; 若流到一半模型出错/网络断,
     前面已展示的半截内容收不回来 → 用户看到残缺/错误的结果, 且无法回滚。

流式输出的本质:
  - 它是为了"边生成边展示"(像打字机效果), 优化的是"首字延迟"和体验;
  - 在流"结束(done事件/[DONE])"之前, 你手里永远是"到目前为止的不完整片段";
  - "不完整片段"对【纯文本展示】是OK的(显示已生成的部分, 越来越多);
  - 但对【需要完整才有意义的东西】(JSON解析、要校验的结构、要据此做决策的结果)不行!

★ 关键: 流式 = 增量、陆续、未结束前不完整;
  - "能增量消费的"(纯文本逐步展示): 适合流式, 边收边显示;
  - "必须完整才能用的"(JSON解析/结构校验/据此决策): 必须等流结束、拿到完整结果再处理;
  别把"过程中的不完整片段"当"完整的最终结果"去解析、去据此行动、去不可逆地展示。
*/

看着控制台一连串 Unexpected end of JSON input,再想到用户那边偶尔闪现的半截乱码,我又懊恼又恍然:"我以为'流式=更快=边收边处理',就急着去解析每一段……可 JSON 哪能解析半截?它要么完整、要么就是堆废字符。流式给我的是'正在生成的过程',我却当成了'已经生成好的结果'。"这个坑最隐蔽的地方在于:偶尔会"碰巧成功"——当某一段流恰好让 buffer 凑成一个完整 JSON 时(极少),parse 就成功了,造成"有时好有时坏"的诡异表象;而"展示半截内容"的问题只在"流中途出错"这个小概率事件下才暴露,平时流都正常结束,根本发现不了下面就来拆解,流式输出到底该怎么用。

第一件事:搞懂流式的本质与"增量 vs 完整"

我顺着这次事故,把流式输出的本质和正确用法彻底理清了。

流式输出到底是什么? 什么能边收边用、什么必须等完整?

【核心: 流式是增量陆续推送、未结束前手里始终是不完整片段; "纯文本展示"可边收边显示, 但"JSON解析/
   结构校验/据此决策"必须等流结束拿完整结果; 别把过程中的不完整片段当完整结果去解析/行动/不可逆展示】

1. 流式输出(streaming)是什么:
   - 模型边生成边把token一段段推给你(SSE/chunked), 而非等全部生成完一次性返回;
   - 目的: 降低"首字延迟"、提升体验(打字机效果)、让长输出能尽早开始展示;
   - 代价/特性: 在"流结束(done/[DONE])"之前, 你手里永远是"到此为止的不完整片段"。

2. 关键区分: "能增量消费的" vs "必须完整才有效的"
   - 能增量消费(适合边收边用): 纯文本逐步展示(聊天回复一个字一个字显示)、
     逐行处理(每完整一行就处理一行)、增量统计;
   - 必须完整才有效(必须等流结束):
     * JSON/XML等结构化解析: 残缺的就是非法的, 解析必失败;
     * 需要校验的结构、需要据此做决策/调用工具的结果;
     * 任何"半截就用会出错或不可逆"的场景。

3. 我错在哪:
   - 把"必须完整才能解析的JSON", 当"能增量消费的"去边收边parse → 解析半截 → 报错;
   - 把"过程中的临时片段", 当"最终结果"去渲染给用户 → 中途出错时半截内容收不回。

4. 正解方向:
   ① 结构化输出(JSON): 流式累积到流结束(done), 再对【完整buffer】做一次JSON.parse;
      (若要流式展示进度, 可展示纯文本进度提示, 但解析只在完整后做)
   ② 真要"流式解析JSON": 用专门的"增量/容错JSON解析器"(能处理不完整片段), 别用标准JSON.parse;
   ③ 纯文本展示: 才适合边收边追加显示(这是流式的主场);
   ④ 处理中途错误/中断: 监听error/abort, 流没正常结束(没收到done)就【不采用】这次结果、
      回滚已展示的临时内容(或标注"生成中断"), 别把残缺当成功;
   ⑤ 区分"展示"和"消费": 给用户看可以流式(临时态), 但程序要据此做逻辑/解析的, 必须用完整结果。

5. 本质: 区分"过程态"和"结果态"
   - 流式给你的是"正在进行的过程"(逐步逼近最终结果);
   - "过程中的中间态"和"最终的结果态"是不同的, 不能混用;
   - 凡"需要完整性/确定性"的操作, 必须基于"结果态"(流结束后的完整内容), 而非"过程态"。

一句话: 流式是增量陆续、未结束前不完整; 纯文本可边收边展示, 但JSON解析/结构校验/据此决策必须等流
   结束拿完整结果; 别把过程中的不完整片段当完整结果去解析/行动; 处理好中途错误, 别把残缺当成功。

这套认知,是整个坑的根。流式是什么:模型边生成边一段段推送,目的是降首字延迟、提升体验;代价是流结束前手里始终是不完整片段关键区分:能增量消费的(纯文本逐步展示、逐行处理)适合边收边用;必须完整才有效的(JSON 解析、结构校验、据此决策)必须等流结束我错在:把必须完整的 JSON 当能增量消费的去边收边 parse、把过程中的临时片段当最终结果去渲染正解方向:结构化输出累积到 done 再整体 parse、要流式解析用容错解析器、纯文本才边收边显示、处理中途错误(没 done 就不采用并回滚)、区分展示与消费本质:区分"过程态"和"结果态"——凡需要完整性/确定性的操作必须基于结果态一句话:流式是增量陆续、未结束前不完整;纯文本可边收边展示,但 JSON 解析/结构校验/据此决策必须等流结束拿完整结果;别把过程中的不完整片段当完整结果去解析/行动;处理好中途错误,别把残缺当成功。

第二件事:正解——结构化等完整、纯文本才流式、处理中断

知道了"过程态≠结果态",正解就清楚了:按"能不能增量消费"决定怎么处理流。

// 正解1: 结构化输出(JSON)——累积到流结束, 再对完整内容解析一次(本次该做的)
let buffer = "";
let done = false;
try {
  for await (const chunk of llmStream) {
    if (chunk.type === "done") { done = true; break; }   // 流结束标志
    buffer += chunk.delta;
    // (可选)展示纯文本进度: showProgress(buffer)  ← 只展示, 不解析
  }
  if (!done) throw new Error("流未正常结束(中断)");          // 中途断了, 不采用
  const obj = JSON.parse(buffer);                            // ✓ 流结束后, 对完整buffer解析一次
  useResult(obj);                                            // ✓ 基于完整结果做逻辑
} catch (e) {
  rollbackOrShowError(e);                                    // 解析失败/中断: 回滚、报错, 别用残缺
}

// 正解2: 纯文本展示——这才是流式的主场, 边收边追加显示
let text = "";
for await (const chunk of llmStream) {
  text += chunk.delta;
  appendToUI(chunk.delta);    // ✓ 逐字追加显示(打字机效果), 不完整也无所谓(只是显示进度)
}
// 文本展示对"不完整"是容忍的: 显示已生成的部分, 越来越多, 自然过渡到完整。

// 正解3: 真要"流式解析结构化"——用容错的增量解析器, 别用标准JSON.parse
//   - 用支持"部分JSON(partial JSON)"的库(如 best-effort-json-parser / 流式JSON解析器);
//   - 它能从残缺片段里尽力解析出"目前已确定的字段", 容忍未闭合;
//   - 适合"想流式展示结构化结果的已生成部分"的高级场景(但复杂, 非必要不用)。

// 正解4: 一定要处理流的"中途错误 / 中断"
//   - 监听 error / abort 事件、检查是否收到正常的结束标志(done/[DONE]);
//   - 没正常结束 → 这次结果【不算数】: 别采用、回滚已展示的临时内容、提示用户"生成中断, 请重试";
//   - 别把"残缺的半截"当成"成功的结果"。

// 正解5: 想清"展示给人" vs "程序消费"
//   - 展示给人看: 可以流式(用户能接受逐步出现的临时态);
//   - 程序要据此解析/校验/调工具/做决策: 必须用流结束后的【完整、确定】结果。

// 核心: 按"能否增量消费"分流——纯文本边收边展示(流式主场); JSON等结构化累积到流结束再整体解析;
//   处理好中途错误(没done就不采用并回滚); 区分"展示用的过程态"和"消费用的结果态"。

这套正解的关键,是按"这东西能不能增量消费"来决定怎么对待流,并严格区分"展示"和"消费"结构化等完整:JSON 累积到流结束(收到 done)再对完整 buffer 解析一次,基于完整结果做逻辑——这正是本次该做的。纯文本才边收边显示:这是流式的主场,逐字追加、容忍不完整。真要流式解析结构化:用容错的增量 JSON 解析器,别用标准 parse。处理中途错误/中断:没收到正常结束标志就不采用、回滚临时内容、提示重试,别把残缺当成功。区分展示与消费:给人看可流式(过程态),程序据此解析/决策必须用完整结果(结果态)。

第三件事:其他几个"把不完整/中间态当完整结果"的坑

顺着这次流式,我把"误把中间态当最终态"的几类坑也一并理了:

几类"把不完整/中间态当完整结果"的坑:

坑1: 读流式/分块网络数据, 按固定大小切分就当一条记录——TCP是字节流, 一次read到的
   可能是半条或多条消息(同343粘包半包); 要按协议边界拼完整再解析。

坑2: 文件还在写就去读——另一个进程正在写文件, 你读到了写了一半的内容;
   正解: 写完原子重命名(write临时文件+rename), 读方读到的总是完整的。

坑3: 事务未提交就读到中间状态——读未提交(脏读)拿到别人事务中途的、可能回滚的数据;
   正解: 合适的隔离级别, 别依赖未提交的中间数据。

坑4: 异步操作没等完成就用结果(同591/587)——Promise没resolve、查询没执行完就用;
   正解: 等待完成(await/回调)再用结果。

坑5: 分批/分页处理时, 拿到部分页就当全部——只处理了第一页就以为是全量(同589);
   正解: 确认是否还有更多, 处理完整或明确知道是采样。

坑6: 进度条/中间统计当最终结论——任务跑到一半的中间指标, 当成最终结果汇报;
   正解: 等任务完成再下结论, 中间态只作参考。

共同的根: 很多东西在"完成/结束/提交"之前, 处于"不完整、可能还会变、可能会失败"的【中间态】;
   把中间态当成"已完成的最终态"去解析、去据此决策、去不可逆地使用, 就会出错;
   要清楚地区分"过程中"和"已完成", 凡需要完整性/确定性的操作, 必须基于"已完成的结果态"。

这些坑看似不同,根却是同一个:很多东西在"完成/结束/提交"之前,处于"不完整、可能还会变、可能会失败"的中间态;把中间态当成"已完成的最终态"去解析、决策、不可逆地使用,就会出错认清这个根("区分过程态与结果态,需要确定性的操作必须基于结果态"),就能避开一大类"用了还没好的东西"的问题。

第四件事:适合流式 vs 必须完整——两张对照表

我把哪些场景适合流式边收边用、哪些必须等完整,整理成对照表,贴在了团队的 LLM 接入规范里:

场景 能边收边用吗 怎么处理
聊天回复纯文本展示 ✓ 能 边收边追加显示(打字机)
JSON 结构化结果 ✗ 不能 累积到流结束再 parse
要校验的结构/Schema ✗ 不能 完整后校验
据此调用工具/做决策 ✗ 不能 用完整确定结果
逐行/逐段的文本处理 △ 按完整行 凑够一行再处理一行
Markdown 渲染 △ 容忍 可流式,但代码块等需完整
处理要点 说明
等结束标志 收到 done/[DONE] 才算完整
整体解析 JSON 对完整 buffer 解析一次
处理中断 没正常结束就不采用、回滚
区分展示/消费 展示可流式,消费要完整
容错解析器 真要流式解析结构化才用
错误回滚 半截内容能撤回/标注中断

这两张表的核心,第一张是区分"能增量消费(纯文本展示)"和"必须完整(结构化、决策)"——流式是给"展示"用的,不是给"解析结构化"用的;第二张是处理流式必做"等结束标志、整体解析、处理中断、区分展示与消费"。记住一条:流式输出优化的是"展示体验",凡是"程序要解析、校验、据此行动"的,都要等流结束、用完整结果。

第五件事:关于流式输出的几组容易想当然的认知

这次事故也让我厘清了几组关于流式输出的、容易想当然的概念:

直觉以为 实际上
流式=更快,啥都该边收边处理 流式优化体验,结构化仍要等完整
边收边 parse JSON 更高效 残缺 JSON 解析必失败
流式过程中的内容就是结果 是过程态,流结束才是结果态
展示给用户和程序消费一样处理 展示可流式,消费必须完整
流总会正常结束 可能中途出错/断,要处理中断
偶尔 parse 成功说明写法对 是 buffer 碰巧凑完整,不可靠
展示了半截没关系 中途出错时半截脏数据收不回

这张表里,我栽的是第一行和第三行:把"流式=更快"理解成"所有东西都该边收边处理",又把"流式过程中的片段"当成了"结果",结果对着半截 JSON 一通解析、还把临时内容暴露给了用户厘清这些,核心是一个意识:流式输出给你的是"正在生成的过程"而非"已生成的结果";它适合"逐步展示"这种容忍不完整的场景,但凡需要"完整性/确定性"(解析、校验、决策)的,都必须等流结束、拿到完整的结果态。

第六件事:用 LLM 流式输出时,我现在的自检习惯

现在每当我要用 LLM 的流式输出,我都会先按这张图问自己:

这张图的精髓,是"纯文本才流式展示、结构化等完整、处理中断、区分展示与消费"先问输出是纯文本还是结构化、结构化就等流结束整体 parse处理中途出错区分给人看还是程序消费这套习惯,让我从"流式就边收边解析"变成了"过程态归过程态、结果态才用于解析决策"——核心始终是:流式是增量陆续、未结束前不完整;纯文本可边收边展示,但 JSON 解析/结构校验/据此决策必须等流结束拿完整结果;别把过程中的不完整片段当完整结果。

我立下的几条规矩

这场"边收边解析半截 JSON、还暴露残缺内容"的事故,换来了我用 LLM 流式输出时,刻进骨子里的几条铁律:

  1. 流式输出是增量、陆续推送的,在流结束前手里始终是不完整片段。
  2. 纯文本展示适合流式(边收边追加显示),这是流式的主场。
  3. JSON 等结构化数据必须完整才能解析;累积到流结束(收到 done)再整体 parse。
  4. 残缺的 JSON 不是"不完整的 JSON",而是"非法字符串",parse 必失败。
  5. 必须处理流的中途错误/中断:没正常结束就不采用、回滚临时内容、提示重试。
  6. 区分"展示给人(可流式过程态)"和"程序消费(必须完整结果态)"。
  7. 凡需要完整性/确定性的操作(解析、校验、决策),必须基于流结束后的完整结果。

附:一个安全消费 LLM 流式 JSON 的封装

借这次的坑,我封装了一个工具:它对外提供"纯文本进度回调(可流式展示)"和"完整结果回调(流结束后才给完整 JSON)"两个口子,把"过程态"和"结果态"从 API 层面就分开。

/**
 * 安全消费 LLM 流式输出:
 *  - onProgress(text): 流式过程态, 给纯文本展示用(可不完整);
 *  - 返回值: 流正常结束后的完整结果(结构化), 解析失败/中断则抛错。
 */
async function consumeLLMStream(stream, { onProgress } = {}) {
  let buffer = "";
  let finished = false;
  try {
    for await (const chunk of stream) {
      if (chunk.type === "done" || chunk.done) { finished = true; break; }
      buffer += chunk.delta ?? "";
      onProgress?.(buffer);          // 过程态: 只给展示, 不解析
    }
  } catch (e) {
    throw new Error(`流式中断: ${e.message}`);   // 中途出错, 明确抛
  }
  if (!finished) throw new Error("流未正常结束, 结果不完整");  // 没收到done, 不算成功
  try {
    return JSON.parse(buffer);       // 结果态: 流结束后, 对完整buffer解析一次
  } catch (e) {
    throw new Error(`完整输出仍非合法JSON: ${e.message}`);
  }
}

// 调用方: 展示和消费职责清晰分离
try {
  const result = await consumeLLMStream(stream, {
    onProgress: (text) => showTypingEffect(text),   // 流式展示(过程态, 容忍不完整)
  });
  useStructuredResult(result);        // 只在拿到完整结果后, 才据此做逻辑(结果态)
} catch (e) {
  showError("生成失败或中断, 请重试", e);   // 中断/解析失败: 不采用残缺
}

// 原则: 从API设计上就把"过程态(展示用、可不完整)"和"结果态(消费用、必完整)"分成两个口子,
//   让调用方不可能"误把过程态当结果态"——把正确用法变成唯一顺手的用法。

这个封装的价值,在于它从接口层面就把"过程态"(onProgress 的文本,供展示)和"结果态"(返回值的完整 JSON,供消费)分成了两个明确的口子:展示用过程态、消费用结果态,调用方不可能再像我当初那样把半截片段拿去解析。把"区分过程与结果"这个容易搞混的认知,固化进了 API 的形状里。

写在最后

回头看,这场由"把流式的不完整片段当完整结果"引发的、解析报错又暴露残缺内容的事故,真正教给我的,远不止"JSON 要等流结束再解析"这一个技巧。它让我对"一个东西在'正在形成的过程中'和'已经形成的结果'是两种本质不同的状态; 处于'过程中'的它, 是不完整、不确定、随时可能变化或夭折的, 绝不能当成'已经定型的结果'去依赖和使用",有了一次刻骨的体会。我栽跟头,是因为我急于使用一个"还在形成中"的东西——我看到流式数据陆续到来, 就迫不及待地把"到目前为止收到的部分"当成"已经完成的结果"去解析、去展示;可它还没"长成": 那半截 JSON 还没闭合、那段内容还没说完、这个生成过程还可能在下一刻出错夭折;我把"一个正在进行、尚未定型的过程"误当成了"一个已经定型、可以信赖的成品", 于是要么解析失败(它还不是个合法的成品), 要么把一个"可能会变、可能会废"的半成品不可逆地用了出去(展示给用户)这让我领悟到一个关于"过程与结果、未完成与已完成"的深刻认知:许多事物都有一个"正在形成"到"已经完成"的过程; 处于"形成中(in-progress)"的中间态, 具有"不完整、不确定、可逆、可能失败"的本质属性, 而"已完成(committed/finalized)"的结果态才具有"完整、确定、可依赖"的属性;把"中间态"当"结果态"来对待——基于一个"还没定的东西"去做"需要它已经定了"的事(解析、校验、决策、对外承诺、不可逆的行动)——是一类极其普遍的错误根源;这不仅是流式输出: 等承诺兑现再宣布、等数据落库再确认、等流程走完再结论、等对方真正同意再行动——本质都是"不要把'还在进行中的过程态'当成'已经成立的结果态'去依赖"这给了我一种对待"进行中之事"的清醒:每当我想使用一个东西时,要先分清"它是已经'定型/完成/确认'了, 还是仍在'形成/进行/待定'中?"——对于"需要它确定才能做"的操作(解析、校验、决策、不可逆地行动), 必须耐心等到它真正'完成'(拿到确定的结果态)再做, 而不是急于消费一个还在变化中的中间态;"清醒区分'进行中的过程态'和'已完成的结果态', 只在结果态上做需要确定性的操作",是避免'把半成品当成品用'式错误的关键认清形成中的中间态不完整不确定不可依赖、需要确定性的操作必须基于已完成的结果态、别急于消费还在变化的过程态——这,是我用一次流式输出处理不当的事故,换来的、关于 AI、也关于如何区分过程与结果的、最朴素也最深刻的领悟。如果这篇复盘,能让你下次用 LLM 流式返回 JSON 时,忍住"边收边 parse"的冲动、稳稳等到流结束再解析完整内容,那我对着满屏 Unexpected end of JSON input 和用户那闪现的半截乱码懊恼的这段时间,就值了。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

我的服务跑了几个月一直好好的,某天突然各种 No space left on device,数据写不进、健康检查失败,连同节点上别的服务一起遭殃,排查发现是日志文件没配轮转涨到了几十 G 把磁盘撑满了的深度复盘

2026-6-3 1:07:10

技术教程

我们追求微服务把一个本来内聚的业务拆成了十几个小服务,本想解耦独立部署,结果一个下单流程要串着调八个服务、链路又长又慢、改一个小需求要协调好几个服务一起发版、出了问题谁也说不清的深度复盘

2026-6-3 1:19:28

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索