新文章 网摘 文章 随笔 日记

在 ASP.NET Core 中使用 Consul 进行健康检查

上一篇文章中,我写过如何使用Consul和 ASP.NET Core 实现客户端服务发现。如果您使用容器或微服务进行任何操作,这是一种非常有用的技术。

除了注册您的服务之外,如果服务注册中心可以跟踪服务的每个实例的运行状况,这将非常有帮助。如果客户端知道服务实例不再可用或不健康,它可以避免向该位置发送请求并处理由此产生的错误。在这篇文章中,我们将定义服务健康意味着什么,并了解如何使用 ASP.NET Core 和 Consul 实现健康检查。

服务运行状况

我们可以考虑通过几种方式检查服务实例的健康状况。在应用程序级别,如果服务正在运行、可以处理请求、不抛出异常等等,您可能会认为服务是健康的。要考虑的另一件事是运行服务的机器(或虚拟机或容器)的状态。您可能想知道内存消耗是多少、磁盘空间的使用百分比是多少,或者 CPU 利用率是多少?要考虑的第三类健康检查是外部依赖项的状态。例如,服务能否与数据库通信,能否与缓存服务交互,能否连接到给定的第 3 方供应商?即使服务本身已启动并正在运行,

领事健康检查

在我写这篇文章时,当前版本的 Consul (0.8.0) 支持 5 种不同类型的检查。

  • HTTP 间隔检查- 将以给定的间隔向指定的 URL 发出 HTTP GET 请求。带有 2xx 状态代码的响应被认为是通过,而所有其他的都被认为是有问题的。这可以通过Web 应用程序中的端点/status或端点轻松实现。/health
  • TCP 间隔检查- 尝试连接到给定的主机/IP 地址和端口号。如果可以建立连接,则认为健康检查状态为通过,否则状态为严重。这对于您自己的甚至是侦听端口的第 3 方应用程序很有用。
  • 脚本间隔检查- 使用这种类型的检查,调用外部应用程序,执行编码操作,使用适当的系统代码退出,并可能生成一些输出。如果您的检查背后有更复杂的逻辑,那么这是一个不错的选择。您可以提供一个脚本(用 bash、Powershell、python 等编写),Consul 甚至会将输出捕获到它的 UI 中。
  • Docker 间隔检查- 调用 Docker 容器内的外部应用程序。预计将对容器内运行的服务进行健康检查,并使用适当的退出代码退出。
  • 生存时间(TTL)检查——检查的状态必须通过 Consul 的 HTTP 接口定期更新;通常由一些外部系统。因此,不是 Consul 启动健康检查,而是期望在给定的时间段内提供服务的状态。如果 TTL 过期,则状态将设置为关键。
向 ASP.NET Core 添加运行状况检查

