Back to Skywalking

BanyanDB self-observability dashboard

docs/en/banyandb/dashboards-banyandb.md

11.0.018.9 KB
Original Source

BanyanDB self-observability dashboard

Apache SkyWalking BanyanDB is the native storage for SkyWalking. A production deployment is one cluster made of many nodes, each running one or more containers with a role (liaison front door, data backend, and the lifecycle tier-migration sidecar), and data is organized into groups. SkyWalking models that reality directly and renders it on the Layer: BANYANDB dashboards in the Horizon UI:

SkyWalking entityBanyanDB conceptIdentity
Serviceone BanyanDB clusterthe cluster label
ServiceInstanceone container on a nodecontainer_name + pod_name (joined by @, e.g. data@…-data-hot-0)
  ↳ attributesrole / tiercontainer_name (liaison/data/lifecycle), node_type (hot/warm/cold), node_role, pod_name
Endpointone group (storage partition)the group label (e.g. sw_metricsMinute)

Requires BanyanDB 0.11+. This feature reads the FODC-proxy cluster-observability metric families and the queue / lifecycle metric families that BanyanDB introduced after 0.10. Run a 0.11+ cluster with the FODC proxy and the Prometheus metrics provider enabled.

Data flow

  1. Each BanyanDB container exposes its metrics; in a cluster the FODC proxy aggregates every container's Prometheus metrics onto a single /metrics endpoint (default :17913) and stamps each sample with per-container identity labels (pod_name, container_name, node_role, and node_type on data containers).
  2. An OpenTelemetry Collector scrapes the FODC proxy /metrics as the single Prometheus target, adds a static cluster: <name> label (the only label SkyWalking must inject), and pushes via the OpenTelemetry gRPC exporter to the SkyWalking OAP Server.
  3. The OAP Server parses the MAL rules under otel-rules/banyandb/ to filter / calculate / aggregate and store the cluster, instance and group metrics.

Set up

  1. Run a BanyanDB 0.11+ cluster (liaison + data nodes; data nodes may be tiered hot/warm/cold) with the FODC proxy enabled and the Prometheus metrics provider on (default). Standalone mode is the degenerate case — one cluster, one node, one container_name=standalone.

  2. Run an OpenTelemetry Collector whose prometheus receiver scrapes the FODC proxy /metrics (:17913) as the single target and adds a static cluster: <name> label, exporting OTLP to OAP. The FODC proxy already stamps the per-node identity labels (pod_name / container_name / node_role / node_type), so cluster is the only label the collector must inject.

    The scrape job_name MUST be banyandb-monitoring. Every rule file filters on { tags -> tags.job_name == 'banyandb-monitoring' } (the OTel receiver maps the Prometheus job to the job_name tag), so a differently-named job produces no metrics.

    yaml
    receivers:
      prometheus:
        config:
          scrape_configs:
            - job_name: "banyandb-monitoring"          # REQUIRED — the rules filter on it
              scrape_interval: 15s
              static_configs:
                - targets: ["<fodc-proxy-host>:17913"] # the FODC proxy aggregates every node's metrics
                  labels:
                    cluster: <your-cluster-name>        # the only label SkyWalking must inject
    exporters:
      otlp:
        endpoint: <oap-host>:11800
        tls:
          insecure: true
    service:
      pipelines:
        metrics:
          receivers: [prometheus]
          processors: [batch]
          exporters: [otlp]
    

    Scrape the FODC proxy, not the individual nodes. The proxy resolves each node's identity from the cluster and stamps pod_name / container_name / node_role and the data-node tier (node_type) onto every sample — context the raw per-node :2121 endpoints do not carry. Direct per-node scraping is not recommended: it would have to hand-inject all of those identity labels for every node. (The e2e does exactly that only because it runs no FODC proxy — see the test collector config — and is not a production pattern.)

  3. Enable SkyWalking's OpenTelemetry receiver. The banyandb/* rules are enabled by default in enabledOtelMetricsRules.

  4. Open the Horizon UIBanyanDB layer.

Metrics

