Node-js 健康檢查和過載保護

設想一下,你有 30 個 Node 服務器與 "Nginx" 服務器平衡。服務器的負載被平均分配,所以如果你有 9000 個用戶,每個服務器有 300 個客戶。把負載平均分配給每臺服務器並不意味着你可以避免過載,因爲你的工作對每個用戶都可能不同。例如,對於 user_1,你可能讀取 3 個文件,但對於 user_2,你可能需要讀取 10 個(3.34 倍)。根據用戶的請求過程會有更多的複雜性,這是現實中需要去思考和解決的問題。在類似於這種的情況之下,開發者不得不平衡對同每一臺服務器的請求,因爲一旦這臺服務器是 Server Overload(過載) 的狀態,你的服務可能會掛掉。

健康檢查 每隔 n 秒向服務器發送請求,以瞭解服務器是否能夠處理更多的請求,如果正常,服務器將其標記爲 OK,並繼續從 Balancer(平衡器) 接收更多的請求,否則服務器將其標記爲 Error,Balancer 將不會向該服務器發送任何請求,直到 Balancer 再次發送健康檢查請求並標記爲 OK。

這個過程被稱爲健康檢查。

作爲檢測應用是否正常運行的機制,服務器健康檢查通常在以下情況下使用:

  1. 高可用性

  2. 負載均衡:如果正在使用多個實例運行同一項目或者應用,則可以將負載平衡器配置爲定期查詢每個實例並記錄其響應時間和狀態。

  3. 自動化部署:自動化部署過程中包括激活新版本後立即執行的測試步驟,這些測試步驟大多數都涉及到對系統組件進行基本的功能驗證或心跳監控。

  4. 監控和警報:當服務不再可訪問或出現其他問題時,服務器健康檢查可以觸發警報並通知管理員或開發人員進行干預操作。

實際應用

以下是基於 Express 和 Node.js 實現健康檢查的簡單 Demo:

  1. 安裝 healthcheck 模塊:使用 npm 或 yarn 等包管理工具安裝 healthcheck 模塊。

  2. 在 Express 應用中添加路由:創建一個新路由來處理 / healthcheck 請求,並返回 200 OK 響應。

const healthCheck = require('express-healthcheck');

app.use('/health', healthCheck({
  healthy: function () {
    return { everything: 'is ok' };
  }
}));
  1. 向監控系統報告:如果正在使用譬如 Prometheus[2] 之類的監控系統,則可以將其配置爲定期查詢 / health 接口並記錄結果。此外,還可以將結果發送到其他系統進行分析和通知。

  2. 添加自定義檢查項:除了默認提供的基本系統信息之外,還可以編寫自己的檢查函數來測試特定組件或功能是否可用。這些函數必須返回承諾對象並被註冊到健康檢查器中:

const checkDbConnection = async () ={
  try {
    const client = await pool.connect();
    await client.query('SELECT NOW()');
    return true;
  } catch (e) {
    console.error(e);
    return false;
  }
};

const customChecks = [checkDbConnection];

app.use('/health', healthCheck({
  healthy: function () {
    return { everything: 'is ok' };
  },
  customChecks
}));

結合着 nginx 和 node.js 做健康檢查

考慮到實際項目中廣泛使用 Nginx 的現狀,所以筆者推薦使用 nginx_upstream_check_module(不隨 Nginx 源碼分發) 和 Node.js 來實現服務器健康檢查:

  1. 首先,在 Nginx 配置文件中啓用 upstream_check 模塊。例如,可以在 http 塊中添加如下代碼:
http {
  upstream myapp {
    server localhost:3000;

    check interval=3000 rise=fall=timeout=2000 type=http;
    check_http_send "HEAD /health HTTP/1.0\r\n\r\n";
    check_http_expect_alive http_2xx http_3xx;
  }
}

這將創建一個名爲 myapp 的上游組,並且每隔 3 秒鐘會向 localhost:3000 發送一個 HTTP HEAD 請求以檢查其狀態。

  1. 在 Node.js 應用中,按照前面提到的方法設置 / healthcheck 路由(或任何其他自定義路由)。
const healthCheck = require('express-healthcheck');

app.use('/health', healthCheck({
  healthy: function () {
    return { everything: 'is ok' };
  }
}));
  1. 確保應用正在偵聽端口 3000 並運行。如果需要更改端口,請相應地更新 Nginx 配置文件。

  2. 最後,在瀏覽器中訪問 http://localhost/_nginx_health_check/myapp(根據需要更改主機和路徑),以確保 Nginx 正確顯示了 myapp 上游組件的狀態,並且已經能夠成功連接到 Node.js 服務端點。

