系统的鲁棒性和弹性
如果更习惯于单体系统,则分布式系统可能会出现很多我们不熟悉的故障模式。网络可能会丢包,网络调用可能会超时,机器可能会死机或停止响应。在简单的分布式系统(例如传统的单体应用程序)中,这些情况可能很少见。但是,随着服务数量的增加,这些罕见的情况会变得越来越普遍。
该问题如何表现出来
不幸的是,这些问题最有可能出现在生产环境。在传统的开发和测试周期中,我们仅在短时间内重新创建了类似线上的环境。这些罕见的事件不太可能在线下出现,并且他们通常在发生之后就会消失。
该问题何时发生
诚实讲——如果我能提前告诉大家,你们的系统何时会受到不稳定的困扰,我就不会写这本书了。因为,我可能会将写书的时间用于在海滩的某个地方喝鸡尾酒。我只能说,随着服务数量的增加和服务调用的数量的增加,会越来越容易受到弹性问题的困扰。服务之间的交互越多,遭受到连锁故障和“back pressure”之类的事情的可能性就越大。
back pressure
back pressure是一种现象:在数据流从上游生产者向下游消费者传输的过程中,上游生产速度大于下游消费速度时,导致下游的Buffer溢出,这种现象就叫做back pressure。
back pressure的概念源自工程概念中的back pressure:在管道运输中,气流或液流由于管道突然变细、急弯等原因导致由某处出现了下游向上游的逆向压力,这种情况称作back pressure
。这是一个很直观的词:向后的、往回的压力。可是,国内的热力工程界对这个词的正式翻译是背压
,把back
翻译成了背
,着实有点让人迷惑。
因此,这里就不翻译back pressure一词了。
back pressure指的是在Buffer有上限的系统中,Buffer溢出的现象,它的应对措施只有一个:丢弃新事件。
- 生产速度大于消费速度,所以需要Buffer;
- 外部条件有限制,所以Buffer需要有上限;
- Buffer达到上限这个现象,有一个简化的等价词叫做back pressure;
- back pressure的出现其实是一种危险边界,唯一的选择是丢弃新事件;
如上,就是back pressure的本质,back pressure的出现其实是一种危险边界,唯一的选择是丢弃新事件。
该问题的解决方案
一个好的出发点是:问自己一些关于我们所有的服务调用的相关问题。
- 我知道调用失败的方式吗?
- 如果调用确实失败了,我知道该怎么办吗?
回答完这些问题后,就可以开始寻找各种解决方案了。服务彼此之间的隔离会有所帮助,或许包括引入异步通信以避免时间耦合(我们在第1章中谈到了这一主题)。使用合理的超时可以避免较慢的下游服务的资源冲突。同时,结合断路器之类的模式,可以启动快速失败,以避免back pressure问题。
运行多个服务副本可以帮助解决实例宕机的问题,可以使用平台实现DS管理,以确保服务在crash时可以重新启动。
重申第二章中的观点,弹性不仅仅是实现某些模式。弹性一套完整的工作方式——建立一个组织,该组织不仅要准备处理不可避免的问题,而且还要根据需要改进工作方法。可以将这种想法付诸实践的一种具体方法是:在出现线上问题时记录下来,并记录所学到的知识。我常常发现,组织一旦解决了最初的问题,就快速的前进了——仅仅是几个月之后,同样的问题就又出现了。
之前,我发现某个团队在ES6的兼容性问题上连续出现了多次线上问题。
老实说,在这里,我只是做了一点肤浅的研究。对于这些想法的更详细的研究,我建议阅读《Building Microservices》一书的第11章;或者看看Michael Nygard的《Release It!》,该书由Pragmatic Bookshelf在2018年发行。