Download PDF version of this article PDF

在 Google 重新发明后端子集化

设计一种连接搅动减少的算法,以替代确定性子集化

Peter Ward 和 Paul Wankadia,Kavita Guliani 参与

近年来,Google 的 Autopilot 系统在内部用于提高资源利用率而变得越来越流行。Autopilot 可以执行多项操作:它可以配置为执行水平扩展,从而调整服务运行的任务数量以满足需求;并且它可以配置为执行垂直扩展,从而调整每个任务配置的 CPU/内存资源。Autopilot 在预防中断方面也很有效:它可以比人工操作员更快地通过扩展服务来响应需求的增加。

随着 Autopilot 的使用变得广泛,服务所有者发现了一个有趣的问题:每当水平扩展的服务调整大小时,许多客户端连接(通常是长连接)会短暂断开并重新连接。这种连接搅动导致了二阶效应

• 飞行中请求的错误或延迟增加

• 连接握手导致的 CPU/内存使用率增加

• 新建立连接的 TCP 慢启动 导致的吞吐量降低

• 连接缓存的压力增加

这些影响的严重程度因服务而异,但在某些情况下,错误或延迟的增加使服务的服务级别目标面临风险,并阻碍了 Autopilot 的采用。调查确定,这种连接搅动是由后端子集化引起的。

后端子集化——一种在连接服务时减少连接数量的技术——对于降低成本非常有用,甚至对于在系统限制内运行可能是必要的。十多年来,Google 一直使用确定性子集化作为其默认的后端子集化算法,但尽管此算法平衡了每个后端任务的连接数,但确定性子集化具有很高的连接搅动水平。

我们在 Google 的目标是设计一种连接搅动减少的算法,以替代确定性子集化作为默认的后端子集化算法。这很宏伟,因为正如 Hyrum 法则 所述,“您的系统的所有可观察行为都将被某些人依赖。” 我们需要了解确定性子集化的所有行为,以避免回归。

 

Borg 中的后端子集化

Google 服务运行在 Borg 上,这是公司的集群管理软件。服务所有者配置在多个 Borg 单元 中运行的作业,以实现地域多样性。在一个单元内,一个作业由一个或多个任务组成,每个任务都在数据中心的某台机器上运行。任务从零开始连续编号。

后端子集化用于连接作业时——如果一个由 M 个任务组成的前端作业连接到一个由 N 个任务组成的后端作业,通常会有 M×N 个连接,当作业有数千个任务时,这可能会非常大。相反,M 个前端任务中的每一个都连接到 k 个后端任务,从而将连接数减少到 M×k。选择 k 的适当值留给读者,但它通常会远小于 MN

要使用后端子集化,服务必须是复制的:如果将相同的请求发送到不同的任务,它们应该执行等效的工作并返回等效的响应。

前端任务上的负载均衡策略用于将每个请求定向到特定的后端任务,目标是在后端任务之间实现均匀使用。每个后端任务都分配了相同的资源,因此为了避免过载,我们需要为负载最高的后端任务进行配置。

 

先前的方案

后端子集化算法选择的子集对生产有多种影响:连接平衡、子集多样性、连接搅动和子集分散。为了描述这些行为并解释新算法是如何开发的,让我们从一个简单的算法开始,并对其进行迭代改进。

 

随机子集化

最简单的算法之一是选择随机子集:每个前端任务都对后端任务列表(由任务编号 0 到 N-1 标识)进行洗牌,并选择前 k 个任务。

不幸的是,这与许多负载均衡策略的交互很差。假设您有一个 CPU 密集型服务,其中所有请求的成本都相同,并且每个前端任务都使用轮询负载均衡来均匀地平衡后端任务之间的请求。因此,每个后端任务上的负载将与其连接数直接相关。然而,如图 1 所示,来自随机子集化的连接分布远非均匀。

Reinventing Backend Subsetting at Google

