Проверка работоспособности является фундаментальной частью наших API. Я думаю, они попадают в эту категорию «нефункциональных, но крайне необходимых» вещей. Более или менее как хорошая часть кода инфраструктуры.
Они не увеличивают стоимость бизнеса само по себе , но имеют огромное влияние на тех , кто в ИТ, как DDD и шаблонов проектирования. Обычно вы можете видеть их в сочетании с инструментами управления контейнером или мониторинга, чтобы убедиться, что система работает и работает.
Существуют в основном две категории проверки здоровья: готовность и живучесть.
Проверка работоспособности выполняет тщательную проверку всех зависимостей приложений, таких как базы данных, внешние службы и т. Д. Система загружается и работает, но еще не готова обслуживать входящие запросы.
Вместо этого используются проверки работоспособности, чтобы показать, что приложение готово обслуживать трафик. Они должны выполняться довольно быстро и служить немедленной проверкой, чтобы убедиться, что все в порядке.
Идея состоит в том, чтобы сначала запустить проверки готовности. Если они пройдут, положитесь только на живые в течение определенного времени.
Успешная проверка работоспособности должна вернуть статус HTTP 200 и базовый отчет, особенно для отчетов о готовности.
Настройка проверок в проекте ASP.NET Core довольно проста. Просто добавьте вызов services.AddHealthChecks()
в ConfigureServices()
методе нашего Startup.cs
.
На GitHub есть несколько интересных репозиториев, которые добавляют несколько хороших методов расширения. AspNetCore.Diagnostics.HealthChecks — одна из самых известных, предоставляющая проверки для широкого спектра систем, таких как SQL Server, MySql, Oracle, Kafka, Redis и многих других.
После того, как вы зарегистрировали проверки в DI-контейнере, следующим шагом будет предоставление конечной точки:
C #
xxxxxxxxxx
1
public void Configure(IApplicationBuilder app)
2
{
3
app.UseEndpoints(endpoints =>
4
{
5
endpoints.MapHealthChecks("/ops/health");
6
});
7
}
Это простейший возможный пример, однако, MapHealthChecks()
методы также дают нам возможность настроить вывод, указав Response Writer:
C #
xxxxxxxxxx
1
public void Configure(IApplicationBuilder app)
2
{
3
var healthCheckOptions = new HealthCheckOptions()
4
{
5
ResponseWriter = WriteReadinessResponse
6
};
7
app.UseEndpoints(endpoints =>
9
{
10
endpoints.MapHealthChecks("/ops/health", healthCheckOptions);
11
});
12
}
13
private static Task WriteReadinessResponse(HttpContext context, HealthReport result)
15
{
16
context.Response.ContentType = "application/json; charset=utf-8";
17
var options = new JsonWriterOptions
19
{
20
Indented = true
21
};
22
using (var stream = new MemoryStream())
24
{
25
using (var writer = new Utf8JsonWriter(stream, options))
26
{
27
writer.WriteStartObject();
28
writer.WriteString("status", result.Status.ToString());
29
writer.WriteStartObject("results");
30
foreach (var entry in result.Entries)
31
{
32
writer.WriteStartObject(entry.Key);
33
writer.WriteString("status", entry.Value.Status.ToString());
34
writer.WriteString("description", entry.Value.Description);
35
writer.WriteStartObject("data");
36
foreach (var item in entry.Value.Data)
37
{
38
writer.WritePropertyName(item.Key);
39
JsonSerializer.Serialize(
40
writer, item.Value, item.Value?.GetType() ??
41
typeof(object));
42
}
43
writer.WriteEndObject();
44
writer.WriteEndObject();
45
}
46
writer.WriteEndObject();
47
writer.WriteEndObject();
48
}
49
var json = Encoding.UTF8.GetString(stream.ToArray());
51
return context.Response.WriteAsync(json);
53
}
54
}
На основании добавленных проверок это должно вернуть что-то вроде этого:
C #
xxxxxxxxxx
1
{
2
"status": "Healthy",
3
"results": {
4
"db": {
5
"status": "Healthy",
6
"description": null,
7
"data": {}
8
}
9
}
10
}
Теперь я упомянул «оркестровку контейнеров» в начале этой статьи. Это имеет тенденцию быть синонимом Kubernetes , который имеет свою собственную конфигурацию для проверок работоспособности. В вашем configuration.yml
файле вы можете указать как живость, так и готовность:
C #
xxxxxxxxxx
1
readinessProbe:
2
httpGet:
3
path: /health/readiness
4
port: 80
5
initialDelaySeconds: 10
6
timeoutSeconds: 30
7
periodSeconds: 60
8
successThreshold: 1
9
failureThreshold: 5
10
livenessProbe:
11
httpGet:
12
path: /health/liveness
13
port: 80
14
initialDelaySeconds: 10
15
timeoutSeconds: 5
16
periodSeconds: 15
17
successThreshold: 1
18
failureThreshold: 3
Несколько вещей, чтобы отметить здесь. Прежде всего, конечные точки разные. Как мы уже обсуждали ранее, мы можем (и должны) разделить наши проверки, чтобы проверки жизнеспособности работали как можно быстрее.
Это может быть достигнуто, например, просто пропуская все проверки и возвращая 200 сразу:
C #
xxxxxxxxxx
1
endpoints.MapHealthChecks("/health/readiness", healthCheckOptions);
2
endpoints.MapHealthChecks("/health/liveness", new HealthCheckOptions(){
4
Predicate = (_) => false
5
});
Это Predicate
позволяет фильтровать чеки по различным условиям, таким как имя или теги. Да, это вещь, и ее можно указать. Подробнее здесь .
Возвращаясь к нашему конфигу Kubernetes, стоит упомянуть и другие настройки, используемые для проверок. Например, timeoutSeconds
выше при проверке готовности, так как мы проверяем, что все наши зависимости живы. То же самое относится и к periodSeconds
: мы хотим, чтобы проверки жизнеспособности проводились чаще.
Кроме того, не забывайте, что если failureThreshold
превзойти по живости, стручок будет убит. Сбой готовности приведет к тому, что модуль будет помечен как нездоровый, и больше не будет получать трафик.