源卷中变化的 B 与 D chunk 指向有限经典 COW 异常存储里保存的原值。

LVM 快照在时间上定格一块块设备

经典 LVM 快照是在源逻辑卷上附加写时复制异常存储。lvcreate -s -L 5G -n snap vg/data 请求五 GiB 存储,实际分配还受卷组空闲容量和分配粒度约束。创建时不需要复制整份源卷,但不代表完全没有工作或必然瞬时完成。thin 快照使用另一种共享池机制,不能把经典快照的独立异常存储套到所有 LVM 快照上。 异常存储要覆盖整个保留窗口内发生变化的不同 chunk 及其元数据,包括备份复制期间的写入。突发负载可能比安静时估算更早耗尽容量。经典存储满后快照会失效,读取开始返回错误。应提前观察有效状态和增长趋势,留下扩容或结束备份的时间;只规定一个百分比告警,而没有响应能力与空闲空间,不能形成可靠恢复计划。 异常存储,不是副本 源使用 snapshot-origin 目标,snapshot 则把未变化的源 chunk 与保存的异常组合成视图。直接写快照的数据进入它自己的 COW 设备。对已保存异常的同一 chunk 反复修改,不需要为这份快照再保存一次原始内容。原文一百万次写入、十六个热块却只有十五个异常的数字,没有找回轨迹;若十六个不同 chunk 都写过,就需十六份数据异常,另加元数据。 lvs -a -o lv_name,lv_attr,origin,data_percent,lv_size 展示类型、状态和用量。swi-a-s--- 只是示意,不是所有快照固定的属性串;第五位 I 表示无效快照。告警应覆盖实际增长速率和处理时间。lvextend 需要 VG 中有可分配空间;lvchange --monitor y 只启用监控,自动扩容还依赖 dmeventd、有效扩容策略及足够容量,并不是一个开关就能保证成功。 ...

四月 10, 2028 · 1 分钟 · XB Field Notes
SYN 队列保存未完成握手的请求,accept 队列保存已建立、等待 accept() 的连接。仅当 listen backlog 配置为 8192、somaxconn 为 4096 时,accept 侧上限为 4096。增加等待容量本身不会提高处理速率;原文全文仍暂缓、待审。

SYN backlog 保存未完成握手的请求

监听中的 TCP 套接字会区分未完成握手的请求,以及已经建立、等待应用 accept() 的连接。真正的参数名是 tcp_max_syn_backlog;本文保留历史 URL 中的拼写。它约束的是内核记住的半开请求,而传给 listen() 的 backlog 约束 accept 队列。先弄清压力发生在哪个阶段,再考虑处理办法,否则调大一个数字很可能没有解决真正的问题。 SYN cookies 是无法继续保存普通握手状态时的兜底机制。它不代表服务器不会过载、不保证报文送达,也不意味着 SYN 队列从此无需关注。即使启用了 cookies,丢包、过滤、资源分配失败和 accept 侧压力仍然可能让连接失败。判断时必须把握手状态、应用接收速度与最终业务响应分开。 SYN 队列保存未完成握手的请求,accept 队列保存已建立、等待 accept() 的连接。仅当 listen backlog 配置为 8192、somaxconn 为 4096 时,accept 侧上限为 4096。增加等待容量本身不会提高处理速率;原文全文仍暂缓、待审。 全文仍暂缓、待审;本图不为文中存疑论断背书。 backlog 参数管的是 accept 队列 Linux 从 2.2 起改变了 listen() backlog 的含义。配置值会受到 somaxconn 限制;只有当两者分别是 8192 和 4096 时,配置上限才是 4096。这是条件明确的配置例子,不是一次测量得到的精确接纳数量。应查看实际监听套接字与其网络命名空间,不能假定默认值,也不能根据短促突发中恰好成功的连接数反推严格容量。 ...