轮询是一种简单的负载均衡策略,但并非唯一受连接分布影响的策略。鉴于 Google 服务的多样性及其不同的负载均衡需求,要求与连接无关的负载均衡策略是不切实际的。因此,子集化算法应力求平衡连接分布。

属性:连接平衡

目标是衡量子集化算法贡献的负载不平衡量,假设负载均衡策略受连接分布的影响。为此,假设每个前端任务在其子集中对每个后端任务产生相等的负载量;这在实践中很少完全正确,但足以用于这些目的。

利用率是衡量负载均衡的有用指标:将总使用量除以总容量即可得出正在使用的资源比例。这可以应用于连接分布:总使用量将是连接总数 (M×k),并且(由于我们为负载最高的后端任务进行配置)总容量将基于连接数最多的后端任务 (max(Cn)×N,其中 Cn 是连接到第 n 后端任务的连接数)。这提供了以下指标

 

Utilization = M*k / max(C_n0*N = M*k/N / max(C_n) = mean(C_n)/max(C_n)

 

然而,此指标未考虑连接的离散性。如果 M×k 不能被 N 整除,则理想的子集化算法必须为每个后端任务分配 [M*k/N][M*k/N] 个连接,因此 max(Cn) = [M*k/N]Utilization < 1。为了在这种情况下实现 Utilization = 1,必须调整指标以给出可实现的利用率

 

Utilization = [mean(C_n)]/max(C_n) = [M*k/N]/max(C_n)

 

使用此指标可以比较各种不同场景下子集化算法的连接平衡。请注意,以两种方式实现高利用率非常简单。首先,增加 k 自然会提高利用率,因为它降低了子集化对负载均衡的影响;将子集大小增加到 N 将完全禁用子集化。其次,随着前端任务与后端任务的比率增加,子集化算法对每个后端任务都有“更多选择”,因此即使随机选择,连接平衡也会自然而然地提高。图 2 显示了这一点,该图绘制了对于最多 256 个任务的作业(k = 20, 1 M 256, k N 256, M×k > N)利用率与前端任务与后端任务比率的关系;虽然不是一个现实的界限,但这足以证明该算法的行为。

Reinventing Backend Subsetting at Google

 

轮询子集化

可以通过前端任务的任务编号(0 到 M-1)引入前端任务之间的协调来改进随机子集化。轮询子集化将后端任务连续分配给第一个前端任务的子集,然后分配给第二个前端任务的子集,依此类推,如表 1 所示。每个前端任务 m 都可以通过从后端任务编号开始有效地生成其子集。

Reinventing Backend Subsetting at Google

应该很容易看出,这将尽可能均匀地平衡连接:一旦后端任务 n 被分配了一个连接,在所有其他后端任务都被分配连接之前,它将不会被分配另一个连接。尽管此算法具有良好的连接平衡,但其其他行为是不可取的。

属性:子集多样性

想象一下,如果表 1 中有更多前端任务会发生什么。前端任务 5 将被分配接下来的四个后端任务,即 {0, 1, 2, 3},但这与前端任务 0 的子集相同。对于 10 个后端任务和每个子集 4 个任务,可以分配给前端任务的可能子集有 10 4 = 210 个,但此算法只能分配五个不同的子集。在一般情况下,有 N / gcd(k, N) 个不同的子集。

为什么这很重要?想象一下,其中一个前端任务正在进行金丝雀发布更改,这会在其子集中的后端任务中触发不良行为(例如,高延迟或崩溃)。这将影响其他前端任务,但这些任务应该能够在其他后端任务上重试其请求。但是,如果其他前端任务与金丝雀前端任务具有完全相同的子集,则它们将面临相同的命运,并且将无法故障转移——或者将故障转移到相同的后端任务,从而使它们过载。

 

确定性子集化

可以通过引入随机性来增加子集多样性,但这必须以保持连接平衡的方式进行。这导致了一种解决方案,您可以在其中对所有后端任务进行洗牌,将它们分配给前几个前端,然后重复。

例如,对于表 1 中的场景,您可以将后端任务洗牌为 [9, 1, 3, 0, 8, 6, 5, 7, 2, 4],并将子集 {9, 1, 3, 0} 和 {8, 6, 5, 7} 分配给前两个前端任务。然而,这带来了一个问题,因为后端任务 2 和 4 未分配。如果这些延续到下一个前端任务的子集中,您可能会得到洗牌后的后端任务 [7, 2, 0, 8, 9, 1, 4, 5, 3, 6],但您不能将后端任务 2 分配给同一个前端任务。尝试跳过该后端(并使用后端任务 0)也是有问题的,因为它引入了一个依赖项,即前端任务需要计算每个先前的洗牌后端任务集,而不仅仅是从中分配任务的那个。

这可以通过省略剩余任务来解决,这只会引入少量的连接不平衡。在此示例中,前端任务 2 将使用子集 {7, 2, 0, 8}。

这是先前在 站点可靠性工程:Google 如何运行生产系统,第 20 章) 中描述的算法,但仍然可以进行一项改进,即平衡每个组中的剩余任务。实现此目的的最简单方法是在洗牌之前选择哪些任务将以轮询方式成为剩余任务。例如,第一组前端任务将选择 {0, 1} 作为剩余任务,然后对剩余任务进行洗牌以获得子集 {8, 3, 9, 2} 和 {4, 6, 5, 7},然后第二组前端任务将选择 {2, 3} 作为剩余任务,并对剩余任务进行洗牌以获得子集 {9, 7, 1, 6} 和 {0, 5, 4, 8}。这种额外的平衡确保所有后端任务都被均匀地排除在考虑范围之外,从而产生更好的分布。

