1 背景
動態探測是周期性進行的,全局默認2分鐘,支持分頻道設置探測頻率(最低1s探測頻率),這就決定了選路也是周期性的,在兩次最優路徑更新的時間間隔內,如果回源鏈路發生波動,則只能依靠失敗后重試來解決,如果域名并發量很大,同一時間可能產生大量重試,這樣一方面客戶體驗不好,另一方面也加重了平臺的壓力。
2 方案
2.1 錯誤信息格式
路徑失敗主要包括兩種類型,包括父層返回錯誤和源站返回錯誤(建聯失敗或者返回4xx,5xx),可以通過內部頭,把產生錯誤的源地址、目的地址、目的端口,后端角色和時間戳返回給邊緣。
2.2 錯誤信息存儲
邊緣需要對錯誤信息進行存儲,并在選路時通過對選路信息和錯誤信息做對比,剔除掉已經置為不可用的路徑信息。
邊緣錯誤信息的存儲有兩種存儲方式:一是lua的共享字典 shared.dict 方式,二是lua的 lrucache 方式
lua共享字典 shared.shict 使用的是共享內存,每次操作都是全局鎖,如果高并發環境,不同 worker 之間容易引起競爭。所以單個 shared.dict 的體積不能過大。
lrucache 是 worker 內使用的,由于 Nginx 是單進程方式存在,所以永遠不會觸發鎖,效率上有優勢,并且沒有 shared.dict 的體積限制,內存上也更彈性,但不同 worker 之間數據不同享,同一緩存數據可能被冗余存儲。
比較了上述兩種錯誤信息的存儲方式,結合此功能的業務場景是應用在高并發時減少重試的次數,所以考慮使用 lrucache 更合適一些。這樣實現出來的效果就跟 nginx 原生的 max_fails 和 fail_timeout 的配置效果相似了(nginx 原生的max_fails 和 fail_timeout 是在單 worker 內進行統計并起作用的)。
2.3 錯誤路徑對比
(1)單位周期內發生M次錯誤
在單 worker 單位周期為 fail_timeout 設置的時間中,失敗達到 max_fails 次數,那么接將把節點標記為不可使用,對于已經標記為down的節點,在這個周期中不再使用包含此節點的路徑。
等待下一個周期(同樣為fail_timeout)再一次去請求,判斷能否連接能否成功,開啟下一次的循環。
源ip,目的ip,目的端口加入到匹配判斷當中,對于不符合的路徑信息剔除掉
(2)連續發生N次錯誤
在單 worker 單位周期為 fail_timeout 設置的時間中,連續失敗達到 conti_max_fails 次數,那么接將把節點標記為不可使用,對于已經標記為down的節點,在這個周期中不再使用包含此節點的路徑。等待下一個周期(同樣為fail_timeout)再一次去請求,判斷能否連接能否成功,開啟下一次的循環。
連續發生N次錯誤和單位周期內發生M次錯誤,兩者是或的關系,當滿足其中任何一個條件時,都把后端錯誤的節點置為down。
3 配置方式
源站的配置方式,可以針對不同源站設置不同的最大失敗次數,連續失敗次數和失敗的超時時間, 父層屬于內部節點沒必要做分開統計,做成一個統一的配置項即可。