读书摘要 -- 第四章
高度交互的复杂性和紧耦合这两个“幽灵”,会将快速动态变化的裂纹转变为彻底的系统事故。
本章将讨论会破坏系统的反模式。这些是造成多种系统失效的常见原因。每一个反模式都会在系统中产生、加速或增加裂纹。应该避免这些不良的行为。
4.1 集成点
项目的上下文关系图无非是下面两种:蝴蝶图或蜘蛛图。
蝴蝶图:有一个中央系统,其中一侧有大量传入和连接的扇入数据,另一侧则有大量扇出数据;
蜘蛛图:图中有很多方块和相互的依赖关系。精心设计的是分层图;随意设计的则是MESH蜘蛛网;
这几种风格的共同特点是连接数超过服务数。蝴蝶图有2N个连接数,而蜘蛛网最多会有N*N个连接数,大部分系统的连接数则介于两者之间。
所有这些连接都是集成点,集成点是系统的头号杀手。每一个传入的连接都存在稳定性风险。每个套接字、进程、管道或RPC都可能停止响应。
例如:套接字
网络系统失效按速度分为快慢两种。快速的网络系统失效,会让调用代码立即出现异常。“拒绝连接”是非常快速的系统失效,只需要几毫秒的时间就能返回给调用方。缓慢的系统失效,比如一个被丢弃的ACK,会让线程在抛出异常之前被阻塞几分钟。被阻塞的线程无法处理其他事务,因此系统的容量就会降低。如果所有线程最终都被阻塞,那么实际上服务器就已被关闭了。显然,一个缓慢的响应比没有响应糟糕得多。
套接字连接是一个抽象概念,只有在计算机终端内存中,它们的存在才有意义。一旦创建套接字,TCP连接就可以保持好几天,而且无须任何一方发送数据包。只要两个终端计算机内存中都具有该套接字状态,那么“连接”就仍然有效。路由可以改变,物理链路可以被断开和重新连接,这些都没关系,只要终端的两台计算机认为“连接”确实存在,那么“连接”就会持续存在。
而网络中间的防火墙内的“已建立连接”表。该表是有时长限制的。因此,即使TCP本身允许无限时长的连接,该表也不允许。解决方案:周期的ping报。
要点:
小心必然会出现的恶魔。每个集成点最终都会以某种方式发生系统失效,所以需要为系统失效做好准备。
为各种形式的系统失效做好准备。集成点的系统失效有多种形式,如各种网络错误和语义错误。通过明确的协议获得良好的错误响应是不现实的,相反,某种协议违规、缓慢响应或停止响应等,这些情况更为常见。
知道何时应该揭开抽象。调试集成点的系统失效,通常需要透过抽象看问题。由于系统失效大多违反了高层协议,因此往往很难在应用层调试。此时可以求助于数据包嗅探器和其他网络诊断工具。
系统失效会迅速蔓延。若系统代码缺乏一定的防御性,那么远程系统失效会以层叠失效的方式迅速演变为系统问题。
采用一些模式来避免集成点问题。利用断路器、超时、中间件解耦和握手等模式进行防御性编程,以防止集成点出现问题。
4.2 同层连累反应
水平扩展通过增加服务器来增加容量;
垂直扩展,即构建越来越大的服务器,为主机添加CPU核数、内存和存储空间;
部分交互式工作负载通过垂直扩展实现,大多数交互式工作负载则依赖水平扩展;
尽管集群水平扩展不易遭遇单点系统失效,但它们可能会出现与负载相关的系统失效。
如果由于某些和负载相关的原因(例如内存泄漏或间歇性竞态条件),导致第一台服务器无法工作,那么幸存的节点会更容易发生系统失效。
如果应用程序存在缺陷(通常是资源泄漏或与负载相关的崩溃),就会发生同层连累反应。某一层上同层连累反应的系统失效容易导致其调用层上的层叠失效。
要点:
记住:一台服务器的停机会波及其余服务器。由于一台服务器停机,其他服务器必须负担其工作负载,这样就会发生同层连累反应。增加的负载使得剩余的服务器更易发生系统失效。同层连累反应会迅速让整层系统停机。依赖该层系统的其他层级必须做好防护措施,否则将会陷入层叠失效。
寻找资源泄漏。大多数情况下,如果应用程序发生内存泄漏,便会发生同层连累反应。当一台服务器耗尽内存并停机时,其他服务器不得不负担它的工作负载,但所增加的流量会加快内存泄漏。
寻找难以捕捉的时序缺陷。流量状况也可能引发难以捕捉的竞态条件。同样,如果一台服务器陷入死锁,其他服务器所增加的负载也极易使它们陷入死锁。
采用自动扩展。应该为云端的每个自动扩展组创建健康状况检查机制。自动扩展将关闭未通过健康状况检查的服务器实例,并启动新的实例。只要自动扩展机制的响应速度比同层连累反应的蔓延速度快,那么系统服务就依然可用。
利用“舱壁模式”进行保护。使用舱壁模式分隔服务器,可以防止同层连累反应毁掉整个系统服务。但当被分隔的服务器停机时,它们无法帮助其调用方确定哪个服务器分隔区停止了工作,不过这时调用方可以使用断路器模式。
4.3 层叠失效
当某一层系统崩溃导致其调用层也发生裂纹时,就发生了层叠失效。
层叠失效通常源于枯竭的资源池。资源池枯竭的原因往往是较低层级所发生的系统失效。没有设置超时时间的集成点,必定会导致层叠失效。
推测性重试也会让系统失效“跳过层级之间的间隙”而蔓延。服务提供方的响应变慢,调用方发出更多推测性重试请求,在服务提供方已经放慢响应时,占用调用方更多的线程。
要点:
阻止裂纹跨层蔓延。当裂纹从一个系统或层级跳到另一个系统或层级时,会发生层叠失效。这通常是因为集成点没有完善自我防护措施。较低层级中的同层连累反应也可能引发层叠失效。一个系统肯定需要调用其他系统,但当后者失效时,需要确保前者能够保持运转。
仔细检查资源池。层叠失效通常是由枯竭的资源池(例如连接池)所导致的。当任何资源调用都没有响应时,资源就会耗尽。此时获得连接的线程会永远阻塞,其他所有等待连接的线程也被阻塞。安全的资源池,总是会限制线程等待资源检出的时间。
用超时模式和断路器模式实现保护。层叠失效在其他系统已经出现故障之后发生。断路器模式通过避免向已经陷入困境的集成点发出调用请求,进而保护系统。使用超时模式,可以确保对有问题的集成点的调用能及时返回。
待补充