该算法提供了良好的连接平衡和子集多样性,并且在生产环境中已经运行了十多年。在 Autopilot 使水平调整大小更加频繁之前,观察到的唯一主要问题可能归因于特别小的子集大小。

 

属性:连接搅动

考虑当后端任务从 10 个增加到 11 个时,前端任务的子集会发生什么情况,如图 3 所示,更改以红色突出显示。

Reinventing Backend Subsetting at Google

尽管这是一个很小的尺寸变化,但子集有很多变化——并且一个不幸的前端任务 (3) 被分配了一个完全不同的子集。当发生这种后端尺寸变化时,每个前端任务将断开与其子集中不再存在的后端的连接,并连接到新添加的后端。重新建立这些连接涉及多次网络往返,在此期间可能会发生以下情况

• 后端过载,因为前端任务将拥有的已建立后端任务较少,无法在其中平衡负载,并且连接分布将不平衡。

• 请求的错误或延迟增加,如果对于给定的前端任务没有可用的已建立后端任务。

这种连接搅动是由更改后端大小引起的,因此称为后端搅动。子集化算法也可能具有前端搅动(来自更改前端大小)和子集大小搅动(来自更改子集大小)。

理想情况下,后端搅动的量应与后端大小的变化成正比。例如,如果后端大小加倍,则每个前端任务的子集更改一半是合理的。这种后端搅动应均匀分布在子集之间:每个前端子集中一半的后端发生更改可能是可以接受的,但一半的前端的所有后端子集都发生更改则不可接受。

到目前为止,所考虑的算法都没有任何前端搅动——这在子集化算法中尤其不受欢迎。假设前端作业过载,并且添加了额外的任务以增加容量。前端搅动将导致现有前端任务重新连接到某些后端任务,从而在其他任务开始服务之前有效地降低容量。

如果子集大小是动态调整的,例如当它基于前端大小、后端大小和/或流量级别时,子集大小搅动非常重要。很容易看出,随机子集化的搅动最小:子集大小仅用于获取洗牌列表的前缀。另一方面,轮询和确定性子集化都以导致高子集大小搅动的方式依赖于子集大小。

属性:子集分散

要考虑的另一个有趣的交互是新软件版本如何部署到 Borg 作业。作业通常通过从任务 0 开始并限制正在进行的任务重启数量的滚动重启进行更新。除了重启缓慢的异常任务外,这意味着在更新期间,连续编号的任务块将不可用。

