本课程围绕同一个决定展开:系统出错之后,是否应当重试,以及如何重试。十二周对应十二种具体情况,从时断时续的 HTTP 调用,到同一笔款项被重复扣除的支付流程。课程要回答的问题是:重试在什么情况下确实有效,又在什么情况下会使问题进一步恶化。
系统出错之后,是否应当重试,以及如何重试?答案通常是肯定的,重试大多也确实成功了,这个动作因此往往在无人审视的情况下就成了习惯。本课程用十二周讨论它失效的场合:同一笔款项被扣除两次;刚刚开始恢复的下游服务被自己的客户端再次压垮;调用方早已不再等待,重试却仍在九十秒之后继续执行。
十二周,十二种情况
每一周都把同一个问题放进一种新的情况,而每一种情况都足够具体,可以直接复现:一次读取操作超时;同一笔款项被扣除两次;一万个客户端在同一秒内同时重连;凌晨三点,两个人分别发出了同一笔付款,而两次操作之间没有任何代码加以拦截。
每一周的结构相同,都由五个部分组成:具体情况;多数人首先想到的做法;这种做法在此处失效的原因;应当改用的方案;以及这个决定由谁负责,可能是客户端、调用库、平台、运维人员或产品团队,也可能无人负责。
每一种方案的适用边界都由它自身的工作原理决定:退避(backoff)会给本来即将成功的请求增加延迟;熔断(circuit breaker)在断开期间会拒绝那些原本可以成功的调用;超时截止(deadline)会丢弃即将完成的工作。到第十二周,你应当能够指出自己提出的任何一条重试策略的边界,并当面为它辩护。
适合什么样的学生
本课程面向三年级学生:写过需要经过网络通信的代码,并且已经遇到过它出乎意料的失败。你应当能够读懂一份陌生的代码库,并在其中做出少量修改。课程不要求分布式系统的理论基础,也不假定你有生产环境的运维经验。
本学期的大部分时间,你都在有意制造故障,并决定如何应对。学期结束时,你会得到三项成果:一份审计报告;一条重试策略,你需要当面为它辩护,而对方受命找出它的漏洞;以及一篇书面论证,说明在某些情况下根本不应重试。