三月 24, 2028 · 1 分钟 · XB Field Notes
任务字节、任务等待与设备三条独立轨道对齐观察窗口,不直接认定责任进程。

iotop 能看出是哪个进程在烧磁盘

iotop 把任务级内核统计接入系统整体的存储调查,可以帮助发现报告大量 IO 或等待的任务,但这两种观察并不相同。被其他工作阻塞的任务,可能是受影响者,而不是争用的来源。内核计数器也不为每种文件系统、缓存与存储层提供完美归因,不能把一个列表直接当成责任判决。 把 iotop 与设备指标、应用延迟放在一起看。活跃写入者或较高等待值,单独都不足以证明存储瓶颈。先比较同一时段,再决定检查哪个组件;两个命令的输出可以形成线索,却不会自动结束调查。应明确自己看到的是工作量、等待时间,还是实际设备完成的操作。 逐个进程的计数器 先核对安装的实现与版本。所引用的 iotop-c 已在主进程行中汇总线程活动;-P 只是隐藏单独的线程行。其他变体应核对各自手册,不能把显示选项误写成首次发生汇总。-o 根据观察到的 IO 活动过滤,不会判断工作是否有害。读写字节速率与 IO 等待百分比单位不同,不能把它们当作同一种消耗排名,也不能只凭一列高低决定是否应终止进程。 Linux 的 read_bytes 统计存储层读取,缓存命中的读取不一定产生这类字节。write_bytes 在页面变脏时记账,不一定等到设备完成写入;取消写入与稍后的回写,会让任务总量和设备吞吐不同。延迟统计记录任务等待,包括同步块 IO 等待;CPU iowait 是另一种整体指标,不能作为可靠的逐任务归责依据。页面缓存中的活动、进程等待和设备忙碌,需要分别解释。 看到谁在扫盘 明确选择排序列,并观察足够时间,区分持续工作和短促突发。写入速率高可能来自预期的备份、索引构建或日志任务。修改调度、限额之前,要关联进程归属、应用角色与当时业务。排名靠前只说明值得进一步检查,不会直接告诉你应轮转日志、迁移任务还是终止进程,正常的批处理也可能占据榜首。 在正确的 PID 命名空间中解析任务,并确认该标识仍指向预期进程。命令行、父子关系与打开文件能够提供上下文,但打开某个文件不证明全部写入都去了那里。两次读取之间 PID 可能复用,陈旧号码可能已经属于无关任务。容器内外看到的号码也可能不同,必须把身份与观察范围一同记录,避免把一个范围中的统计匹配到另一个范围中的进程。 先看再动 观察本身有成本与访问要求。进一步的系统调用追踪可能扰动进程并暴露参数,需要另外获准且范围明确的调查。追加标志属于打开文件时的设置,不是每次 write 系统调用携带的标志。不能把虚构的吞吐、打开文件与追踪输出组合成一次已测得的诊断,也不能看到文件存在就推断写入路径已被证明。 记录基线条件:工具实现、间隔、进程或线程模式、是否累计,以及可比较的业务负载。按文档默认的一秒间隔,-b -n 60 大约是一分钟,不是五分钟,还要考虑启动与首份报告。设备 await 包含排队与服务时间;接近百分之百的利用率,并不能在所有并行 SSD 或 RAID 上证明吞吐已经饱和。 ...

三月 15, 2028 · 3 分钟 · XB Field Notes
blue 与 green 网络范围分离、部分上下文共享;删除 blue 名称后,进程引用仍连接命名空间。

网络命名空间隔离网络资源,名称并不拥有其中所有进程