考虑对轮询子集化的影响:在表 1 中,第一个前端任务的子集 {0, 1, 2, 3} 是此过程将重启的前四个任务;如果正在进行的任务数量与子集大小相似,则在更新期间,大多数前端任务的子集将在某个时候完全不可用。随机子集化和确定性子集化的性能更好,因为任何单个子集都不太可能具有相对接近的任务编号,但是如果有足够数量的前端任务,则很可能有些会遇到此问题。

我们在实践中观察到了这个问题;可以通过减少允许的正在进行的任务数量(减慢更新速度)或增加子集大小(增加成本)来缓解此问题。理想情况下,子集化算法应分散每个子集中的后端任务编号,以便更新对前端任务产生一致且最小的影响。子集多样性和子集分散之间存在张力:对于前者,您需要许多不同的子集,但对于后者,您希望限制哪些子集是可接受的。

 

寻找新的算法

以下是后端子集化算法所需的属性

• 良好的连接平衡

• 高子集多样性

• 无前端搅动

• 低后端搅动

• 低子集大小搅动

• 良好的子集分散

除了前端搅动之外,这些属性中的任何一个都不需要最佳性能——性能只需要在各个方面都足够,以避免不良行为。

 

一致性子集化

起点是基于一致性哈希:为每个前端和每个后端分配单位圆上的随机位置;每个前端通过选择沿顺时针方向绕圆移动时找到的前 k 个后端来确定其子集。图 4a 显示了具有前端任务(蓝色方块)和后端任务(黄色圆圈)随机位置的一致性子集化。前端任务 0 顺时针移动并选择它看到的第一个两个后端,从而得到子集 {3, 2}。

Reinventing Backend Subsetting at Google

当在圆上添加或删除任务时,其他任务的位置不受影响。这大大减少了连接搅动:当添加后端任务时,每个前端任务的子集最多只能有一个更改。

不幸的是,此算法在连接平衡或子集多样性方面表现不佳。前端任务在选择其子集时没有协调,因此连接平衡不优于随机子集化。子集多样性受到影响,因为前端任务选择的第一个后端任务决定了子集的其余部分,因此,最多可能存在 N 个不同的子集。

 

Ringsteady 子集化

如何改进一致性子集化的连接平衡?后端任务的连接数与圆上后端任务之前的“自由空间”量成正比,因此连接平衡由后端任务在圆周围的间隔均匀程度决定。鉴于这种见解,您可以通过使用有利于均匀分布的位置序列来改进随机选择的位置:低差异序列

只有后端任务是连续编号的,这才有可能,因此低差异序列中的第 n 个元素可以与第 n 个后端任务关联。

我们在 Google 选择使用的序列是二进制 van der Corput 序列,它以 0 作为第零个元素开始(添加 0 作为第零个元素),为 0、½、¼、¾、⅛、⅝、⅜、⅞。这些分数确定每个节点在圆上的位置。如图 4b 所示,第一个任务放置在圆的顶部,第二个任务放置在半圆处,依此类推。

选择此序列的原因之一是它在计算元素位置方面的便利性。例如,要获得第五个元素的位置(使用 8 位字长),您反转 5 = 000001012 的位以获得 101000002 = 160;然后,将此视为定点数会得到位置 160/28 = ⅝。

到目前为止,本文仅讨论了后端任务,但前端任务的要求是相同的:如果后端任务远远多于前端任务,则应均匀间隔前端任务,以便其子集选择尽可能扩展而不会重叠。对前端和后端任务使用相同的序列会导致另一个方便的属性:当 M = N 时,每个前端任务都有一个不同的子集(从相同编号的后端任务开始),并实现理想的连接平衡。图 4b 显示了我们正在运行的算法,我们称之为 Ringsteady 子集化。

与子集分散留给机会的随机子集化和确定性子集化不同,Ringsteady 子集化保证了良好的子集分散:连续编号的后端任务在圆上彼此间隔很远,因此圆周围连续任务的子集将具有均匀分散的任务编号。

