【Azure 應用服務】App Service 運行狀況健康檢查功能簡介 (Health check)

通過Azure App Service門戶,啟用Health Check來監視應用服務的實例,當發現其中一個實例處於不健康(unhealthy)狀態時,通過重新路由(即把有問題的實例從負載均衡器中移除, Load Balancer)的方式把請求發送到健康的實例上。並且如果不健康的實例一直存在問題,系統則會啟動一個新實例來替換不健康的這個實例。

This article uses Health check in the Azure portal to monitor App Service instances. Health check increases your application’s availability by re-routing requests away from unhealthy instances, and replacing instances if they remain unhealthy.

應用服務計劃應該擴展到兩個或者更多的實例,以充分利用Health Check功能。並且應該是對應用的關鍵組件進行監控檢查。

Your App Service plan should be scaled to two or more instances to fully utilize Health check. The Health check path should check critical components of your application.

 

例如:如果應用依賴於資料庫和一個Message系統,那麼Health Check應該設置在需要與資料庫連接,Message系統連接的功能點。當應用關鍵組件出現異常時,通過返回500的狀態碼告訴Health Check表示當前實例的運行狀態為不健康(unhealthy)。

For example, if your application depends on a database and a messaging system, the Health check endpoint should connect to those components. If the application cannot connect to a critical component, then the path should return a 500-level response code to indicate the app is unhealthy.

 

 

Health Check 會做些什麼呢?

1)通過啟用Health Check功能時配置的請求URL,應用服務的所有實例將會每間隔1分鐘對該URL請求一次。

2)如果某一個實例在連續兩次或多次無法處理URL請求(響應狀態不在200 ~ 299 間),或者根本就無法響應URL的請求,則系統將判定這一個實例為不健康狀態並將其從請求路由表中刪除以便於不處理真正的業務請求。

3)當從路由表中移除後,Health check將繼續對這一個不健康的實例發送請求,如果這個實例一直沒有成功響應,App Service將會重啟底層的VM,努力嘗試修復它並讓它正常工作。

4)如果這一個實例在一個小時內,一直都是unhealthy狀態,它將會被新的實例所取代。

5)此外,在向外擴展實例(添加新實例),App Service也會使用Health check中所配置的請求URL,確保當前實例已做好充分準備,正式接受真正業務請求。

注意:Health check不支援 302 重定向。 每小時最多更換一個實例,每個應用服務計劃每天最多更換三個實例。

 

啟用 Health Check

 

  •  為了啟用Health Check,進入App Service的Azure 門戶頁面,然後選擇Health Check目錄
  •  選擇」 啟用 「按鈕,並輸入一個有效的URL,可以對應用的健康狀態起健康檢測的相對路徑,例如:/health  or /api/health
  •  點擊」 保存 「按鈕

 注意:Health Check啟用或更改會重啟當前應用程式。為了盡量減少對生產應用程式的影響,建議配置在Staging slots後,通過交換部署槽的方式發布到生產。

 

Health Check的配置選項

為了修改默認的Health Check配置選項,可以在應用程式的設置(Application Setting)修改參數: WEBSITE_HEALTHCHECK_MAXPINGFAILURESWEBSITE_HEALTHCHECK_MAXUNHEALTHYWORKERPERCENT

 

  • WEBSITE_HEALTHCHECK_MAXPINGFAILURES : 允許值為 2 ~10 。將實例視為unhealthy並將從負載均衡器中移除所需要滿足的失敗請求次數。例如,當設置為2時,實例將在2次ping失敗後被刪除(默認值為10)

 

  • WEBSITE_HEALTHCHECK_MAXUNHEALTHYWORKERPERCENT : 允許值為 0 ~ 100。默認情況下,一次將不超過一般的實例數從負載均衡器中移除,以避免壓倒剩餘的健康實例。例如,如果應用服務計劃擴展到四個實例並且三個不正常,則兩個將被排除。 另外兩個實例(一個健康和一個不健康)將繼續接收請求。 在所有實例都不健康的最壞情況下,不會排除任何實例。 將值修改為 0 到 100 之間,更高的值意味著將刪除更多不健康的實例(默認值為 50)。

 

Health Check的身份認證和安全

Health Check與應用服務的身份驗證和授權功能集成。 如果啟用了這些安全功能,則不需要其他設置。

如果使用的是自定義的身份驗證系統,則健康檢查路徑(Health Check Path)必須允許匿名訪問。

要保護 Health Check Endpoint,應該首先使用 IP 限制、客戶端證書或虛擬網路等功能來限制應用程式訪問。 可以通過要求傳入請求的 User-Agent 匹配 HealthCheck/1.0 來保護Health Check Endpoint。 User-Agent 不能被欺騙,因為請求已經被先前的安全功能保護了。

 

Health Check Metrics指標

啟用 App Service 的Health Check後,可以使用 Azure Monitor 監視站點的運行狀況。操作步驟如下:

 

常見問題

1: 如果應用程式在單個實例上運行會發生什麼?

如果應用程式僅擴展到一個實例並且變得不健康,它不會從負載均衡器中刪除,因為這會導致您的應用程式完全停機。 將兩個或更多實例擴展到兩個或更多實例,以獲得Health Check的重新路由優勢。 如果應用程式在單個實例上運行,仍然可以使用 Health check 的監控功能來跟蹤應用程式的健康狀況。

 