The metric source expressions mirror the upstream BanyanDB Grafana boards, so the SkyWalking dashboards stay in lockstep with the BanyanDB catalog. The rule files are otel-rules/banyandb/banyandb-service.yaml, banyandb-instance.yaml, banyandb-endpoint.yaml and banyandb-instance-relation.yaml.

The instance and endpoint catalogs are category-separated: the rule name carries a role prefix (instance scope) or a data-type prefix (endpoint scope) so that a human can read a metric name and know which role / data type it belongs to, and so the UI layer template can select the right panel set. The storage prefix is on the rule name only — every metric still carries the meter_banyandb_{instance,endpoint,instance_relation}_ family prefix, and the scope / entity keys are unchanged.

Service scope — cluster summary (meter_banyandb_*)

UnitMetricDescription
w/smeter_banyandb_cluster_write_rateCluster write rate across measure/stream/trace
r/smeter_banyandb_cluster_query_rateCluster query rate
c/mmeter_banyandb_cluster_error_rateCluster error rate (counts/min)
Countmeter_banyandb_reporting_instancesLive container count by role
Countmeter_banyandb_total_cpu_coresCluster CPU capacity
Bytesmeter_banyandb_total_memory_usedCluster memory used
Bytesmeter_banyandb_total_disk_usedCluster disk used

Instance scope — per container (meter_banyandb_instance_*)