图 2c 表明,我们的算法在某些情况下比确定性子集化(参见图 2b)实现了更低的利用率,但明显优于随机子集化(参见图 2a)。

 

前端和后端缩放

不幸的是,Ringsteady 子集化的连接平衡存在缺陷,如图 2c 的右侧所示:前端任务多于后端任务,但利用率并未收敛到理想状态——这与图 2b 中的确定性子集化不同。低差异序列导致前端和后端任务的位置接近但不完全均匀间隔。仅在存在剩余任务的场景中才存在不平衡。

那么为什么不使它们都完全均匀间隔呢?这将需要稍微移动它们(比较图 4b 和 4c),这将引入少量的连接搅动,但应改善连接平衡。当应用于前端任务时,我们称之为前端缩放,当应用于后端任务时,我们称之为后端缩放

通过前端和后端缩放,我们的算法将始终实现理想的连接平衡。不幸的是,前端缩放使前端任务的位置依赖于前端大小,这会引入前端搅动,使其不适合此用例。

图 2d 显示了结果。与图 2c 相比,后端缩放实现了在 M > N 时改善连接平衡的目标,而在 M < N 时仅略有退化。虽然在某些情况下,这仍然比确定性子集化(参见图 2b)实现了更低的利用率,但它被认为是足够的。

 

Rocksteadier 子集化

带有后端缩放的 Ringsteady 几乎 具有我们所有期望的属性。它在子集多样性方面有所不足,因为它是一致性子集化的衍生产品,因此只有 N 个不同的子集是可能的。我们研究了 Rendezvous 哈希 作为增加子集多样性的替代方案,但尚不清楚如何将连接平衡提高到超出随机水平。相反,我们设计了一种结合了 Ringsteady 的算法,以增加子集多样性,而不会显着降低任何其他属性。

以前,我们通过洗牌每个后端任务来实现子集多样性,但这使得顺序依赖于后端大小,因此会导致后端搅动。相反,通常前端大小 M 远小于可能的子集数量。因此,不必洗牌每个后端(即,产生所有可能的排列)即可实现足够的子集多样性。

解决此问题的方法是形成 L 个后端任务的组(称为批次),并对每个批次进行洗牌。参数 L 必须是一个常数:使其依赖于前端大小、后端大小或子集大小会引入连接搅动。最后一个后端批次必须由 L 个任务组成,因此如果后端大小不是 L 的倍数,则会添加填充任务;这些不是真正的后端任务,并且在选择子集时将被跳过。还形成了 L 个前端任务的组。在每个前端批次中,我们尝试在前端任务之间均匀分布后端任务——类似于轮询或确定性子集化。

表 2 显示了此过程的第一步:使用 L = 10 将前端和后端任务分组到批次中。出于说明目的,这显示了第二个前端批次(任务 10-19)。由于后端大小不是 L 的倍数,因此填充任务 55-59(以灰色文本指示)被添加到最后一个后端批次。

Reinventing Backend Subsetting at Google

表 3 显示了此过程的第二步:洗牌每个后端批次。该表显示了在从左到右洗牌每个后端批次后,前端任务 13(红色)和 19(蓝色)的潜在子集分配。

Reinventing Backend Subsetting at Google

此过程的要求是

• 前端批次内的每个前端任务都需要对后端任务使用相同的洗牌顺序。

• 后端批次在不同的前端批次中应以不同的方式洗牌。

• 添加新的后端批次不得影响先前洗牌的后端批次的顺序。

可以通过使用前端批次号(对于前端任务 m,这是 [m/L] )作为 PRNG(伪随机数生成器)的种子,然后使用此 PRNG 按顺序洗牌每个后端批次来实现这些要求。

