知其然,知其所以然
MongoDB 2026-10-12

count、countDocuments、estimatedDocumentCount 的差别

实测 count 的三种写法:estimatedDocumentCount 读元数据只要 0.2 ms,countDocuments({}) 要数 100 万个文档 97 ms,带索引的条件走 COUNT_SCAN(1.4 ms)、无索引则 COLLSCAN(110 ms);kill -9 重启后 estimatedDocumentCount 是 0,要 validate 才修正;带 limit 的 count 提前停止。

MongoDB count countDocuments estimatedDocumentCount 元数据 真实验证 动画演示
MongoDB 2026-10-12

索引占多大:前缀压缩与字段长度

实测索引占多大:20 万个文档上 12 个字段的索引,每条目从 5.4 字节(枚举)到 150.6 字节(128 字符随机串),全部索引 79.8 MB 比 68.2 MB 数据还大;顺序递增的字符串比随机的小 3.4 倍(前缀压缩);关掉前缀压缩后膨胀 3.6~5.0 倍;随机字符串每个字符约 1.14 字节;线性增长。

MongoDB 索引大小 前缀压缩 字段长度 WiredTiger 真实验证 动画演示
爬虫工程 2026-10-12

重试与指数退避:加抖动和不加抖动的重试风暴

200 个客户端同时遇到 1 秒故障的模拟:立刻重试向服务器砸了 2400 个请求且全部放弃;没有抖动的指数退避让 200 个客户端每轮同时重来,31.6 秒才结束还有 26 个放弃;加完全抖动 5.3 秒、去相关抖动 2.9 秒全部成功。

爬虫 重试 指数退避 抖动 jitter 惊群 asyncio Python 真实验证 动画演示
爬虫工程 2026-10-12

429 与 Retry-After:服务端告诉你等多久

实测爬虫对 429 和 Retry-After 的处理:立刻重试向限流服务器发了 110 个请求仍失败 15 个,遵守 Retry-After 只发 23 个、3.0 秒全部成功;urllib3 支持整数和 HTTP-date 两种写法,默认上限 21600 秒;429/503 只要带 Retry-After,即使不在 status_forcelist 里也会被重试。

爬虫 429 Retry-After 限流 urllib3 Retry requests Python 真实验证 动画演示
MongoDB 2026-10-12

$lookup:有无索引的执行差别

实测 $lookup 有无索引的差别:外键有索引是 IndexedLoopJoin,1,000 条订单 3.9 ms;没有索引是 NestedLoopJoin,2,367 ms(约 600 倍),10,000 条要 24 秒;建索引后立刻恢复;let / pipeline 形式慢约 5 倍;$lookup 结果超过 16 MiB 可以返回但不能 $out。

MongoDB $lookup 索引 连接 IndexedLoopJoin NestedLoopJoin 真实验证 动画演示
爬虫工程 2026-10-12

哪些错误该重试:超时、5xx、4xx 的分类

1000 个 URL 的模拟(瞬时故障、永久 404/403、永远 500 的 bug 页):不重试成功 400;任何失败都重试成功 750 但 1950 个请求中 500 个浪费在永久错误上;只重试网络错误成功 550;网络错误 + 429/502/503/504 白名单成功 750、浪费 0。

爬虫 重试 错误分类 HTTP状态码 超时 5xx 4xx requests Python 真实验证 动画演示
MongoDB 2026-10-12

数组更新操作符:$push、$pull、$addToSet、$[]

实测数组更新操作符:$push 的 $each / $position / $sort / $slice,$addToSet / $pull / $pullAll / $pop 的语义;位置操作符 $、$[]、$[<id>] 加 arrayFilters;对非数组字段 $push 的报错;$addToSet 对子文档字段顺序敏感;8 线程各 100 次 $push 全部保留(800),读-改-写只剩 153。

MongoDB 数组更新 $push $pull $addToSet 位置操作符 arrayFilters 真实验证 动画演示
爬虫工程 2026-10-12

POST 重试:幂等性与重复提交

实测 POST 重试:urllib3 的 Retry 默认只重试 DELETE/GET/HEAD/OPTIONS/PUT/TRACE;对 POST 打开重试后,创建订单后丢回应的场景重复下了 2 个订单;带 Idempotency-Key 且服务器去重时只有 1 个;服务器先创建订单再回 503 同样重复。

爬虫 重试 幂等 POST Idempotency-Key urllib3 Retry requests Python 真实验证 动画演示
MongoDB 2026-10-12

并发 upsert 与唯一索引:E11000 从哪来

实测并发 upsert:没有唯一索引时 16 线程 300 轮产生 632 个文档(227 个 k 重复);有唯一索引时文档数正好 300,服务端自动重试所以客户端看不到 E11000;条件不含唯一键时 E11000 会露给应用;捕获后改普通更新可行;findOneAndUpdate + $inc 取号无重复。

MongoDB upsert 并发 唯一索引 E11000 findOneAndUpdate 真实验证 动画演示
MongoDB 2026-10-12

findAndModify 做任务队列

实测用 findOneAndUpdate 做任务队列:8 个 worker 原子领取 2,000 个任务零重复(7,462 个/秒);先 find 再 update 的做法有 6,377 个任务被重复领取;带条件 update 没有重复但失败 6,223 次、慢 8 倍;按优先级领取、队列索引(0.1 对 17 ms)、租约清扫崩溃的 worker。

MongoDB findAndModify 任务队列 原子领取 租约 真实验证 动画演示
MongoDB 2026-10-12

bulkWrite 的 ordered 与 unordered

实测 bulkWrite 的 ordered 与 unordered:ordered 在第一个错误处停止(nInserted 4),unordered 跳过错误继续(nInserted 6,4 个错误一起返回);混合操作的顺序在 unordered 下不再保证;25 万个文档拆成 3 条命令(maxWriteBatchSize 100,000);单节点上耗时几乎一样。

MongoDB bulkWrite ordered unordered 批量写入 真实验证 动画演示
MongoDB 2026-10-12

写关注 w:1、majority、j:true 的耗时对比

实测写关注的延迟:3 节点副本集上 w:1 0.2 ms,w:2 / w:3 0.6 ms,j:true 与 w:majority 约 4 ms(要等 journal 落盘);secondary 挂掉后 w:majority 仍成功、w:3 超时报 code 64 但写入已生效;只剩 1 个节点 primary 降级;w:0 不报错;写关注的设置位置与优先级。

MongoDB 写关注 writeConcern w:majority journal 副本集 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号