前言:让服务在故障中仍能交代清楚
写出一个返回 JSON 的 Go 接口并不难。难的是上线之后回答这些问题:用户已经离开,为什么数据库查询还在执行?队列长度看上去很短,为什么 goroutine 数一直增长?服务收到了退出信号,为什么仍有任务写了一半?上游没有报错,为什么新的请求迟迟拿不到连接?这些问题属于服务的运行边界,不能靠增加几个 go 关键字解决。
本书面向已经能够实现 HTTP 接口、读懂结构体与接口的后端开发者。读者可以带着 Java、网关、消息系统或 Agent 基础设施的经验进入,但不要把 Go 的 goroutine 直接换算成 Java 线程池,也不要把 context 当成可以自动终止任务的控制器。我们从每个资源由谁创建、谁继续使用、谁有权关闭开始,逐步建立可以验证的服务行为。
作者 Aias00 是 Apache ShenYu PMC 成员,长期关注 Java、Go 与 Agent 基础设施。本书采用这类工程工作的一个朴素判断:当一个结论不能落到代码、约束和故障验收上时,它暂时只能算设计意图。书中没有借用未公开生产系统为实验背书,也没有把本机的一次基准测试写成生产容量承诺。
贯穿全书的工程位于实验包根目录。它只有标准库依赖,包含一个 HTTP 服务、容量固定的后台工作池、复用连接的外呼器,以及可在真实 TCP 和子进程上执行的测试。请求可以等待工作,也可以提交服务负责的后台任务。我们故意制造队列饱和、取消、未读完的响应体、慢读取和退出超时,然后检查最终资源状态。
本地实验环境是 go version go1.24.3 darwin/arm64。持续集成固定使用 Go 1.24.3,在 Linux 上重新编译并执行 race 和行为测试。操作系统调度、TCP 缓冲区与计时结果会变化,因此验收尽量围绕“任务是否退出”“在途数量是否受限”“关闭后是否拒绝接纳”展开。程序输出和实际测试清单位于附录及实验包的 EXPERIMENTS.md;每一个输出都有对应命令与适用范围。
阅读顺序也反映了问题的依赖。先理解取消与资源所有权,再讨论 channel、锁和有界接纳;然后进入 HTTP 输入、输出和连接;最后研究退出协议、数据竞争与诊断。你可以跳到正在排查的问题,但仍建议先读第一、三和十一章,它们说明整个工程的责任边界。
每章练习都要求产生可观察结果,而不是只添加一段代码。比如“支持取消”必须能证明阻塞的工作确实退出;“优雅退出”必须能证明接纳关闭、已接纳任务的边界和进程状态;“修复连接泄漏”必须让受限制的下一次请求恢复。练习不要求购买云服务,不需要数据库容器,不依赖语言模型接口。
EPUB、网页和完整 Markdown 来自同一份有序书稿;完整代码附录在构建时直接读取实验工程。下载实验 ZIP 后,解压到一个空目录,先执行 go version,再执行 go test -race ./...。代码与文字的可追溯关系是本书的一部分:如果你改了实现,应当重新运行实验,修改对应解释,然后一起发布。
本书希望帮助你形成一种更可靠的工作方式:先写明边界,再在边界上制造失败,最后依据证据缩小结论。一个服务不需要永远不失败,但需要能够在失败时及时停止无用工作、保护有限资源,并留下足够的信息让下一位工程师看懂发生了什么。