我们仍然需要想出一种将子集分配给前端任务的方法。让我们首先考虑一些简单但效果不佳的方法。第 i 前端任务可以查看第 i 行,并从每个批次中获取后端任务。如果我们到达行中的最后一个后端批次,我们将回绕以从表中的下一行读取。例如,在表 3 中,前端任务 13 将选择一个以 {4, 14, 21, 39, 46, 52, 7, 18, ...} 开头的子集。我们还跳过填充后端任务,最后一个后端批次回绕到第一个,因此前端任务 19 将选择一个以 {6, 10, 20, 30, 44, 8, 13, 22, ...} 开头的子集。

这种分配子集的方法在两个方面造成了连接不平衡:它未能跨后端批次(即,跨列)进行平衡;并且它未能跨后端批次(即,跨行)进行平衡。

为了跨后端批次进行平衡,请考虑表 3 中描述的场景,其中子集大小较小,例如 k = 3。前端任务 10-19 的子集将仅从前三列中选择后端任务:后端任务 0-29 每个都将有一个连接。请注意,这对于每个前端批次都是如此:虽然每个后端批次内的顺序因前端批次而异,但第一个后端批次始终包含任务 0-9,第二个批次包含 10-19,依此类推。

需要不同的前端批次才能以均匀分布且不引入搅动的方式访问不同的后端批次。可以通过将 Rocksteadier 算法中的前端/后端批次映射到 Ringsteady 中的前端/后端任务来解决此问题的这一部分。例如,在图 4c 中,前端任务 1 以 [1, 5, 3, 0, 4, 2] 的顺序查看后端任务;在表 4 中,列被重新排序,以便前端批次 1 中的所有任务都以相同的顺序从批次中选择后端任务。Rocksteadier 前端批次 1 使用与 Ringsteady 前端任务 1 相对应的顺序。

Reinventing Backend Subsetting at Google

当最后一个前端批次不完整时,会发生剩余的(并且相对较小的)平衡问题。例如,考虑表 4,如果仅存在前端任务 10、11 和 12,并且子集大小相对较大:因为它们的子集都从连续的行开始,所以它们之间会存在一些重叠,从而导致与某些后端任务的多个连接(例如,第三行上的任务 5、45、26,... 可能来自所有三个前端任务的连接),而较低行中的后端任务将没有连接。可以通过使用从前端任务到起始行的不同映射来减少这种不平衡:这只是大小为 L 的固定排列;我们任意选择使用 Ringsteady 顺序 [0, 8, 2, 4, 6, 1, 9, 5, 3, 7] 来跨行分散连续的前端任务。表 5 显示了最终的子集分配过程,对前端任务进行排列,并显示了前端任务 10(红色)、11(蓝色)和 12(绿色)的子集分配 (k = 10)。

Reinventing Backend Subsetting at Google

较大的 L 值会增加子集多样性,但会以连接不平衡为代价。幸运的是,相对较小的值(例如 10)能够为典型的 Borg 作业提供足够的子集多样性,而不会增加大量的连接不平衡。

 

测试和部署

在开发期间,我们使用了从生产环境中收集的前端、后端和子集大小的测试套件,以比较不同算法的属性。这表明 Rocksteadier 子集化减少了连接搅动,但我们想验证它是否也减少了我们看到的二阶效应。

为此,我们在非生产环境中的一项服务上运行了一个实验。两个前端作业(一个使用确定性子集化,另一个使用 Rocksteadier 子集化)持续向后端作业发送请求,后端作业在实验期间以增量方式调整大小(具有不同的步长)。图 5 显示了结果:每次后端大小发生变化时,使用确定性子集化的前端作业都会看到错误峰值,而使用 Rocksteadier 子集化的前端作业则基本上不受影响。

Reinventing Backend Subsetting at Google

我们在受后端搅动影响最严重的服务中试用了 Rocksteadier 子集化。对于一项特定的服务,这消除了采用 Autopilot 的障碍,从而节省了大量资源并降低了生产事件的频率。

在运行几个月没有发生任何重大事件后,Rocksteadier 子集化作为新的默认后端子集化算法在整个集群中推广。这次推广很成功,并且在很大程度上没有引起服务所有者的注意。

 