Linux 网络命名空间分离接口、路由、邻居表、套接字端口和包过滤规则等网络资源。它与其他命名空间共享内核,不是独立操作系统。进程通常继承父进程的网络命名空间,工具也可以在另一个范围中执行进程。这种隔离针对网络资源,不会自动涵盖全部进程身份和文件系统访问,因此需要按实际机制说明边界。 坏掉的样子 运行 ip netns exec 不会自动获得完整容器隔离。PID、用户身份和主机名隔离属于其他机制。应用可能看到不同路由,却仍与父环境共享普通文件和主机名。如果把一个网络命名空间当成完整沙箱,就会赋予它从未配置过的保证。应区分实际改变了哪类资源,以及哪些属性仍然来自原有运行环境。 新命名空间也不会自动得到有用的外部连接。接口需要有意放置和配置,本地回环可能需要启用。移动接口会改变管理它的命名空间,原范围不再把该设备列为自己的接口。因此,从错误范围执行配置命令,可能报告接口不存在,尽管预期设备仍位于另一个命名空间。诊断前应先确认命令的执行上下文。 名称还有独立生命周期。ip netns 按约定在 /run/netns 暴露引用,通常也能通过 /var/run/netns 访问。删除名称会移除这项引用,但进程或其他引用仍可维持命名空间存活。如果清理流程把名称列表中消失,直接等同于所有服务终止,就可能留下网络资源和运行中的进程。名称只是管理入口,不是进程所有权的完整表达。 网络范围不同,而选定上下文仍共享。删除名称后,自有进程引用仍可存活;当前运行仍待验证。 快速验证 文中结果属于历史文章报告;保留验证文件中未找到原始集成日志,本轮没有重新执行特权操作。 将脚本保存为 check-network-namespace.py,只在获准的一次性虚拟机中准备 Docker,并启用 Python 断言运行 python3 check-network-namespace.py。固定的 Python 3.11.16 与 iproute2 6.1.0 软件包仍需可取得。NET_ADMIN 与 SYS_ADMIN 是前提,不保证越过其他安全限制;不要削弱宿主保护。临时 proc 挂载支持其中的网络参数设置,不移动宿主接口,也不发布宿主端口: ...

二月 19, 2028 · 2 分钟 · XB Field Notes
两次历史应用结果都保留可选文件的 ENOENT。必需文件缺失时子进程退出码为 7;仅恢复必需文件后退出码为 0。单条错误记录不能独自证明失败原因。

strace 解释选定的系统调用边界

strace 在选定 Linux 进程与内核之间的边界上观察系统调用和信号,不需要重新构建程序,就能展示尝试访问的路径、参数、返回值和错误。应用日志漏掉操作时,这些证据很有帮助;但它不会暴露每个用户态决定,也不会自动指出哪次失败调用导致最终结果。正确诊断仍需把边界行为与程序控制流程联系起来。 这里展示原文样例的两组受控结果,并非新采集的追踪。同一错误在不同控制流程中意义不同。图中仅展示选定进程与系统调用边界,不代表全部应用工作或完整因果链。当前审核仍为已修订、执行受阻;本次未尝试追踪。 坏掉的样子 父进程可能启动子进程执行真正工作。只追踪父进程,会看到等待和退出,却漏掉子进程中的文件打开失败。使用 -f 跟随新建进程可以扩大范围,但不会自动追踪所有既有兄弟进程或请求涉及的外部服务。被选中的进程集合,本身就是证据范围的一部分,不能只看到主命令被追踪就认定全部参与者都在视野内。 错误返回不一定是根因。程序经常尝试可选文件、搜索多个位置,并从预期失败中恢复。找到第一条 ENOENT,或者退出前最后一次不成功调用,都不能替代理解应用控制流程。真正需要回答的是,这个返回值如何影响正在调查的操作。相同错误名在不同分支里,可能分别代表正常探测和不可继续的条件。 过滤与计时也会改变解释。把输出限制为文件打开,就有意排除了网络及其他活动。追踪还可能改变调度和延迟,尤其影响系统调用频繁的工作负载,没有通用固定降速倍数。过滤后的记录看起来正常,不能证明被排除操作成功,也不能证明没有追踪器时会出现完全相同的竞争时序。 快速验证 本轮复核没有重复追踪集成。所述结果来自此前环境,不证明每个容器都允许 ptrace。 把脚本保存为 straceprobe.py,在安装 strace 的一次性 Linux 环境中运行 python3 straceprobe.py。实测使用 Linux 6.12.76、Python 3.11.2 和 strace 6.1。样本启动自己的无害程序,使用临时配置路径,并要求环境允许追踪新启动子进程: ...

