超時是每個異步分布式系統(tǒng)的關鍵部分。他們通常配置為靜態(tài)并且很難得到。squbs提供 Timeout Policy設施,作為 squbs-pattern包的一部分來幫助動態(tài)確定正確的超時時間(通過提供一個策略而不是靜態(tài)設置)。這個通過策略來動態(tài)定義超時時間。請注意超時策略僅有助于輸出超時值,其本身不會導致超時發(fā)生。
依賴
在你的build.sbt或scala構(gòu)建文件中加入以下依賴:
"org.squbs" %% "squbs-pattern" % squbsVersion
快速例子
一個正常的await通過Scala的代碼展示如下:
Await.ready(future, timeout.duration)
在如下的閉包內(nèi),你可以改變這個代碼至一個 await塊
val policy = TimeoutPolicy(name = Some("mypolicy"), initial = 1 second)
val result = policy.execute(duration => {
Await.ready(future, duration)
})
Scala API
你可以通過傳遞如下規(guī)則創(chuàng)建TimeoutPolicy
-
對于固定的超時時間,你實際上不需要指定一個規(guī)則。 fixedRule是默認的
val policy = TimeoutPolicy(name = Some("MyFixedPolicy"), initial = 1 second, rule = fixedRule) -
超時時間基于響應時間的標準差(sigma)
val policy = TimeoutPolicy(name = Some("MySigmaPolicy"), initial = 1 second, rule = 3 sigma) -
超時時間基于響應時間的百分比
val policy = TimeoutPolicy(name = Some("MyPctPolicy"), initial = 1 second, rule = 95 percentile)
隨后你可以使用如下策略:
val result = policy.execute(duration => {
Await.ready(future, duration)
})
或者不使用閉包的另一個形式
val policy = TimeoutPolicy(name = Some("mypolicy"), initial = 1 second)
val tx = policy.transaction
Await.ready(future, tx.waitTime)
tx.end
tx.end是非常重要的,因為它為單一操作提供閉包(由超時策略監(jiān)視),當我們使用推薦的閉包版本的API時,某些事情將會自動監(jiān)控。它用于一個反饋回路來觀察實際的運行時間并將這個信息返回給heuristic。
Java API
在JAVA api中,我們通過一個策略builder創(chuàng)建超時策略,可以在以下的例子中看到:
-
固定的超時時間.
TimeoutPolicy fixedTimeoutPolicy = TimeoutPolicyBuilder .create(new FiniteDuration(INITIAL_TIMEOUT, MILLISECONDS), fromExecutorService(es)) .minSamples(1) .rule(TimeoutPolicyType.FIXED) .build(); -
超時時間基于響應時間的標準差(sigma)
TimeoutPolicy sigmaTimeoutPolicy = TimeoutPolicyBuilder .create(new FiniteDuration(INITIAL_TIMEOUT, MILLISECONDS), system.dispatcher()) .minSamples(1) .name("MySigmaPolicy") .rule(3.0, TimeoutPolicyType.SIGMA) .build(); -
超時時間基于響應時間的百分比
TimeoutPolicy percentileTimeoutPolicy = TimeoutPolicyBuilder .create(new FiniteDuration(INITIAL_TIMEOUT, MILLISECONDS), system.dispatcher()) .minSamples(1) .name("PERCENTILE") .rule(95, TimeoutPolicyType.PERCENTILE) .build();
然后,使用這個超時時間策略,只需要在你的閉包內(nèi)執(zhí)行調(diào)用,如下:
policy.execute((FiniteDuration t) -> {
return es.submit(timedCall).get(t.toMillis() + 20, MILLISECONDS);
});
或者,你可以使用非閉包調(diào)用:
TimeoutPolicy.TimeoutTransaction tx = policy.transaction();
try {
return timedFn.get(tx.waitTime());
} catch (Exception e) {
System.out.println(e);
} finally {
tx.end();
}
tx.end是重要的,因為它提供一個被超時策略監(jiān)視的單一操作,當使用推薦的閉包版本的API,這些事會被自動監(jiān)視。這是用來一個反饋回路來觀察真實的調(diào)用時間,并且把這些信息返回到heuristic。
TimeoutPolicy中的Heuristics
默認的超時策略是一個固定的超時,代碼你將始終獲得一個初始值在常規(guī)模式,一個調(diào)試值在調(diào)試環(huán)境。不過,擁有一個超時策略的前提是提供heuristics-based超時。下面是超時策略中使用的主要概念:
在統(tǒng)計學中, the [68–95–99.7 rule]規(guī)則,如眾所周知的 three-sigma rule 或 經(jīng)驗法則,將近所有的值接近三個平方差的正太分布中。
因此,如果你聲明你的超時策略如下:
val policy = TimeoutPolicy("mypolicy", initial = 1 second, rule = 2 sigma)
你將獲得一個超時值覆蓋大約 95%響應時間,放棄 5% 異常值通過使用2個sigma或95%的超時策略。通過調(diào)用policy.execute(tiemout=>T) 或 policy.transaction.waitTime生效。
回到統(tǒng)計
這里有三種方式來回顧統(tǒng)計學
- 在TimeoutPolicy創(chuàng)建時設置
startOverCount,當所有的事務計數(shù)到達startOverCount,這將自動開始重新統(tǒng)計 - 調(diào)用
policy.reset重設統(tǒng)計,你可以同樣在調(diào)用重設方法時提供一個新的initial和startOverCount。 - 調(diào)用
TimeoutPolicy.resetPolicy("yourName")在全局重設策略。
名稱
任何構(gòu)建超時策略提供一個可選的名稱。超時策略使用同一個名稱和其他策略實例分享他們的指標。 policy-by-name避免用戶創(chuàng)建一個策略實例,并通過共享相同策略傳遞出所有的使用。用戶可以干凈的復制策略在任何使用點,同時還能收集指標。另外,通過調(diào)用TimeoutPolicy.resetPolicy("name")使用策略中名稱可以集中清除指標。
警告:不要為完全不同性質(zhì)的策略使用同一個名稱,因為可能混淆你的統(tǒng)計。結(jié)果可能不可預測。
調(diào)試
用于調(diào)試目的,默認的超時策略為1000秒當你在調(diào)試模式中執(zhí)行時。你可以通過傳遞debug參數(shù)至TimeoutPolicy進行設置,如下:
val policy = TimeoutPolicy(name = Some("mypolicy"), initial = 1 second, debug = 10000 seconds)