结论

Google 寻求一种算法,该算法能够提供良好的连接平衡、高子集多样性、无前端搅动、低后端搅动、低子集大小搅动和良好的子集分散。大多数子集化算法都能够提供其中几个属性,但据我们所知,Rocksteadier 子集化在提供所有这些属性方面是新颖的。

最后,虽然这些权衡适用于 Google 的生产环境,但它们在其他环境中可能并不理想。无论如何,对这些属性的讨论和对设计过程的解释在其他上下文中可能很有用。

 

Peter Ward 是 Google 悉尼站点可靠性工程 (SRE) 部门的高级软件工程师。他目前在 Google 地图工作,但之前曾在包括 Autopilot、Chrome 和 Google 相册在内的各种产品上工作过。他很容易被技术难题吸引。Peter 的 Twitter 是 @flowblok

Paul Wankadia 是 Google 悉尼站点的高级软件工程师。他在站点可靠性工程 (SRE) 部门工作了五千天后退休,现在致力于提高软件效率。您可能还记得他开发的正则表达式库,例如 redgrep 和 RE2。他很享受用第三人称谈论自己。Paul 的 Twitter 是 @junyer

Kavita Guliani 是 Google 站点可靠性工程 (SRE) 部门的技术文档编写员。作为 SRE 技术文档编写员,她与工程师、用户体验 (UX) 人员、项目经理和客户合作,创建有助于产品或服务采用的文档。除了 SRE 之外,Kavita 还支持云项目。在空闲时间,她喜欢在大自然中度过时光、冥想和旅行。

版权 © 2022 年归所有者/作者所有。出版权已许可给 。

acmqueue

最初发表于 Queue 第 20 卷,第 5 期
数字图书馆 中评论本文





更多相关文章

David Collier-Brown - 你对应用程序性能一窍不通
当您遇到性能或容量规划问题时,无需进行全面的基准测试。一个简单的测量将提供您系统的瓶颈点:这个示例程序在每个 CPU 每秒处理八个请求后会明显变慢。这通常足以告诉您最重要的事情:您是否会失败。


Noor Mubeen - 工作负载频率缩放定律 - 推导与验证
本文介绍了与每个 DVFS 子系统级别的工作负载利用率缩放相关的方程。建立了频率、利用率和缩放因子(其本身随频率变化)之间的关系。这些方程的验证结果证明是棘手的,因为工作负载固有的利用率在治理样本的粒度上也以看似不明确的方式变化。因此,应用了一种称为直方图脊线跟踪的新方法。当将 DVFS 视为构建块时,量化缩放影响至关重要。典型的应用包括 DVFS 调控器和/或其他影响系统利用率、功耗和性能的层。


Theo Schlossnagle - DevOps 世界中的监控
监控似乎令人感到有些不知所措。最重要的是要记住,完美不应成为追求更好的绊脚石。DevOps 能够在组织内部实现高度迭代的改进。如果你没有任何监控,那就弄点什么;弄点任何东西都行。有总比没有好,而且如果你已经拥抱了 DevOps,那么你已经同意随着时间的推移不断改进它。


Ulan Degenbaev, Jochen Eisinger, Manfred Ernst, Ross McIlroy, Hannes Payer - 空闲时间垃圾回收调度
谷歌的 Chrome 浏览器力求提供流畅的用户体验。动画会以 60 FPS(帧每秒)的帧率更新屏幕,这使得 Chrome 大约有 16.6 毫秒的时间来执行更新。在这 16.6 毫秒内,所有输入事件都必须被处理,所有动画都必须被执行,最后帧必须被渲染。错过截止时间将导致丢帧。这些对于用户是可见的,并且会降低用户体验。这种零星的动画瑕疵在这里被称为 jank(卡顿)。本文介绍了一种在 JavaScript 引擎 V8(Chrome 使用的引擎)中实现的方法,用于在 Chrome 空闲时调度垃圾回收暂停。





© 保留所有权利。

© . All rights reserved.