二月 14, 2028 · 1 分钟 · XB Field Notes
用户任务表的五个日历字段之后直接是命令;系统任务表还要先写账号字段。

Cron 系统任务表与用户任务表有不同契约

Cron 可以从不止一种任务表读取计划。用户任务表属于某个账号,而系统任务表能够为每一条记录指定运行账号。把一行原样复制到另一种表中,如果没有调整字段,cron 对命令起点的理解就会变化。排查看似正确的五字段日历表达式之前,应先确认正在编辑的到底是哪种任务表,而不是只检查分钟和小时。 Debian 用户表在五个字段后开始命令,系统表则先增加用户名。未转义百分号先于 shell 引号处理,并分离标准输入。本图为示意图;没有执行需要特权的示例。 账号列改变了解析边界 传统用户记录依次填写分钟、小时、月内日期、月份、星期,再接命令正文,由 crontab 命令安装给选定用户。Debian 的 /etc/crontab 和 /etc/cron.d 下文件,则在五个日历字段之后额外增加用户名。这个用户名属于系统表格式,并不是可以随意放进用户任务表的说明性字段;多写或少写都会改变后续解释。 月份限制仍然必须满足。当月内日期与星期都受到限制时,Debian/Vixie 的日期规则允许满足其中之一,但月份与星期并不是二选一。把表达式迁移到带秒字段或采用其他日期组合方式的调度产品前,应核对具体方言。表面上相似的空格布局,不能证明两个调度器提供相同语义。 系统任务文件还受所有权、权限、名称及末尾换行要求约束。Debian 中应采用 root 所有、组和其他用户不可写且名称被接受的文件,不要把任意备份后缀当成有效任务名。/etc/cron.daily 等周期目录通常通过发行版安排和 run-parts 被调用,不是每份脚本都独立当作 crontab 解析。实际运行时间需要查看本机已安装的调度安排。 坏掉的样子 在 root 用户自己的任务表中,五字段后再写 root,意味着让 shell 执行一个名为 root 的命令。任务表安装成功,不证明这个命令存在。反过来,系统表漏掉账号列,就会把命令文字当成用户名。审阅时需要同时检查解析边界与最终身份,尤其是任务会写文件或读取受保护数据时,不能仅凭“都是 root 配置的”推断执行账号。 任务环境同样是一份契约。不要默认交互别名、shell 启动文件或启动 cron 的父进程环境都会传给任务。需要的值应明确配置,同时选择合适的 PATH 和解释器。cron.d 文件中的环境也不应被认为自动继承 /etc/crontab 中的设置。验证时要采用真正的运行账号检查权限与输出,避免管理员手工执行成功掩盖低权限任务失败。 ...

一月 12, 2028 · 5 分钟 · XB Field Notes
未引用的 report final.md 拆成两个参数,引用展开则保留一个。

Shell 的字段拆分把未加引号的变量拆成多个参数

