Agile Dynamic Provisioning of Multi-tier Internet Applications
ICAC 2008
本文是面对多层应用架构下(例子用的是e-commerce)进行的调度算法。用排队网络建模,每一个层的一个虚拟机为一个G/G/1系统,则每一层为G/G/n系统
背景
从原因上来说,是因为难以预测流量峰值的大小与到来时间,因此本文会选择使用一种动态资源分配与请求策略的组合来处理workload variation。
在Case-study中本文详细地描述了瓶颈层的概念。本文的调度原理与前文类似,即找到一个瓶颈层,从流量表现上来说,这个瓶颈层是流经流量中处理速度最慢的一层,而对这一层的伸缩会影响到整体的结果。关键是伸缩之后可能会造成瓶颈层的迁移,即有一个新的层,其处理能力无法跟上服务的进入速度。
本文中的应用期望一个性能阈值(performance bound),这一般通过SLA来规定。SLA通过对平均响应时间或一个合适的响应时间分布的规定来完成,比如说95%的请求应该满足端到端时延小于1s。
调度算法
调度算法的目标就是给每一层分配足够多的资源,使得它们能够在peak workload到来时不会违反SLA。
调度算法需要解决的有两个问题:How much to provision和when to provision.
对于第一个问题,本文建立了一个analytical model来进行,将服务的请求速率和单个请求的服务需求(service demand of an individual request),以此来计算每一层所需要的服务器的数量,并进行调度。
通过排队网络来建模,网络中的每一个队列代表多层应用中的一层。每一个队列会输出所有数据到下一个队列(the queues from a tier feed into the next tier)。
作者提到这样做可以克服独立进行每层调度与黑盒方法的好处:
- 因为每一层的容量是用排队模型分开计算的,每一层需求的流量是同时被分配的,因此每一个调度动作对最终结果的影响是实时的。
- 使用G/G/1系统来对服务器建模(The use of a G/G/1 building block for a server at each tier)允许我们通过将随机多层应用拆分成多个单元来建模来分拆复杂的任务。
对于第二个问题(When to provision),这取决于网络流量的波动。网络流量可能存在着长期的变动像是天级别的,或者季节性的变动,比如短期流量波动。作者用了两种方式来进行处理,使用了预测式调度来处理未来数小时的流量波动,并用响应式调度来纠正长期调度中存在的错误
How much to provision
这里是用排队论解决的
假设应用有k层,用T1,T2,…,Tk来代替。令期望的端到端时延为R,这个值是由应用的SLA决定。使用offline profiling来将这个整体的SLA进行分解,变为各个层自身的响应时间要求,用d1,d2,…,dk来表示。显然,有
∑
d
i
=
R
\sum d_i = R
∑di=R,假设流量进入速率为
l
a
m
b
d
a
lambda
lambda,由于容量一般是用最差的情况进行估计,我们假设此时的流量值为到来速率分布的一个高阶分位点(high percentile of the arrival rate distribution),从而估计出peak session rate。
给定peak session rate和per-tier response time,我们的目标是决定需要给每层分配多少资源才能够在平均响应时间限制内完成处理。
用G/G/1对一层的一个服务器进行建模。
- 第一步,决定每个服务器的容量,从而理清它所能处理的请求速率
- 知道每台服务器的容量后,第二步就是根据peak session rate来计算每一层所需要的实例数量。
对于G/G/1模型而言,请求的到达间隔是一个固定且已经知道的分布(interarrival times are derived from a fixed, known distribution)。每个请求会带给服务器一些工作,服务器处理这些工作的时间就称为请求的服务时间。在G/G/1系统中,请求的服务时间同样服从一个已经知道且固定的分布。请求按照FCFS的模式进行处理,队列长度可以无限,并且请求按顺序处理(不中断)
G/G/1系统可以根据到达间隔和服务时间分布来表达有用的系统指标,例如平均请求响应时间和吞吐量。而且因为G/G/1可以处理随机地到达请求和服务时间,它能够更泛用地对每一层的行为建模。
根据[Kleinrock 1976]的结果,G/G/1系统中存在
λ
i
≥
[
s
i
+
σ
a
2
+
σ
b
2
2
(
d
i
−
s
i
)
]
−
1
\lambda_i \ge [s_i+\frac{\sigma_a^2+\sigma_b^2}{2(d_i-s_i)}]^{-1}
λi≥[si+2(di−si)σa2+σb2]−1,其中
d
i
d_i
di是第i层的平均响应时间,
s
i
s_i
si是该层的平均服务时间,
λ
i
\lambda_i
λi是第i层的请求到达率,
σ
a
\sigma_a
σa和
σ
b
\sigma_b
σb是到来间隔时间(inter-arrival time)和服务时间(service time)的方差。
因为上述这些值都是可以在系统中在线测出来的,因此我们得到了一个关于请求率下界的估算值。给定average session think-time为Z,则session会以速率1/Z到来。使用Little’s law,可以知道对于
λ
\lambda
λ有请求到达速率(request arrival rate)
λ
τ
Z
\frac{\lambda_{\tau}}{Z}
Zλτ,其中
τ
\tau
τ为average session duration。(我个人认为这是对流量发送端的一个估计,因为前面贡献有提到workload是session-based的)
因此,一旦每一个服务器的流量下界被估算出来,第i层所需要的服务器的数量
η
i
\eta_i
ηi就可以用峰值请求率
λ
τ
Z
\frac{\lambda_{\tau}}{Z}
Zλτ计算,有
η
i
=
⌈
b
e
t
a
i
λ
τ
λ
i
Z
⌉
\eta_i=\lceil \frac{beta_i \lambda_{\tau}}{\lambda_i Z} \rceil
ηi=⌈λiZbetaiλτ⌉,其中
β
i
\beta_i
βi是一个与应用层相关的常数,加入的目的是为了量化所谓服务请求量的概念(service demand),因为同一个请求给不同应用层带来的压力是不一样的。
β
i
\beta_i
βi在单个流量会给第i层带来多倍的工作时是可能大于1的。
预测式调度部分
长期预测使用的是一个high percentile of the arrival rate distribution for an hour来估算一个小时可能出现的最大流量(peak demand),这样资源调度器就可以在最差的时候分配足够多的资源。估算的范围为过去数天内同一段时间,可以参考论文的插图4。而因为互联网应用中经常会出现的超载现象(overload),所需要的资源值很可能会比绝大多数情况需要的资源值还要多,此时就需要响应式方法进行调度。
可以使用过去数个点的误差来进行校正。设 λ p r e d ( t ) \lambda_{pred}(t) λpred(t)是对t时刻流量的预测值, λ o b s ( t ) \lambda_{obs}(t) λobs(t)为对t时刻流量的观测值,则有赋值语句 λ p r e d ( t ) = λ p r e d ( t ) + ∑ i = t − h t − 1 m a x ( 0 , λ o b s ( i ) − λ p r e d ( i ) ) h \lambda_{pred}(t)=\lambda_{pred}(t)+\sum_{i=t-h}^{t-1}\frac{max(0,\lambda_{obs}(i)-\lambda_{pred}(i))}{h} λpred(t)=λpred(t)+∑i=t−ht−1hmax(0,λobs(i)−λpred(i))。
响应式调度部分
前文所提到的预测式调度器可能会出现问题,特别是当今天的流量模式与昨天 的不同时。
调度器会时刻监视预测值与观测值,一旦误差大于一个阈值,就会执行响应式调度算法。当流量的上升速率或下降速率大于一定阈值的时候,会触发对应的阈值调度算法。
有两种方式来实现,第一种是使用之前提到的观测值代替预测值来继续进行调度。第二种是增加每一个接近耗尽的层的资源分配(比如10%)。这个新的资源分配需要确保不会发生瓶颈层转移的情况,因此下游的容量需要同比例的进行增加。
实验
排队论用在实验中效果似乎还可以。在测算上,使用了一些offline profilng的方法对每一层的参数进行了测度,并且会通过Online measurement的方式对每一层进行测试。
在调用的过程中,会使用预测式方法获得流量数,并根据输入的参数计算出所需要的实例数量。