可以选择在服务注册时包括健康检查。在某些情况下,这是上一篇文章中的注册码的样子。

 public static IApplicationBuilder RegisterWithConsul(this IApplicationBuilder app,
         IApplicationLifetime lifetime)
        {
            // Retrieve Consul client from DI
            var consulClient = app.ApplicationServices
                                .GetRequiredService<IConsulClient>();
            var consulConfig = app.ApplicationServices
                                .GetRequiredService<IOptions<ConsulConfig>>();      
                  
            // Get server address information
            var features = app.Properties["server.Features"] as FeatureCollection;
            var addresses = features.Get<IServerAddressesFeature>();
            var address = addresses.Addresses.First();               
            var uri = new Uri(address);

            // Register service with consul
            var registration = new AgentServiceRegistration()
            {
                ID = $"{consulConfig.Value.ServiceID}-{uri.Port}",
                Name = consulConfig.Value.ServiceName,
                Address = $"{uri.Scheme}://{uri.Host}",
                Port = uri.Port,
                Tags = new[] { "Students", "Courses", "School" }
            };
            consulClient.Agent.ServiceDeregister(registration.ID).Wait();
            consulClient.Agent.ServiceRegister(registration).Wait();

            lifetime.ApplicationStopping.Register(() => {
                 consulClient.Agent.ServiceDeregister(registration.ID).Wait(); 
            });
           

该类AgentServiceRegistration有一个Checks属性,可用于提供与服务注册相关联的健康检查列表。让我们看一下向这个应用程序添加一些 Consul 健康检查。

HTTP 健康检查
var registration = new AgentServiceRegistration()
{
    ID = $"{consulConfig.Value.ServiceID}-{uri.Port}",
    Name = consulConfig.Value.ServiceName,
    Address = $"{uri.Scheme}://{uri.Host}",
    Port = uri.Port,
    Tags = new[] { "Students", "Courses", "School" },
    Checks = [new AgentCheckRegistration()
              {
                  HTTP = $"{uri.Scheme}://{uri.Host}:{uri.Port}/api/health/status",
                  Notes = "Checks /health/status on localhost",
                  Timeout = TimeSpan.FromSeconds(3) ,
                  Interval = TimeSpan.FromSeconds(10)
              }]
};

此检查期望/api/health/status应用程序中有一个可用的端点,供 Consul 向其发出 HTTP GET 请求。另请注意,您可以设置超时和检查间隔。

这是端点的样子。当然,您可以在 中添加更多代码HealthController以确定返回的条件Ok

[Route("api/[controller]")]
public class HealthController : Controller
{
    [HttpGet("status")]        
    public IActionResult Status() => Ok();
}
TCP 健康检查
var registration = new AgentServiceRegistration()
{
    ID = $"{consulConfig.Value.ServiceID}-{uri.Port}",
    Name = consulConfig.Value.ServiceName,
    Address = $"{uri.Scheme}://{uri.Host}",
    Port = uri.Port,
    Tags = new[] { "Students", "Courses", "School" },
    Checks = [new AgentCheckRegistration()
              {                 
                  TCP = "localhost:8000",
                  Notes = "Runs a TCP check on port 8000",
                  Timeout = TimeSpan.FromSeconds(2),
                  Interval = TimeSpan.FromSeconds(5),
              }]
};

有了这个 TCP 检查,Consul 会尝试打开到 localhost 上的端口 8000 的连接。请注意,这些类型的检查不仅限于本地连接。它们可用于检查是否可以连接到任何应用程序,侦听给定 IP 地址的任何端口。

脚本健康检查
var registration = new AgentServiceRegistration()
{
    ID = $"{consulConfig.Value.ServiceID}-{uri.Port}",
    Name = consulConfig.Value.ServiceName,
    Address = $"{uri.Scheme}://{uri.Host}",
    Port = uri.Port,
    Tags = new[] { "Students", "Courses", "School" },
    Checks = [new AgentCheckRegistration() 
              {              
                  Script = "/path/to/script/check.py",
                  Notes = "Runs check.py in the project folder",
                  Timeout = TimeSpan.FromSeconds(2),
                  Interval = TimeSpan.FromSeconds(5),
              }]
};

上面的代码设置了一个将调用 python 脚本的健康检查。如果脚本返回适当的退出代码,则检查成功。

这是我用来测试的简单脚本。

#! /usr/bin/env python3
import os, sys

print(os.getcwd())
sys.exit(os.EX_OK)

有了这些健康检查,您组织中的任何人都可以轻松地在 Consul UI 中查看您注册服务的状态。

对于健康检查状态的编程访问,我们可以直接利用 Consul 的HTTP API或使用 NuGet 包。

var _consulClient = new ConsulClient(c =>
{
    var uri = new Uri(_configuration["consulConfig:address"]);
    c.Address = uri;
});

var services = _consulClient.Agent.Services().Result.Response;
foreach (var service in services)
{
    var checks = _consulClient.Health 
                         .Checks(_configuration["consulConfig:serviceName"])
                         .Result;
    foreach (var checkResult in checks.Response)
    {
        Console.WriteLine($"{checkResult.ServiceID} - {checkResult.Status.Status}");
    }
}
结论

在这篇文章中,我们介绍了如何使用 Consul 和 PlayFab Consul NuGet 包注册运行状况检查。

Consul 只是在应用程序中设置健康检查的众多选项之一。在我写这篇文章时,看起来 ASP.NET 团队正在开发他们自己的健康检查支持版本。

https://cecilphillip.com/using-consul-for-health-checks-with-asp-net-core/

 

posted @ 2022-05-17 18:37  岭南春  阅读(303)  评论(0)    收藏  举报