simdjson:每秒解析数 GB 的 JSON
原文:Geoff Langdale, Daniel Lemire. Parsing Gigabytes of JSON per Second. arXiv:1902.08318v7 [cs.DB], 2024 年 7 月 23 日版。
本文是原文的中文翻译,保留了原 paper 的章节编号、图、表与脚注。原文作者单位:branchfree.org(澳大利亚)与 Université du Québec (TELUQ)(加拿大魁北克大学)。
原文:Geoff Langdale, Daniel Lemire. Parsing Gigabytes of JSON per Second. arXiv:1902.08318v7 [cs.DB], 2024 年 7 月 23 日版。
本文是原文的中文翻译,保留了原 paper 的章节编号、图、表与脚注。原文作者单位:branchfree.org(澳大利亚)与 Université du Québec (TELUQ)(加拿大魁北克大学)。
原文:Viktor Leis, Peter Boncz, Alfons Kemper, Thomas Neumann. Morsel-Driven Parallelism: A NUMA-Aware Query Evaluation Framework for the Many-Core Age. SIGMOD 2014, pp. 743–754.
本文是原文的中文翻译,保留了原 paper 的章节编号、图、表与脚注。原文作者单位:Technische Universität München(慕尼黑工业大学)与 CWI(荷兰数学与计算机科学研究基础研究所)。
随着现代计算机架构的演进,两个问题共同阻碍了并行查询执行的前沿方法:(i) 为了利用多核,所有查询工作必须均匀地分配到(很快会是)数百个线程上才能获得好的加速比,然而 (ii) 即使拥有准确的数据统计信息,由于现代乱序执行核心的复杂性,把工作均匀地划分也依然很困难。结果是,现有的"plan-driven(计划驱动)“并行方法撞上了负载均衡和上下文切换的瓶颈,因此不再具备可扩展性。多核架构面临的第三个问题是内存控制器的去中心化,这导致了非一致性内存访问(NUMA)。
对此,我们提出"morsel-driven(小块驱动)“查询执行框架,其中调度成为一个细粒度的、NUMA 感知的运行时任务。Morsel-driven 查询处理取输入数据的小片段(“morsels”),把它们调度给 worker 线程,由 worker 线程执行完整的算子流水线直到下一个 pipeline breaker。并行度不是被烘焙进计划里,而是在查询执行过程中可以弹性地改变,因此 dispatcher(调度器)能够对不同 morsel 的执行速度做出反应,也能根据工作负载中新到达的查询动态调整资源。此外,dispatcher 还感知 NUMA 本地 morsel 和算子状态的数据局部性,使得绝大部分执行都发生在 NUMA 本地内存上。我们在 TPC-H 和 SSB 基准上的评估显示出极高的绝对性能,以及在 32 核上超过 30 的平均加速比。
关键词:Morsel-driven parallelism;NUMA-awareness
原文:Jeff Shute, Radek Vingralek, Bart Samwel, Ben Handy, Chad Whipkey, Eric Rollins, Mircea Oancea, Kyle Littlefield, David Menestrina, Stephan Ellner, John Cieslewicz, Ian Rae, Traian Stancescu, Himani Apte. F1: A Distributed SQL Database That Scales. VLDB 2013.
F1 是 Google 构建的一套分布式关系型数据库,用于支撑 AdWords 业务。F1 是一种混合型数据库,同时具备高可用性、Bigtable 这类 NoSQL 系统的可扩展性,以及传统 SQL 数据库的一致性和易用性。F1 构建在 Spanner 之上,Spanner 提供了跨数据中心的同步复制与强一致性。同步复制意味着更高的 commit 延迟,但 F1 通过带结构化数据类型的层次化 schema 模型以及合理的应用设计缓解了这种延迟。F1 还包含一套功能完整的分布式 SQL 查询引擎,以及自动的变更追踪和发布机制。最近的若干出版物曾断言这些设计目标相互排斥 5, 11, 23。本文的一个关键贡献就是展示我们如何在 F1 的设计中同时达成所有这些目标,以及我们在何处做了取舍与牺牲。
Hash 表的性能通常取决于两件事:冲突发生后如何找下一个候选位置,以及这些候选位置离缓存有多远。传统链式哈希把冲突元素串成链表,逻辑简单,但一次查询可能要跳过多个指针;普通开放寻址没有指针跳跃,却常常只能逐个 slot 检查。
Swiss Table 的核心贡献是在开放寻址表前面加了一层非常小的元数据,让 CPU 能按 group 批量排除大量不可能匹配的 slot。它不改变 hash 表的基本语义,而是改变查找、插入、删除时的观察方式:先用极小的哈希指纹过滤,再对少数候选 key 做精确比较。
这个设计来自 Google 的工程实践,后来成为 Abseil flat_hash_map 的底层实现,也被 Rust 标准库 HashMap 采用。Go 1.24 之后,内置 map 的默认运行时实现也切换到了 Swiss Table 风格。
百分位数是描述数据分布最常用的指标之一:P95、P99 告诉你接口长尾延迟,中位数告诉你"典型"水平。SQL 标准为精确计算提供了 PERCENTILE_CONT 和 PERCENTILE_DISC,大数据引擎则普遍内置了以 sketch 为核心的近似算法。本文从原理出发介绍这些函数与算法,给出每种算法的伪代码,并配上可以手算验证的例子。
假设你正在运营一个分布式限流系统,全公司上百个服务都要经过你分配的"带宽配额"。预算就这么多,但每个服务的真实需求你事先不清楚——有的服务平时风平浪静,促销时流量能翻 10 倍;有的服务每月稳定增长 30%。
你会怎么分配这些带宽?
30 多年前,Van Jacobson 在设计 TCP 拥塞控制时面对的是同一个问题:网络(链路)的带宽是共享资源,发送方不知道链路的当前容量,也不知道有多少其他发送方在抢资源。他必须设计一个让所有发送方在不知道对方存在的情况下,依然能公平、高效地共享链路的算法。
如果你写过监控告警、自适应限流或者负载均衡,大概率遇到过这个问题:怎么用一个数值,实时地描述"当前系统有多慢"?EWMA(Exponentially Weighted Moving Average,指数加权移动平均)几乎是工程实践里的标准答案——它只需要一个 float 的内存,一行加法就能更新,却能给出比简单平均更贴近"当下"的估计。
先看一段栈,再决定要不要继续读——
# 这两份 stack dump 间隔 14 分钟抓的,"jdbc:mysql://10.14.127.31:19030/xxx"
# 的 connection adder 线程,tid 完全一致,栈帧一帧没动。
# 业务侧呢?告警群里全是 SQLTransientConnectionException。说真的,这种栈谁都不想看到——10 个 HikariCP 连接池、每个池的 adder 都卡在 socketRead0,不是忙,是死等。更扎心的是,业务方第一时间甩锅 HikariCP “卡死了”,但 HikariCP 的 MAIN 池好好的;另一边 DBA 看到 MySQL 进程没崩、SHOW PROCESSLIST 也查不出明显异常。两边都没事,问题到底出在哪?
在 Presto/Trino 中,0.5 默认不是 DOUBLE,而是 DECIMAL。这个容易被忽略的字面量类型,会让 bigint * 0.5 这类表达式整体走上 Decimal 算术规则,最终把结果 scale 锁死在 1 位小数。
本文从一个线上"精度丢失"问题切入,逐步拆解 Presto 的类型推导链与 Decimal 四则运算规则,再对比 MySQL 在加减乘除上的差异,最后给出可复用的排查建议。如果你曾在跨引擎或跨团队迁移时被精度问题困扰,这篇文章应该能帮到你。
限流是高并发系统里最朴素的自我保护手段:当流量超过系统承载上限时,主动拒绝或排队部分请求,换取整体稳定。
这篇文章从固定窗口、滑动窗口、漏桶、令牌桶、GCRA 五类经典算法讲起,用 Redis Lua 脚本还原实现细节,再分析 Redisson RateLimiter 的设计本质,最后落到分布式限流的三大关键问题与生产选型建议。如果你正在设计或优化一套限流方案,这篇文章会是一张清晰的路线图。
凌晨 3 点,oncall 电话响了。“服务慢了,用户在刷不出页面。” 你 SSH 进一台从没见过的 Linux 服务器,没有 Prometheus dashboard,没有 APM 火焰图,只有黑漆漆的命令行。
第一分钟该敲什么?
Netflix 性能工程团队 2015 年给出的答案是:10 个命令,60 秒。本文把这套方法整理成一份可以照抄的清单,并补上一张"心智地图",让你不只是机械记忆命令,而是理解为什么要敲它们、应该看哪几列、看完之后该往哪走。
你有没有遇到过这种场景:线上服务偶发延迟,top 看 CPU 正常、iostat 看磁盘不忙、strace 抓不到关键调用,但应用就是慢。想看某个系统调用真实的耗时分布?想找"一闪而过"的短进程?传统工具集体失灵。
问题的根源在于:Linux 内核对你"关着门"。你想观测的所有关键路径——系统调用、网络收发、调度、文件 I/O——都在内核里,而你已经很多年没编译过内核了。
eBPF(extended Berkeley Packet Filter)就是 Linux 给开发者开的一扇窗。它让你不重启内核、不写内核模块,就能在内核的关键路径上跑一段自定义逻辑。本文用三件事讲清它:eBPF 是什么、怎么工作、怎么先用起来。
你有没有遇到过这种情况:公司丢给你 10 万份内部事件报告,问你 “过去三年里,攻击模式呈现出哪些新趋势?” 你把这堆文档丢给传统 RAG 系统,它会按相似度捞出 Top-K 个最相关的文档块,让大模型基于这些片段作答。听起来很合理对吧?
问题来了:大模型拿到的只是 10 万份报告里"和’攻击趋势’长得最像"的几十个片段。它 根本没有通读过完整语料 ,怎么回答得出"新趋势"这种 全局性问题(Global Sensemaking) ?向量检索的本质是"局部相似",而全局总结是"通盘理解",这是两件本质不同的事。
类似的全局性问题还有很多:
GraphRAG(Graph-based RAG)就是为这类问题而生的。它把 RAG 的检索单元从"文本片段"升级为 “知识图谱” ,通过图社区摘要、Map-Reduce 等机制让 LLM 真正具备 全局感知能力 。
你有没有遇到过这种情况:服务器上有两份代码,版本 A 和版本 B,你只想把 A 的改动同步到 B,但网络带宽只有几 Mbps,传输一个 24MB 的文件要等上好几分钟。
也许你会想到先在本地 diff,然后把 patch 发过去。没错,这是个思路。但你有没有想过:如果 A 和 B 都不在同一台机器上,diff 根本跑不起来怎么办?
这就是 rsync 要解决的问题。
正则表达式看似简单,底层却藏着五花八门的实现思路。本文将带你了解递归引擎、BBVM 虚拟机、Pike VM、Thompson DFA 和导数引擎的工作原理,帮助你在实际项目中做出明智的技术选型。
搬家后,Self-Host 服务无法通过公网 IPv4 访问,只能用 IPv6 + DDNS 方案。但家里路由器不支持精细的 IPv6 访问管理,开着防火墙会影响服务,关闭防火墙又等于裸奔。
最终通过三招解决了问题:反向代理隔离、登录增强、FRP 流量转发。
最近搬家,家里的 Self-Host 服务由于限制无法通过公网 IPv4 访问,就改用 IPv6 + DDNS 的方式提供公网域名访问。
切换完成后,立即收到云服务器上 Uptime Kuma 的告警,显示无法连接 IPv6 地址。排查发现 Docker 容器默认不支持 IPv6。