通過以上幾個步驟,就可以將 nginx_upstream_check_module 和 Node.js 結合起來創建一個強大的健康檢查機制。

儘管 ngx_http_healthcheck_module 擁有着高效、零活且易於配置的優點,但是由於其僅適用於 HTTP 服務,不支持 TCP 或 UDP 健康檢查:如果要檢測連接到非 Web 服務器(如數據庫)是否正常工作,則需要另外使用第三方組件或軟件包。

HAProxy

HAProxy[3] 是一個開源的負載均衡工具,可以將來自客戶端的請求分發到多個後端服務器,並確保這些請求能夠平衡地分配給所有可用的服務器。HAProxy 支持多種協議,例如 HTTP、TCP 和 SMTP 等。

HAProxy 最初是爲高可用性而設計的,在其最簡單的形式下,它只需配置兩個或更多臺服務器即可實現基本負載均衡。但隨着時間推移和版本更新,它已經成爲一款功能強大且廣泛應用於各種場景中(包括大型企業網絡)的軟件。

除了提供負載均衡之外,HAProxy 還具有其他有用功能。例如:

  1. 健康檢查:HAProxy 可以定期檢查後端服務器是否健康,並根據需要啓停不健康或超時連接。

  2. SSL 終止:HAProxy 可以在前置代理層上執行 SSL 加密和解密操作。

  3. 請求重寫:HAProxy 允許使用 ACL 規則對傳入請求進行修改或過濾。

  4. 日誌記錄:HAProxy 生成詳細日誌以便於跟蹤問題並進行性能優化。

HAProxy 可以與 Nginx 和 NodeJS 結合使用,以提供一個高性能、可擴展和可靠的網絡服務基礎設施。以下是將這些技術結合起來使用的一種可能方式:

  1. 使用 Nginx 作爲一個反向代理:在這種配置中,Nginx 作爲前端服務器,接收所有來自客戶端的傳入請求,並將其轉發到適當的後端服務器進行處理。開發者可以配置 Nginx 分別在 80 或 443 端口監聽 HTTP 或 HTTPS 流量。

  2. 將 HAProxy 配置爲一個負載平衡器:HAProxy 應該被配置爲在運行 NodeJS 項目的多個後端服務器之間分配傳入的流量。負載平衡算法可以根據使用者的具體需求來定製。

  3. 使用 PM2 部署 NodeJS 項目:PM2 是一個進程管理器,可以輕鬆地在多個服務器實例上管理和擴展 NodeJS 項目。

  4. 在負載均衡器層面上設置 SSL 終端:如果開發者的應用需要 SSL 加密,可以通過在負載平衡器上安裝 SSL 證書,在 HAProxy 層面上設置 SSL 終止。

下面是使用這些技術時需要考慮到的一些問題:

總的來說,將 HAProxy 與 Nginx 和 nodeJS 結合起來,爲建立快速、可靠的 Web 服務提供了一個強大的工具集,可以處理大量的流量,同時在系統故障或中斷的情況下提供強大的故障轉移機制。

過載保護

爲了檢查服務器是否過載並防止過載,開發者通常需要檢查一些指標。這也取決於項目代碼邏輯是否完全準確無誤,但在這裏可以看到必須檢查的通用指標。

我們可以藉助於 overload-protection[4] 這個包,可以幫助我們快速定位到這些指標。另一個值得推薦的包是 event-loop-lag[5],接受一個代表刷新事件循環滯後測量頻率的毫秒數,並返回一個可以調用的函數,以接收最新的滯後測量值,單位爲毫秒。

使用 overload-protection 包,我們可以指定限制,超過這個限服務器將無法處理更多的請求。當配置的最大請求限制通過時,軟件包會自動發送 503 SERVICE UNAVAILABLE。該包與 http、express、restify 和 koa 包一起工作。

但是,如果負載平衡器 (Banlancer) 可以發送 socket 進行 Health Check,並且你想用 socket 來做,那麼就需要使用別的包來完成此事了。

結語

解釋 "健康檢查" 和 "過載保護"[6]。

" 每臺服務器至少應該有一個健康檢查的實現機制,這對分佈式系統來說是至關重要的。"

[1]

unsplash.com: https://unsplash.com/

[2]

Prometheus: https://prometheus.io/

[3]

HAProxy: https://www.haproxy.org/

[4]

overload-protection: https://github.com/davidmarkclements/overload-protection

[5]

event-loop-lag: https://github.com/pebble/event-loop-lag

[6]

Explaining “Health Checks” and “Overload Protection”: https://blog.bitsrc.io/nodejs-health-checks-and-overload-protection-368a132a725e

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ig3V0iwaVea9V4VQYDm3CQ