天天看點

高危接口通路熔斷機制背景介紹設計方案總結

背景介紹

阿裡雲ECS執行個體的停機、重新開機、釋放等操作都屬于高風險動作,直接影響到ECS執行個體本身所承載的計算任務和業務。特别是大批量操作時,更加需要明确停機或釋放機器的準确性,一旦批量誤操作甚至導緻整個網站業務線的崩潰。為了防止造成這種巨大損失的局面,針對高風險操作接口提供一種限流熔斷機制,批量操作時可以有效的制止過度的錯誤停機、重新開機及釋放。

設計方案

ECS執行個體的停機、重新開機及釋放屬于高風險操作,未來随着接口應用的深入,其他接口也可能處于高風險狀态,例如安全組ACL授權操作等。為了能夠讓所有高風險操作都可以使用該熔斷機制,是以設計的首要原則是高風險接口與熔斷機制本身解耦。

需要統計添加熔斷機制接口機關時間内的調用頻次,設定合理的熔斷上限,在不影響日常合理調用的前提下,還需要考慮正常且正确的批量調用,需要提供臨時白名單政策。白名單内的使用者不受熔斷機制限制,需要認真确認執行個體資訊,以免造成大量錯誤停機、重新開機或釋放的情況。

針對接口熔斷類功能需要添加開關進行控制,并逐個地域進行開放,便于觀察各接口的熔斷情況和調整接口的熔斷上限,通關開關的控制可以應對熔斷機制帶來的突發狀況。比如熔斷機制不合理,導緻接口調用收到嚴重限制,沒有接口隻能通過復原代碼的方式進行恢複,時效性低并且存在風險。

設計方案的基本原則:

  • 需要熔斷的接口與限流熔斷機制之間解耦合;
  • 提供白名單政策,應對超過熔斷上限的合理調用;
  • 提供開關政策統一控制各接口的熔斷機制;

注解和切面(Annotation+Spect)的方式實作熔斷

在不對需要熔斷接口的代碼做任何修改的前提下,隻需要在接口的方法上添加熔斷注解就可以實作熔斷限流的作用,熔斷功能子產品獨立,接口本身的邏輯和代碼獨立,通過添加注解的方式實作高内聚低耦合。

首先,定義一個熔斷的注解AccessLimit:

/**
 * 高危接口熔斷機制
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {}           

通過注解@AccessLimit擷取方法參數中調用者的資訊,實作一個以@AccessLimit為入口的切面,該切面實作了熔斷機制的全部邏輯。以調用者的資訊作為Key,利用Tair天生Key/Value存儲結構的統計該調用者在目前小時内的調用次數,Tair中提供累加的incr方法:

/**
 * @param namespace
 * @param key
 * @param value
 * @param defaultValue
 * @param expireTime
 * @return
 */
Result<Integer> incr(int namespace, Serializable key, int value, int defaultValue, int expireTime);           

Tair統計每個調用者Key值過期之前的調用次數,達到熔斷上限時抛出異常資訊,提示達到風控上線的資訊,并不再進一步調用該方法,達到熔斷限流的效果。

Tair中incr方法的過期時間

針對同一個調用者,在過期之前的機關時間内,同一方法調用一次通路次數累加一次。incr方法需要注意的是過期時間參數每次調用都會更新的,這樣就會存在問題:

1、如果已經達到通路上線,并可以繼續執行incr,那麼從最後一次通路開始重新記錄過期時間。如果在釋放Key之前繼續通路,将導緻該接口針對該使用者無法通路。

2、如果已經達到通路上線,并阻止繼續執行incr,那麼從最後一次通路開始重新記錄過期時間,直到該Key過期才能重新繼續通路。

以上兩種情況統計同一使用者對同一接口的通路次數均不準确。解決該問題的方式需要将調用者的Key與目前時間相結合,熔斷機制限制方式為每小時N次,任意小時内任何時間取整到小時都是同一個值,将該值與調用者資訊拼接作為CacheKey,一天内同一調用者在任意小時内的CacheKey都不一樣,這樣即使incr方法中的過期時間每次更新,仍然可以準确統計每小時内的通路上線次數。不會出現以上兩種請款帶來的時間延遲或持續無法通路的情況。關于Key值處理:

/**
 * 擷取 cache key
 * @param key
 * @return
 */
private String getCacheKey(String key) {
    Calendar calendar = Calendar.getInstance();
    String hour = String.valueOf(calendar.get(Calendar.HOUR_OF_DAY));
    StringBuilder cacheKey = new StringBuilder(key);
    cacheKey.append("#");
    cacheKey.append(hour)
    return cacheKey.toString();
}           

總結

關于接口限流的熔斷機制,利用注解和切面的方式進行實作,不僅設計邏輯明确、容易了解,而且很好的展現了高内聚低耦合的設計思想。結合白名單及開關的政策,使得熔斷機制的使用更加廣泛、安全、靈活。