变量保存的是一个字符串,但没有引号的展开可能把它变成多个命令参数。Bash 的分词阶段使用 IFS 指定的分隔字符检查展开结果,因此,手动引用后能正常使用的路径,放入变量再传递时却可能突然找不到文件。排查时首先应观察接收命令实际拿到的参数数量和每个参数的内容,也要区分空字符串与完全没有参数,不能仅凭终端上看起来相同的一行文本判断输入一致。 IFS 控制分词,而引用还能阻止文件名展开。空参数和没有参数仍是不同情况。 是否分词取决于上下文 默认 IFS 包含空格、制表符和换行符,它们的连续组合会分隔字段,开头和结尾的这类空白也会被忽略。未引用变量里有两个单词时,命令通常收到两个参数;变量为空时,则通常连一个参数都没有。使用 "$value" 会保留一个参数,即使值是空字符串。对于命令行接口,显式传入空值和省略选项值可能触发完全不同的行为。 分词针对适用上下文中的未引用参数展开、命令替换和算术展开结果,并不是重新解析整条命令。普通赋值语句 copy=$value 会保留原字符串,不执行分词和文件名展开。但随后把 $copy 不加引号地作为命令参数使用,仍会重新引入两个问题。Bash 双方括号条件表达式也具有不同于普通命令参数的展开规则,所以赋值或条件判断成功,不能证明后面的外部程序调用也安全。 IFS 是一组分隔字符,不是多字符分隔串,也不是正则表达式。非空白分隔符和空白的处理并不相同,例如连续两个冒号可以产生一个空字段,而连续默认空白通常只是一个字段边界。把 IFS 设为空字符串会关闭分词,但不会把未引用的空展开变成显式空参数。若数据格式有引号、转义或嵌套结构,应使用理解该格式的解析器,不能把调整 IFS 当作通用解析方法。 坏掉的样子 关闭分词并没有关闭随后的文件名展开。即使 IFS 为空,变量里的星号仍可能匹配当前目录下的文件;目录里刚增加一个文件,同一条命令的参数数量就会改变。引用变量能够同时阻止这两种转换,而修改 IFS 只处理了其中一个阶段。控制通配符的 shell 选项也独立存在,不能把它们和分词配置混为一谈。 ...

十二月 31, 2027 · 2 分钟 · XB Field Notes
相等的 8 GiB 范围示意 2 MiB 比 4 KiB 映射更少;分块数量不按比例,也没有测量 TLB 缺失。

巨型页在分配灵活性与翻译覆盖之间取舍

巨型页可以增加每条地址翻译缓存能够覆盖的内存范围,在合适负载下减少翻译开销。但效果取决于访问模式和硬件,不能仅因为申请了很大一块内存,就断定程序频繁发生 TLB 缺失。描述工作集需要的页数减少,也不表示所有翻译能够同时装入处理器的 TLB;页数算术、硬件容量与真实性能是三个不同问题。 页大小是一项输入 x86 常见基准页为 4 KiB,但 Linux 的页大小依赖架构与配置,应读取运行系统而不是把四千多字节当作普遍常量。支持的巨型页尺寸同样会变化;2 MiB 与 1 GiB 是常见例子,不是所有处理器的完整列表。跨机器比较时,应先确认单位和实际尺寸,再比较统计数字。 对理想化的连续 8 GiB 范围,4 KiB 粒度需要 2,097,152 个页面,2 MiB 粒度只需 4,096 个。这只是映射覆盖率计算,没有测量硬件 TLB 容量、缺失率、页表遍历延迟,或同时驻留的翻译数量。不同页面大小对应的翻译缓存结构还可能具有不同容量,因此不能把两种页数之差直接称为实际节省的 TLB 项。 显式池与透明分配 Hugetlb 提供显式申请的大页,并由内核维护相应池。持久池中的页面不能同时用于普通分配,也不能在内存压力下换出。池可以在启动时准备,也能在运行中调整,还可能允许额外的 surplus 页面。启动较早时通常更容易获得连续内存,但这并不表示大页只能一次性在开机前决定数量,之后永远无法改变。 透明巨型页采用另一套机制。依内核支持和政策,较大的匿名内存分配既可能发生在缺页时,也可能由后续合并产生。THP 不只是后台线程,也不要求管理员先准备 hugetlb 池。现代内核还可以支持多种 THP 尺寸,不能把每次透明分配都等同于一个两兆字节映射,更不能用 hugetlb 总数代替 THP 使用量。 ...

十二月 21, 2027 · 2 分钟 · XB Field Notes