openresty健康檢查lua-resty-upstream-healthcheck分析和拓展

    網關作爲流量的入口,承上啓下的中樞,對上游節點的健康狀態監測是比不可少的;若上游節點異常,網關需要動態摘除此節點,避免流量轉到異常節點去,保證服務的穩定。

    本文主要分析lua-resty-upstream-healthcheck源碼,以及在實際工作的優化應用。

一、背景介紹

     目前本人負責的網關是基於orange二次開發的,health_check健康檢查功能是基於插件的形式嵌套在網關中。在lua-resty-upstream-healthcheck的基礎上根據業務增加了tcp/http檢測、異常節點自動摘除、告警等功能。

二、health_check分析

2.1 分析之前

     health_check運行在init_worker階段,也是一個定時任務。在實際項目中,我們用一個nginx work進程來進行健康檢查,比如ngx.worker.id() == 0。這種處理方式的好處就是,就算異常情況下當前處理健康檢查的nginx進程因爲某些原因crash掉了,新fork出來的nginx worker也會集成這個worker id的,只要nginx master進程不掛掉,健康檢查都會正常運行。並且最大限度的減少健康檢查對網關整體性能的影響,讓網關注重做該做的事情。

2.2 代碼分析

     基本流程圖:

     spawn_checker:在health_check模塊中,spawn_checker供外部調用,也是代碼的入口。這裏面主要做了兩件事情:初始化健康檢查參數和開啓定時任務進行check。結合業務需求,增加告警通知配置。同時健康檢查摘除的節點是放在內存裏面的,當nginx reload時,需要重新檢測,重新更新配置,故清空down掉節點信息也放在此函數進行處理。

     check :在函數check中,使用pcall進一步處理真正進行健康檢查的函數do_check,這樣錯誤代碼打印錯誤後可以繼續執行,避免檢查檢查停止。

     do_check: 在do_check中,我們將自己的一些業務邏輯處理放在此處,包括通知告警、自動摘除以及對外提供upstream健康狀態api等。這裏面自動摘除節點是在內存級別摘除,採用的是dyups模塊提供的功能,在此基礎上封裝了一層api接口,提供健康檢查使用。dyups有興趣的同學可以自行查看,本文不再介紹此內容。對外提供的upstream健康狀態,是放到共享內存裏面,提供了對外的api接口,直接調用可獲取upstream健康狀態信息。函數中使用了鎖get_lock調用了check_peers方法,是爲了防止多個工作進程同時發送測試請求。由於上文中介紹到只使用一個worker進程進行健康檢查,所以去除了get_lock。

     check_peers:此函數中,針對單個請求和多併發數進行了不同處理。如果請求併發只有一個,直接進行check_peer進行具體的檢測;如果是多個請求,則使用ngx.thread.spawn生成新的"light thread"來進行check_peer,多個"light thread"可以同時運行,總的耗時只相當於訪問一個源服務器的時間,即使需要訪問的源服務器增加,耗時沒有太大的變化。

     check_peer:此函數纔是真正進行健康檢查的代碼,總結起來包含兩步,tcp檢測和http檢測。

  • tcp檢測:tcp檢測比較簡單,使用ngx.socket.tcp:connect,向上遊服務器發送TCP socket,如果失敗,說明上游節點掛掉或端口未打開,使用peer_fail對down掉的節點進行處理。
  • http檢測:如果tcp檢測成功,則進行下一步檢測。在spawn_checker初始化參數中,對檢測接口重新封裝成請求報文,包含請求行和請求頭。接下來向上遊節點發送請求,讀取並解析響應,若響應返回的status不對或者不在配置的正常狀態中,表明服務異常,同時去解析header頭,判斷錯誤原因。最後用peer_error對異常進行處理。

 

    以上檢測沒有問題,則進行peer_ok處理。

    到此,健康檢查處理結束。以下介紹一下peer_fail、peer_error、peer_ok

    peer_fail:處理檢測節點失敗的次數,如果最後失敗的次數大於配置的次數,使用set_peer_down_globally在共享內存中記錄down掉的upstream以及節點id

    peer_error:如果down了打印日誌,調用peer_fail進行節點狀態處理

    peer_ok:記錄檢測節點成功狀態,將之前檢測不成功的狀態置爲0,使用set_peer_down_globally將節點down的狀態置爲nil

 

2.3 注意事項

  • 在使用健康檢查,如果要用到自動摘除功能,配置上游配置時,proxy_pass後面的域名需要寫成nginx變量形式,否則無法生效。注意dyups官方提供的配置說明
比如:
proxy_pass http://host.test.com;
需要改寫爲:
set $upstream host.test.com;
proxy_pass http://$upstrea;
  • 在對外提供api接口時,提供服務的nginx server配置需要配置白名單,否則可能導致安全漏洞

2.4 相關說明

openresty health_check官方源碼地址:https://github.com/openresty/lua-resty-upstream-healthcheck/blob/master/lib/resty/upstream/healthcheck.lua

基於官方代碼基礎修改後的代碼由於商業原因不便透漏,但大概思想如上所述,如有不對之處請指正,互相學習學習。

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章