Instance rules are role-separated by name prefix. The shared resource / runtime block stays unprefixed (the family is inherently per-instance and resolves on whatever container emits it); front-door families carry a liaison_* prefix, storage / index / queue families a data_* prefix, and the migration-sidecar health triple a lifecycle_* prefix. The prefix lets the UI select the panel set per role (container_name liaison / data / lifecycle) and disambiguates the same wire family read under two roles (e.g. the pending_data_count family is liaison_wqueue_pending on the front door and data_wqueue_pending on the backend — each role rule reads only its own container's series).

Shared — resources / disk-by-path / Go runtime (unprefixed; every container emits these, except node_uptime which is absent on lifecycle — that container runs the metric service without the system collector):

UnitMetricDescription
snode_uptimeNode uptime
Corescpu_usageCPU usage
Bytesrss_memoryResident memory
percentsystem_memory_percentSystem memory used %
percentdisk_usage_percentDisk used % (BanyanDB used_percent, averaged across the node's data paths, which share one filesystem)
Bytesdisk_used_by_path / disk_total_by_pathDisk used / total bytes by mount path
percentdisk_used_percent_by_pathDisk used % by mount path
Bytes/snetwork_recv / network_sentNetwork throughput by interface
CountgoroutinesGo goroutines
sgc_pause_avgAverage GC pause
Bytesheap_inuse / heap_next_gcGo heap in-use / next-GC threshold
Bytes/salloc_rateGo allocation rate

Liaison (liaison_*; front door — the dashboard gates these on container_name == 'liaison'):

UnitMetricDescription
r/sliaison_query_rateQuery rate by data-model service (measure/stream/trace/property)
c/mliaison_grpc_error_rategRPC error rate (total + registry + stream-msg-received errors)
r/sliaison_registry_op_rateSchema-registry / non-query operation rate
w/sliaison_write_rateWrite rate seen at the front door
opsliaison_publish_throughputTier-2 publish throughput by operation (liaison → data)
Bytes/sliaison_publish_bytesPublish bytes
sliaison_publish_latency_p99Publish send latency p99
opsliaison_publish_batch_throughputTier-2 publish batch throughput by operation (build-gated, BanyanDB #1169)
sliaison_publish_batch_latency_p99Publish batch send latency p99 (build-gated, BanyanDB #1169)
Countliaison_wqueue_pendingFront-door write-queue pending records

Data (data_*; backend — the dashboard gates these on container_name == 'data'):

UnitMetricDescription
Countdata_total_dataTotal stored data elements
Countdata_wqueue_file_partsWrite-queue on-disk file parts
Countdata_wqueue_mem_partWrite-queue in-memory parts
Countdata_wqueue_pendingWrite-queue pending records
o/sdata_merge_file_rateMerge-loop rate
Countdata_merge_file_partitionsAvg parts merged per loop (file path)
sdata_merge_file_latencyAvg file-merge latency
o/sdata_series_write_rateInverted-index write rate (measure + stream + trace storage indexes)
o/sdata_series_term_search_rateInverted-index term-search rate
Countdata_total_seriesInverted-index documents (measure + stream + trace storage indexes)
o/sdata_stream_tst_write_rateStream tst index write rate
o/sdata_stream_tst_term_search_rateStream tst index term-search rate
Countdata_stream_tst_total_docsStream tst index documents
opsdata_queue_sub_throughputSubscribe-queue throughput by operation
sdata_queue_sub_latency_p99Subscribe-queue latency p99
opsdata_queue_sub_message_throughputSubscribe-queue per-message throughput by operation (BanyanDB #1169)
percentdata_retention_measure_disk_usage_percentRetention disk-usage % (measure scope)
percentdata_retention_stream_disk_usage_percentRetention disk-usage % (stream scope)
percentdata_retention_trace_disk_usage_percentRetention disk-usage % (trace scope)

The trace storage inverted index is now folded into data_series_write_rate / data_series_term_search_rate / data_total_series (it was silently dropped in the previous, measure+stream-only design).

Lifecycle (lifecycle_*; the tier-migration sidecar on hot/warm data pods — container_name == 'lifecycle'):

UnitMetricDescription
Countlifecycle_migration_cyclesCumulative migration cycles
slifecycle_last_runSeconds since the last migration cycle started (build-gated, BanyanDB #1167+)
Statuslifecycle_last_run_successLast cycle status (1 = OK, 0 = failed; build-gated, BanyanDB #1167+)

Endpoint scope — per group (meter_banyandb_endpoint_*)

A group carries exactly one data-model type, and each type emits a different family namespace, so the endpoint rules are type-separated by name prefix (measure_* / stream_* / stream_tst_* / trace_* / property_*). The previous design summed measure + stream + trace into one unified rule per concept, which (a) rendered all-empty panels for a property group and (b) silently dropped the trace inverted index from series_* / total_series. The per-type split makes each rule read only the families its type genuinely emits, and the UI selects the panel set by the group's data type.

The queue / publish metrics stay type-agnostic (keyed on group + operation, not on a data-model type) and keep their bare names.

Measure (measure_*):

UnitMetricDescription
w/smeasure_write_rateWrite rate for the group
smeasure_query_latencyMean query latency for the group
Countmeasure_total_dataTotal stored data elements for the group
o/smeasure_merge_file_rateMerge-loop rate for the group
smeasure_merge_file_latencyAvg file-merge latency for the group
Countmeasure_merge_file_partitionsAvg parts merged per loop (file path) for the group
o/smeasure_series_write_rateInverted-index write rate for the group
o/smeasure_series_term_search_rateInverted-index term-search rate for the group
Countmeasure_total_seriesInverted-index documents for the group

Stream (stream_* for the storage scope, stream_tst_* for the time-series-table scope):

UnitMetricDescription
w/sstream_write_rateWrite rate for the group
sstream_query_latencyMean query latency for the group
Countstream_total_dataTotal stored data elements for the group
o/sstream_merge_file_rateMerge-loop rate for the group
sstream_merge_file_latencyAvg file-merge latency for the group
Countstream_merge_file_partitionsAvg parts merged per loop (file path) for the group
o/sstream_series_write_rateStorage-scope inverted-index write rate for the group
o/sstream_series_term_search_rateStorage-scope inverted-index term-search rate for the group
Countstream_total_seriesStorage-scope inverted-index documents for the group
o/sstream_tst_index_write_rateTst-scope inverted-index write rate for the group
Countstream_tst_total_seriesTst-scope inverted-index documents for the group

Trace (trace_*):

UnitMetricDescription
w/strace_write_rateWrite rate for the group
strace_query_latencyMean query latency for the group
Counttrace_total_dataTotal stored data elements for the group
o/strace_merge_file_rateMerge-loop rate for the group
strace_merge_file_latencyAvg file-merge latency for the group
Counttrace_merge_file_partitionsAvg parts merged per loop (file path) for the group
o/strace_series_write_rateStorage-scope inverted-index write rate for the group
o/strace_series_term_search_rateStorage-scope inverted-index term-search rate for the group
Counttrace_total_seriesStorage-scope inverted-index documents for the group

Property (property_*; the new data type — sw_property groups previously rendered all-empty panels and now have their own metrics):

UnitMetricDescription
o/sproperty_index_write_rateInverted-index update rate (property "writes" are index updates)
o/sproperty_index_merge_rateInverted-index segment merge rate
sproperty_index_merge_latencyMean inverted-index merge latency
o/sproperty_series_term_search_rateTerm-search rate (property's real read-load signal — read via the registry/term-search path, not the liaison query method)
Countproperty_total_seriesInverted-index documents for the group

Property has no *_total_written, no tst table and no storage scope: write_rate / query_latency / total_data are genuinely N/A for property and are not modeled — property_index_* / property_series_term_search_rate carry the equivalent write and read load instead.

Queue / publish (type-agnostic; keyed on group + operation):

UnitMetricDescription
opsqueue_throughputSubscribe-queue throughput by operation for the group
squeue_latency_p99Publish-queue latency p99 for the group
opsqueue_batch_throughputSubscribe-queue batch throughput by operation for the group (BanyanDB #1169)
opsqueue_message_throughputSubscribe-queue per-message throughput by operation for the group (BanyanDB #1169)
Bytes/spublish_bytesPublish bytes for the group

Instance-relation scope — deployment topology (meter_banyandb_instance_relation_*)

The intra-cluster instance topology (the Horizon UI deployment component) models the pod-to-pod flows within the single BanyanDB cluster service — the OAP-native equivalent of BanyanDB's Grafana "Topology: Pod-to-Pod Flows" view. Source and destination service are both the cluster, so the UI reads these edges via a symmetric, same-service getServiceInstanceTopology(svc, svc) query; the Analyzer emits the ServiceInstanceRelation server/client-side rows the deployment graph draws.

Each edge is detected from both ends (client + server resolve to the same relation id and share one edge entity), and every per-edge metric keeps operation as a label so the dashboard can split per operation. There are three edge kinds:

  • Publish (publish_*, CLIENT side — the liaison fans writes/queries out across the cluster; the SUB side below is the same edge's SERVER half).
  • Queue-sub (queue_sub_*, SERVER side — a node subscribes from its peers; the remote_role=lifecycle slice is the migration edge's SERVER half).
  • Migration (migration_*, CLIENT side — the lifecycle sidecar publishes migrated data to the next tier hot → warm → cold).

Each edge kind carries the same four facets:

SuffixUnitDescription
_throughputmsg/sPer-second rate of finished operations on the edge
_latency_p99msp99 latency on the edge
_error_throughputerr/sPer-second rate of errors on the edge
_bytes_throughputB/sPer-second bytes sent / received on the edge
MetricDescription
publish_throughput / publish_latency_p99 / publish_error_throughput / publish_bytes_throughputLiaison publish (CLIENT) edge metrics
queue_sub_throughput / queue_sub_latency_p99 / queue_sub_error_throughput / queue_sub_bytes_throughputPeer subscribe (SERVER) edge metrics
migration_throughput / migration_latency_p99 / migration_error_throughput / migration_bytes_throughputLifecycle migration (CLIENT) edge metrics

The lifecycle's last-migration timestamp and status are not modeled as edge metrics (they are label-less per-instance gauges with no destination labels); they stay instance-scope as lifecycle_last_run / lifecycle_last_run_success / lifecycle_migration_cycles. The migration traffic (throughput / latency / error / bytes) above is already per-edge.

Customizations

You can customize your own metrics / expressions. The metric definitions and expression rules are in /config/otel-rules/banyandb. The dashboard panel configurations ship from the SkyWalking Horizon UI bundle (apache/skywalking-horizon-ui); the OAP backend does not host UI dashboard JSONs.