2: 為什麼健康檢查請求沒有顯示在前端日誌中?

Health Check請求在內部發送到站點,因此該請求不會顯示在前端日誌中。這也意味著請求的來源為 127.0.0.1,因為它是在內部發送的請求。可以在Health Check Path頁面的程式碼中添加日誌語句,以保留Health Check URL何時被 ping 的日誌。

 

3: Health Check請求是通過 HTTP 還是 HTTPS 發送的?

當站點上啟用 HTTPS Only 時,Health Check請求將通過 HTTPS 發送。否則,它們將通過 HTTP 發送。

 

4: 如果在同一個應用服務計劃中有多個應用怎麼辦?

無論應用服務計劃中的其他應用如何(最多達到 WEBSITE_HEALTHCHECK_MAXUNHEALTHYWORKERPERCENT 中指定的百分比),運行狀況不佳的實例將始終從負載均衡器輪換中刪除。

當實例上的應用程式保持不健康狀態超過一小時時,僅當所有其他啟用Health Check的應用程式也處於不健康狀態時,才會更換該實例。未啟用Health Check的應用程式將不會被考慮在內。

例如:

假設您有兩個應用程式啟用了Health Check,稱為App A 和App B。它們在同一個應用服務計劃中,並且該計劃擴展到 4 個實例。

  • 如果 App A 在兩個實例上變得不健康,負載均衡器將停止向這兩個實例上的 App A 發送請求。 假設 App B 是正常的(Healthy),請求仍會在這些實例上路由到 App B。
  • 如果 App A 在這兩個實例上保持不健康狀態超過一個小時,則只有當 App B 在這些實例上也不健康時,才會替換這些實例。 如果 App B 健康,則不會替換實例。

 注意:如果在同一個應用服務計划下還有另外一個App Serice,它沒有啟用Health Check,則該實例將永遠不會因為Health Check功能而被替換。所以建議對重要的應用程式單獨部署在一個應用服務計劃中,並開啟Health Check。

5: 如果所有實例都不健康怎麼辦?

在應用程式的實例不正常的情況下,應用服務將從負載均衡器中刪除實例,最多可達 WEBSITE_HEALTHCHECK_MAXUNHEALTHYWORKERPERCENT 中指定的百分比。

在所有實例都不健康的最壞情況下,不會排除任何實例。

 

6: 測試Health Check的.Net程式碼 (設置Health Check Path為 /fail

創建一個默認的.NET Core API項目,在 Program.cs 文件中替換默認的Host Builder方法。

  • 通過發送一個/fail的請求,人為的設置請求返回為500。使得Health Check功能認為當前實例為不健康(unhealthy)
  • 在Host啟動的時候會自動生產一個GUID,用於標記當前實例。以便於在後續的驗證中跟蹤實例處理請求的行為或重啟動作
  • 啟用Health Check功能後,所以實例都會收到並處理 /fail 請求,返回500.  
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace hellodotnetcore
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }


        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            //初始化當前Host實例時候隨機生成一個GUID,用於在此後的請求中判斷當前時候是否被標記為健康,非健康,回收。
            var instance = Guid.NewGuid();
            //firstFailure來記錄第一個失敗請求所進入當前實例的時間,firstFailure保存在記憶體中
            DateTime? firstFailure = null;

            return Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                webBuilder.Configure(configureApp =>
                configureApp.Run(async context =>
                {
                    //當請求URL為fail時候,認為設置返回狀態為500,告訴App Service的Health Check功能,當前實例出現故障。
                    if (firstFailure == null && context.Request.Path.Value.ToLower().Contains("fail"))
                    {
                        firstFailure = DateTime.UtcNow;
                    }

                    if (firstFailure != null)
                    {
                        context.Response.StatusCode = 500;
                        context.Response.ContentType = "text/html; charset=utf-8";
                        await context.Response.WriteAsync(
                           $"當前實例的GUID為 {instance}.\n" +
                            $"這個實例最早出現錯誤的時間是 {firstFailure.Value}.\n\n" +
                            $"根據文檔的描述 //docs.microsoft.com/en-us/azure/app-service/monitor-instances-health-check, 如果一個實例在一直保持unhealthy狀態一小時,它將會被一個新實例所取代\n\n" +
                            $"According to //docs.microsoft.com/en-us/azure/app-service/monitor-instances-health-check, \"If an instance remains unhealthy for one hour, it will be replaced with new instance.\".");
                    }
                    else
                    {
                        context.Response.StatusCode = 200;
                        context.Response.ContentType = "text/html; charset=utf-8";
                        await context.Response.WriteAsync($"當前實例的GUID為 {instance}.\n" +
                            $"此實例報告顯示一切工作正常.");
                    }
                })));



            //public static IHostBuilder CreateHostBuilder(string[] args) =>
            //    Host.CreateDefaultBuilder(args)
            //        .ConfigureWebHostDefaults(webBuilder =>
            //        {
            //            webBuilder.UseStartup<Startup>();
            //        });
        }
    }
}

在本地測試以上程式碼效果如下:

 

 

參考資料

Monitor App Service instances using Health check://docs.azure.cn/zh-cn/app-service/monitor-instances-health-check