分布式计算的谬误是由L Peter Deutsch和Sun Microsystems公司的其他人所提出的一组断言,他们描述了不熟悉分布式应用程序的程序员总是会做出的一些错误的假设。
微服务的大规模普及迫使越来越多的工程师意识到这些错误的认识给他们的系统带来多么大的影响。
我们经常会看到一些人在讨论系统设计的时候,忽视或者淡化这8个谬误。
下面我来介绍一下这些谬误以及一些潜在的消减措施,希望大家能感兴趣。
网络是可靠的
为了构建一个可靠的系统,你必须理解并接受任何一种通信都可能会失败的事实。因此,我们需要为系统设计出一种方法来处理这种潜在的错误沟通。所以,最终需要用到重传,而且它可以有多种形式。
存储再转发(store and forward)就是这样一种模型。我们不直接将数据发送到下游服务器,而是将其存储在本地或其他地方,这也提供了能从灾难场景下恢复的保障。
有很多产品属于这种技术,如RabbitMQ,ActiveMQ以及来自云厂商的各种专有解决方案。
网络是零延迟的
图片的左边是在现代系统中直接访问内存的时间,右边是在世界各地往返所需的时间。
我喜欢把延迟看作是完成任何请求的严格开销。传递的消息可以很大,也可以很小,而延迟是不变的。与带宽不同,延迟通常与光速和通信距离(或物理路径)有关。所以两个系统之间的物理距离在这里起着重要的作用。
延迟是无处不在的。它发生在所有的通讯中。理想情况下,这种开销应该尽可能小。延迟的场景和从车上卸货非常相似,就是说,从厨房到车上的时间就是延迟。你是想一趟尽可能多地拿东西,还是想每次只拿一个东西,花几百次往返把车上的东西都卸下来?
带宽是无限的
假设持续无限制地增加信道上的数据大小,这显然是个很大的错误。这种情况只有在某种通讯彻底占满带宽与此同时无法扩容时才会出现。
我第一次遇到这个问题是我不小心将主页所需的有效负载增加了10倍时。这个特定的API是一个无缓存调用,每次页面加载3 MB,这也包括到数据库的往返。我们的系统很快就达到带宽限制,网站也就很快垮了。
现在你可能在想,你刚才告诉我,每次往返时尽可能多地带东西,以减少延迟方面的影响。这是事实,但它也有其局限性。这在很大程度上取决于你的系统设计和各自的优先级。就是说,能够意识到权衡至关重要。
网络是安全的
我们可以理所当然的信任我们所处的网络或为之构建的人,这可能是一个重大错误。如今,随着每天新闻中出现的社区漏洞赏金计划和重大漏洞攻击,这一点变得更加明显。在设计系统时就采取安全第一的方针会让你在未来获得回报。甚至花点时间评估当前系统的安全漏洞并很快产生一个简短的改进清单也是一个很好的开始。
网络拓扑永不改变
网络架构并不总是相同的。例如,如果基础设施的关键部分出现故障,流量能否继续流向适当的目的地?是否存在单点故障?
如今,随着Docker和Kubernetes的出现,更改网络拓扑的便利现在几乎让我们将其视为理所当然,这是非常危险的。像ZooKeeper和Consul这样的工具可以帮助解决服务发现方面的问题,并允许应用程序对布局和系统的变化做出反应。
构建能够对这些拓扑结构变化做出反应的系统可能很棘手,但是,最终会收获更有弹性的系统。
只有一个管理员
这句话花了我一段时间去理解,本质上是说一个人无法控制所有的事情。
随着系统数量的增长,它们会依赖于不在我们控制范围的一些其他的系统,要知道我们只拥有从我们自己的代码到运行它的服务器这一部分。同时,有一个清晰的方法来管理你的系统以及各自的配置是至关重要的。然而,随着各种系统数量的增加,管理和跟踪变得越来越困难。由此诞生的基础设施即代码(IaC)可以帮助将系统中的这些变化代码化。
同时,当出现问题时,也需要有一个很好的方法来诊断问题,监控和可观测性将是可以节省时间的关键工具。
最后,适当的解耦还可以帮助确保整个系统的弹性和在线时间。
传输成本是零
我们经常认为,用于在系统之间发送数据的资源只是很微小的业务成本。当事情很小的时候,这种间接消耗和成本可以忽略不计。不过,随着系统的增长,优化像JSON这样的消息格式的成本可能是值得投入的,虽然与gRPC或MessagePack相比可能有点沉重。认识到这些开销是必不可少的;然而,它也有它的权衡。过早去做可能会在短期内带来更多的麻烦。
网络是同构的
我曾经写过很多关于shims的文章,有关将一种格式的数据转换为另一种格式。我们希望一切都干净整洁,但现实世界远非如此。具有互操作性是必不可少的。
这种灵活性确保了我们的系统能在最新最热的框架里继续发挥作用,也能在不适合的环境中继续运行。(即使,互操作性有其局限性)
如果能知道“所有的系统都是不一样的,不会将你的解决方案耦合到一个系统上。”可以在未来节省你的很多时间和烦恼。
原文链接: Fallacies of Distributed Systems(翻译:伊海峰)