API metrics for disaster recovery

Project LXD
Title API metrics for disaster recovery
Status Completed
Author(s) @pedro-rib
Approver(s) @tomp
Type Implementation
Internal ID LX083

Abstract

Proposing API metrics failure detection on LXD servers as part of a disaster recovery framework in MicroCloud. The goal of this spec is proposing metrics that are useful for detecting failures on each LXD server in a MicroCloud. Those metrics would be accessible through /1.0/metrics on each LXD server along with the existing metrics and be consumed by Canonical Observability Bundle (COS).

Rationale

MicroCloud, and particularly LXD, already provide many tools for disaster recovery, like instance/volume backups, snapshots and LXD’s disaster recovery tool. But although those features provide some tools to help recovering in case a failure happens, they don’t address the problem of detecting the failure itself efficiently.

For this reason, this specification proposes API metrics that convey real-time information about that server’s activity through API request rates. The user could easily make use of those metrics, setting appropriate thresholds for their values and configuring automated actions and alerts using COS or some other third party solution that would consume the values of these metrics.

Specification

Overview

Those metrics are designed to be scraped by Prometheus (that is included on COS) in regular intervals, giving an overview of the behavior of each LXD server on a MicroCloud over time.

The introduced metrics would be included as part of LXD’s internal metrics, accessible through GET /1.0/metrics on each node on a MicroCloud. Thus, each metric value is per node, allowing for identification of failures on any individual node on a MicroCloud.

Lastly, the API rates metrics will consider all endpoints on the main REST API, plus any request against the LXD server that uses an invalid URL will also be considered.

The docs relevant to these metrics can be found here.

Proposed metrics

All proposed metrics include a label dimension named entity_type that would showcase the main type of resource that each endpoint operates on. In this first version of the API metrics, the value associated with this label would follow this pattern:

instance for /1.0/containers and /1.0/instances endpoints.

network for /1.0/network-zones, /1.0/network-allocations, /1.0/network-acls and /1.0/networks endpoints.

storage_pool for /1.0/storage-pools and /1.0/storage-volumes endpoints.

identity for /1.0/auth and /1.0/certificates endpoints.

image for /1.0/images endpoints.

cluster_member for /1.0/cluster endpoints.

project for /{version}/projects endpoints.

profile for /{version}/profiles endpoints.

warning for /{version}/warnings endpoints.

operation for /{version}/operations endpoints.

server for /{version}/events, /{version}/metrics, /{version} and /{version}/resources endpoints. This is also used as a default value in case a URL does not match any other type, like we would expect from requests using invalid URLs.

With this information, it would be possible to filter the values of the metrics for each resource type and better convey to the user information about the failures that could be happening on the LXD server.

Additionally, for the rest of this specification, a request is considered completed if either:

  1. The request handler finished without spawning any asynchronous operation.
  2. All the operations spawned while handling a request are done and the request handler finished.

The metrics that will be included are:

1. Total completed requests: A counter type metric named lxd_api_requests_completed_total with no associated labels. Represents the number of completed requests by a LXD server from the moment it is started. The value for this metric starts at 0 and is incremented by 1 at each completed request on the LXD API, independently of the status of the response.

This will be calculated using a variable in memory and thus would reset to 0 each time the server restarts. This reset could be handled by Prometheus, who would continue incrementing the value of this metric from the last known value prior to the restart. The decrease of this metric’s value due to an unexpected restart could also be detected by the observability tool and interpreted as a failure.

This would also include one additional label dimension named result. This label is related to the request response’s status codes and can have the following values:

  • client_error, for completed requests that responded with a 4* status code, signaling that this request resulted in a client error. The reasoning for this is to easily filter this out when setting thresholds for server errors or identifying failures on the client;
  • server_error, for any request that spawns an asynchronous operation that fails or requests that responded with a 5* status code, signaling that the handling of that request resulted in a server error. An operation is considered as failed if it assumes a 400 status code.
  • succeeded, for all remaining requests.

2. Ongoing requests: A gauge type metric named lxd_api_requests_ongoing with no additional labels aside from the previously mentioned entity_type. Represents the number of ongoing requests on a LXD server at a certain point in time. Will also be computed with a variable in memory, being incremented in one every time a request starts being handled and decremented by 1 each time a request is completed, independently of the status code of the response and the outcome of any spawned operations. This metric is useful to check for a higher than expected number of pending requests, possibly alerting for long response times or an overload on a particular LXD server.

Although there is currently a lxd_operations metric that indicates ongoing operations, not every request spawns an operation and some failures can happen before creating the operation related to that request, so it is important to also include a metric for monitoring ongoing requests.

API changes

To include the new metrics on the LXD API, a metrics_api_requests API extension will be introduced. This extension will include changes to GET /1.0/metrics, adding the new metrics on the beginning of the endpoint’s response in the following format:

# HELP lxd_api_requests_completed_total The total number completed requests.

# TYPE lxd_api_requests_completed_total counter

lxd_api_requests_completed_total{status="succeeded",resource_group="images"} NUMBER_OF_SUCCEEDED_REQS_ON_STORAGE

lxd_api_requests_completed_total{status="succeeded",resource_group="instances"} NUMBER_OF_SUCCEEDED_REQS_ON_INSTANCES

lxd_api_requests_completed_total{status="server_error",resource_group="storage"} NUMBER_OF_SUCCEEDED_REQS_ON_IMAGES

…

# HELP lxd_api_requests_ongoing The number of ongoing requests on LXD REST API.

# TYPE lxd_api_requests_ongoing gauge
lxd_api_requests_ongoing{resource_group="images"} NUMBER_OF_ONGOING_REQS_ON_IMAGES

...