没有解决方案的问题有什么好的?在《负载增长时悄然袭来的42个怪兽问题》一文中,我们讨论了一些问题;在这篇文 章(早些时候有过一篇文章,我会重新组织一下内容)里,我们将讨论我所谓的聚合策略(aggregation strategies)。
请牢记,这些都是下层架构方面的一些建议,比如如何组织代码组件的结构,它们该如何交互。本文不会讨论大规 模集群,但是会讨论你的应用程序在内部——在服务接口之下的深层——可能是什么样的。这个世界上除了事件架构之外, 还有很多东西。
聚合,简单说来就是不用愚蠢的队列,我们的队列会很聪明。我们打心底里把队列视为工作内容的 容器,该容器最终会呈现出整个系统是如何工作的。作为工作内容的容器,我们熟知队列里会有什么请求和数据,我们可以 把这种情报作为我们巨大的优势。
合理排序工作内容
此处的关键理念是一个基本上必须要牢记于心的设计方 法,有程序员将其视为一等概念——在工作创建时的方方面面里什么该做,为什么要做它,该什么时候做这三个问题的优先 级。
避免级联故障
为什么合理排序工作内容如此重要?我们要避免的最不靠谱的情况就是级联故障。天真的 系统没有合理排序的理念,在故障发生时,会让无用的控制层或数据层流量挤占必要的控制流量。
如果你需要向交 换机发送一个请求,对路由进行重新编程以对流量做故障转移,如果此时低优先级的工作项造成了线端拥塞(head-of-line blocking),那么在不关闭整个系统的情况下,你将永远都无法获得系统的控制权。那些不了解情况的啰嗦的程序会不断发 出低优先级的控制和数据流量,让系统一直处于繁忙状态,而做的事情却一点用都没有。这就好像代码中的垃圾食品。
一个了解优先级的系统会试着在确保高优先级的工作按时完成的同时避免无用的工作。用于控制的网络和数据网络 是各自独立的,因此控制消息能自由通行。你会有智能重试策略,无用工作不会占据队列,作废的消息会从队列中剔除。在 网络各处都要考虑缓存,确保不会看到老的版本。当最新的消息入主之时,可以用控制消息来暂停当前的工作,这样才能处 理更高优先级的工作,它们的消息会立即发送出去,而非进入等待。为了让系统更强健,有很多非常酷的事情可做。
处理无限的工作负荷
排定优先级是处理无限工作负荷的关键思想,在《负载增长时悄然袭来的42个怪兽问题 》里就讨论过这一点。传统观念里我们认为100% CPU使用率是一个不好的信号。作为补偿,我们制造了复杂的基础设施对工 作进行负载均衡、状态复制、构建服务器集群。CPU是不会疲劳的,所以我们可以将其榨干。当我们讨论排定优先级时,我 们也在讨论系统在全负荷下如何做出漂亮的、可预见的反应。如果我们进行了合理的条件设置,这些都不成问题。只有对于 那些架构天真的软件而言,这才会成为问题。
有意识的控制
合理排序的工作内容中说到开发者应该对以下内 容进行有意识的控制:
什么工作该做,什么工作该扔
处理工作的顺序
处理工作的任务优先级
给予工作的资源量:
CPU时间
内存
队列空间
磁盘
网络
锁
你可能会注意到典型的编程环境里,你对这些内容的控制力都不强。必须改变这一点。
找出优先级
合理 排序工作内容也是很多其他领域的可扩展性解决方案里的常见做法。排定优先级需要对系统正在发生什么,以及你希望系统 里正在发生什么有一个深刻的理解。优先级取决于:
客户
请求类型
尝试提供公平的服务
请求数
已使用的资源量
需要的资源量
合约中的截止日期
SLA
除了避免级联故障之外,将拥抱优先级作为基本概念的另一个关键原因是为了保证SLA。
你有一个高 优先级的客户,他为了获得优于普通客户的服务而付费。为了实现他们的SLA,系统中的所有组件都必须习惯于理解优先级 ,同时还不能让其他客户处于饥饿状态,为他们提供周到的服务。
这和OS任务调度以及网络流量调度有很多共同之 处。其中的思想是一样的,但开发者需要在系统里运用这些思想。
合并聚合
合并聚合就是把单独的数据和/ 或命令合并到一起。其理念就是按固定限定成比例地使用资源。
例如,假设一个对象有如下命令序列:
新建
更新
更新