这里是全站文章的归档入口,下面是按时间倒序排列的全部文章。若想按主题浏览,请从首页的专题分类进入。
《互联网产品的服务端架构·内容、社交与实时互动》前言
卷二前言:说明本书的读者对象、13 章的组织方式、每章的统一结构、可运行 Go 实验工程的用法、代码分级与版本口径、命名与错误处理约定、表格的读法,以及三种阅读路径、如何跳过已熟悉的部分与如何验证自己真的读懂了;全部代码来自可运行的 Go 1.26 实验工程。
posts
这里是全站文章的归档入口,下面是按时间倒序排列的全部文章。若想按主题浏览,请从首页的专题分类进入。
卷二前言:说明本书的读者对象、13 章的组织方式、每章的统一结构、可运行 Go 实验工程的用法、代码分级与版本口径、命名与错误处理约定、表格的读法,以及三种阅读路径、如何跳过已熟悉的部分与如何验证自己真的读懂了;全部代码来自可运行的 Go 1.26 实验工程。
写队列只设一个阈值,暂停与恢复会在事件循环里反复抖动。本节用 linkd 的 WatermarkHandler 实现高低水位滞回、写队列硬上限、暂停与恢复 OP_READ、令牌桶读限速和帧边界丢弃,并给出可复现的水位迁移、令牌桶配额与硬上限关闭输出。
MappedByteBuffer 的映射、刷盘与取消映射各有边界。本节用 MapProbe 验证只读 force 为空操作、通道关闭不解除映射与 Arena 关闭后的 IllegalStateException,再用 MappedFileServer 对比 mmap 与 transferTo,给出静态文件发送的选择依据与 linkd 落地方式。
卷二序:当产品从「能注册、能改资料」长到「有人发、有人看、有人回应」,服务端要解决的核心问题就从能力建设变成可见性、分发结构与实时一致性;这一卷写给正在做内容社区、社交或 IM 的后端工程师与技术负责人,用百万级用户的「回声」案例讲清判定链、放大成本与可靠性来源。
DirectByteBuffer 的分配与回收不在一条时间线上。本节拆开 Cleaner、MaxDirectMemorySize 与 NMT 三本账,用 DirectMemoryBudget 复现预算拒绝、切片共享、可达泄漏与不可达回收,并给出 linkd 中 BufferPool 的所有权规则与泄漏判定顺序。
零拷贝不是一个系统调用的别名。本节用 8 MiB 文件在 loopback 上拆开 JDK 25 的 transferTo 三级分派,解释返回值 0 的三种来源,并用包裹通道与 JFR 证明:一次返回 8 MiB 也可能只是 1024 次 8 KB 拷贝,macOS 上不要照搬 Linux sendfile/epoll 的结论。
把 DAU、峰值系数、活跃秒数、保留天数、副本数与三项单价放进同一组速查表,用三个案例算例跑出回声的峰值 QPS、图片存储的稳态占用和 200 核一个月的账单,并给出弹性扩缩容的初始参数、测试命令与八个常见估算错误;所有数字均标注为案例假设值并附可复现命令。
本节处理跨线程的请求上下文:ThreadLocal 在线程池中的残留与泄漏、ScopedValue 在 JDK 25 的绑定与恢复、事件循环到业务线程的显式传播,以及不可变消息与 happens-before 如何建立可见性;给出可运行的 RequestContext 与本机输出。
本节给 linkd 补业务线程池:用有界队列和命名线程隔离阻塞任务,按 CPU 与等待比估算线程数,解释 CallerRunsPolicy 为何会把阻塞带回事件循环,并给出指标与拒绝路径;最后用 JDK 25 虚拟线程做同负载对照,附可复现命令与本机单次数据。
附录 B 记录 webapp-lab 的真实工程快照:Go 版本、go.mod、全部 Go 文件清单、目录与包职责、L1 到 L4 的验证分级、三行代码头与 verify 约定,以及只跑一个包、按依赖顺序读代码的方法,帮助读者复现书中的每一个代码块,并说明本卷做到哪一级。
本节拆开 linkd 事件循环的调度层:任务队列为什么必须是多生产者单消费者、execute 的线程归属与重入边界、selector.wakeup 的合并条件、定时任务的最小堆与 select 超时算法,以及一次 500 毫秒阻塞如何让心跳延迟到任务结束;给出可运行的 EventLoopImpl 与本机输出。
在帧编解码之上补齐连接生命周期:用 ping/pong 检测半开连接,按 1000、1001、1002 等关闭码完成关闭握手,并用 ConcurrentHashMap 会话表与每会话有界发送队列实现线程安全广播,给出 WebSocketSessionImpl 与 WebSocketHub。
一份面向评审与复盘的术语和指标速查:解释 DAU、QPS、p95、并发、读写比、命中率、可用性、错误预算、SLI/SLO、回源、灰度、双写、幂等、最终一致、热点、工作集、副本因子与容量余量,并给出常用公式、常见误用和同名指标不同口径的辨析。
从 101 之后的第一段字节开始,拆开 WebSocket 的两字节帧头:FIN、RSV、opcode、MASK 与 7/16/64 位长度编码,讲清客户端掩码的 XOR 算法和控制帧的 125 字节上限,并用 WebSocketFrameCodec 处理半帧、continuation 分片与 UTF-8 校验。
从 linkd-ws 的 /ws/echo 升级请求出发,逐条校验 Upgrade、Connection、Sec-WebSocket-Version 与 Sec-WebSocket-Key,手写 SHA-1 加 GUID 再 Base64 的 Accept 计算,讲清 101 响应写完后协议切换点在哪里,并给出 WebSocketHandshake 的完整实现。
没有基线,三个月后没人说得清系统是变快还是变慢。文章把可用性、p95 与单请求成本写成可比较的指标集,说明相对变化、零基线和发布闸门如何计算,并收口本卷交付的可运行产物,交代卷二为什么先从内容模型讲起,让每次发布都有可复核的对照,避免优化沦为口头争论。
完整握手之后,linkd 还要决定复用哪条会话、用 h2 还是 http/1.1、以及证书到底属于谁。本节讲 TLS 1.3 session ticket 的复用口径、ALPN 协商与主机名校验,给出 TlsSessionPolicy,并用 PKIXParameters 校验证书链。
阻塞式 SSLSocket 会把握手绑在一条线程上,linkd 的 EventLoop 不能这样等。本节把 SSLEngine 封装成 NonBlockingTlsHandshake:逐轮驱动 wrap/unwrap,处理 BUFFER_OVERFLOW、BUFFER_UNDERFLOW 与 NEED_TASK,最后用 TlsHandshakeHandler 接进 6.2 的事件循环。
账号包和 BFF 的单测都绿,真实注册登录却在字段名上断掉。文章说明端到端用例为什么要从用户旅程而不是接口清单来,如何在断言状态码之外验证业务结果,并给出用 httptest 真跑请求、失败后继续执行且能收敛 panic 的场景运行器,同时划清它不覆盖的边界。
从 linkd 明文代理必须加密的约束出发,拆解 TLS 1.3 的 1-RTT 握手、ClientHello/ServerHello 与证书链;用 keytool 生成带 SAN 的 PKCS12 自签证书,再用 TlsHandshakeInspector 打印协议、套件、证书链与 SAN,并给出证书不匹配的排查顺序。