-
Notifications
You must be signed in to change notification settings - Fork 51
docs(function-autoscaler): add function autoscaler docs for self-hosted #1020
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,35 @@ | ||
| # Function Autoscaler Architecture | ||
|
|
||
| The function autoscaler is a Rust service deployed as a horizontally scaled Kubernetes Deployment. It reads utilization and request metrics from a Prometheus-compatible timeseries database, stores discovered functions and coordination state in Cassandra, and writes desired instance counts to the NVCF API. Cassandra lightweight transactions handle leader election and short-lived per-function locks. | ||
| The Function Autoscaler runs as a Kubernetes Deployment in the control-plane | ||
| cluster. It reads metrics from a PromQL-compatible backend, stores coordination | ||
| state in Cassandra, and writes desired instance counts to the NVCF API. | ||
|
|
||
| The work is split into two loops. A leader-elected discovery loop scans the timeseries database for active function versions and upserts them into Cassandra. A scaling loop runs on every replica, but each replica only handles the functions whose IDs hash into its assigned buckets, so the active set is sharded across replicas. | ||
| The work is split into two loops. A leader-elected discovery loop scans the | ||
| timeseries database for active function versions and upserts them into | ||
| Cassandra. A scaling loop runs on every replica, but each replica only handles | ||
| the functions whose IDs hash into its assigned buckets, so the active set is | ||
| sharded across replicas. | ||
|
|
||
| ## Sequence Diagram | ||
|
|
||
| ```mermaid | ||
| sequenceDiagram | ||
| participant Workers as Workers / Invocation Services | ||
| participant TSDB as Time Series DB | ||
| participant Services as NVCF metrics endpoints | ||
| participant Collector as OpenTelemetry Collector | ||
| participant TSDB as Metrics backend | ||
| participant Autoscaler as Function Autoscaler | ||
| participant Cassandra as Cassandra | ||
| participant NVCF as NVCF Service | ||
|
|
||
| Workers->>TSDB: Emit utilization and instance metrics | ||
| Collector->>Services: Scrape selected metrics | ||
| Collector->>TSDB: Remote write | ||
|
|
||
| Note over Autoscaler,Cassandra: Discovery loop (~15s, leader-elected) | ||
| Note over Autoscaler,Cassandra: Periodic discovery loop, leader-elected | ||
| Autoscaler->>TSDB: Query active functions | ||
| TSDB-->>Autoscaler: Function set | ||
| Autoscaler->>Cassandra: Upsert newly discovered functions | ||
|
|
||
| Note over Autoscaler,NVCF: Scaling loop (~30s, per-bucket) | ||
| Note over Autoscaler,NVCF: Periodic scaling loop, per-bucket | ||
| Autoscaler->>Cassandra: Read active functions for this node's buckets | ||
| Autoscaler->>TSDB: Query current instances and utilization history | ||
| TSDB-->>Autoscaler: Metrics | ||
|
|
@@ -32,22 +40,52 @@ sequenceDiagram | |
| Autoscaler->>Cassandra: Write predicted count, refresh function TTL | ||
| ``` | ||
|
|
||
| The discovery loop runs on one leader-elected replica. The scaling loop runs on every replica, but each replica only processes the function buckets assigned to it. | ||
| The discovery loop runs on one leader-elected replica. The scaling loop runs on | ||
| every replica, but each replica only processes its assigned function buckets. | ||
|
|
||
| ## Timeseries Database | ||
| ## Deployment order | ||
|
|
||
| The function autoscaler is a read-only client of a Prometheus-compatible timeseries store. It calls the `/api/v1/query_range` HTTP endpoint and uses PromQL for every metric query, so any backend that implements that interface works: upstream Prometheus, Thanos, Grafana Mimir, or VictoriaMetrics. The reference NVCF deployments point at VictoriaMetrics via the `timeseries_db_url` setting. | ||
| With the default `control` profile, the observability stage installs Prometheus | ||
| Operator CRDs, the OpenTelemetry Operator, an OpenTelemetry Collector with | ||
| Target Allocator and discovery RBAC, control-plane monitors, and VictoriaMetrics. | ||
| The final stage installs State Metrics, then the Function Autoscaler. State | ||
| Metrics is the autoscaler's install-order dependency. At runtime, the autoscaler | ||
| also requires Cassandra, the NVCF API, and a reachable PromQL backend. | ||
|
|
||
| The function autoscaler does not run a scrape config of its own and does not write samples. Before it can do anything useful, the rest of the data plane has to be feeding the same store: | ||
| The shared metrics stage is skipped for `disabled`. The Function Autoscaler is | ||
| installed only for `control` and `all`. | ||
|
|
||
| - Worker pods export utilization and instance count metrics (`nvcf_worker_service_worker_thread_busy_seconds_total`, `nvcf_worker_service_worker_thread_count_total`, instance gauges). | ||
| - Invocation services and the gRPC proxy export request counters (`function_request`, `function_request_total`) labeled by `function_id`, `function_version_id`, and `nca_id`. These labels are how the discovery loop finds active function versions. | ||
| ## Metrics backend | ||
|
|
||
| For a self-hosted control plane, you need three things in place before bringing the function autoscaler online: | ||
| The autoscaler is a read-only client of a PromQL-compatible backend. It uses | ||
| range queries to discover active functions and read instance, request, and | ||
| utilization metrics. | ||
|
|
||
| 1. A Prometheus-compatible store reachable from the function autoscaler pod. | ||
| 2. A scrape configuration (or remote-write feed) covering the worker pods and the invocation-plane services. | ||
| 3. The resulting query endpoint passed in as `timeseries_db_url`. The function autoscaler reports `not ready` on its readiness probe until that endpoint responds. | ||
| The autoscaler does not scrape metrics. It selects a metric source for each | ||
| function, and the metrics for that source must reach the backend that it | ||
| queries. The sources are alternatives, not a single required set: | ||
|
|
||
| | Metric source | Inputs | | ||
| | --- | --- | | ||
| | Worker threads | Worker thread count and busy time, plus invocation activity | | ||
| | LLM API Gateway | Request count and duration, plus State Metrics instance, concurrency, and function metadata | | ||
| | Control plane | Request latency and activity, plus State Metrics instance and concurrency data | | ||
|
|
||
| If worker metrics are unavailable, the autoscaler can use LLM Gateway or | ||
| control-plane metrics when the required inputs are present. | ||
|
Comment on lines
+64
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n -C 6 \
'worker|LLM|Gateway|control.?plane|fallback|metric.?source|PromQL' \
--glob '!docs/**' \
.Repository: NVIDIA/nvcf Length of output: 50368 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== candidate paths =='
git ls-files | rg -i 'autoscal|scal|metric|promql' | rg -v '(^|/)(vendor|third_party|node_modules|dist|build)(/|$)' | head -n 300
printf '%s\n' '== targeted source references =='
rg -n -i \
'worker threads|worker.?thread|llm.?api|llm.?gateway|control.?plane|metric.?source|fallback|promql' \
--glob '!docs/**' \
--glob '!**/vendor/**' \
--glob '!**/third_party/**' \
--glob '!**/node_modules/**' \
--glob '!**/*_test.go' \
--glob '!**/*.test.*' \
--glob '!**/*.spec.*' \
. | head -n 500
printf '%s\n' '== targeted tests =='
rg -n -i \
'worker.?thread|llm.?gateway|control.?plane|metric.?source|fallback|promql|autoscal' \
--glob '!**/vendor/**' \
--glob '!**/third_party/**' \
--glob '!**/node_modules/**' \
--glob '*_test.go' \
--glob '*.test.*' \
--glob '*.spec.*' \
. | head -n 500Repository: NVIDIA/nvcf Length of output: 50368 🏁 Script executed: #!/bin/bash
set -euo pipefail
root='src/control-plane-services/function-autoscaler'
printf '%s\n' '== module outline =='
ast-grep outline "$root/crates/server/src" | head -n 300
printf '%s\n' '== implementation references =='
rg -n -i \
'worker.?thread|llm.?api|llm.?gateway|control.?plane|metric.?source|fallback|promql|query' \
"$root/crates/server/src" \
--glob '!**/vendor/**' \
--glob '!**/target/**' \
| head -n 1000
printf '%s\n' '== tests and test-like references =='
rg -n -i \
'worker.?thread|llm.?api|llm.?gateway|control.?plane|metric.?source|fallback|promql|query|autoscal' \
"$root" \
--glob '*test*' \
--glob '*.rs' \
--glob '!**/vendor/**' \
--glob '!**/target/**' \
| head -n 1000Repository: NVIDIA/nvcf Length of output: 50368 🏁 Script executed: #!/bin/bash
set -euo pipefail
work='src/control-plane-services/function-autoscaler/crates/server/src/work/mod.rs'
scaling='src/control-plane-services/function-autoscaler/crates/server/src/scaling/mod.rs'
printf '%s\n' '== metric source and scaling input definitions =='
sed -n '1,230p' "$scaling"
sed -n '1,230p' "$work"
printf '%s\n' '== presence queries and selector =='
sed -n '320,720p' "$work"
printf '%s\n' '== routing and fallback tests =='
sed -n '1320,1560p' "$work"Repository: NVIDIA/nvcf Length of output: 40153 🏁 Script executed: #!/bin/bash
set -euo pipefail
doc='docs/user/autoscaling/architecture.md'
work='src/control-plane-services/function-autoscaler/crates/server/src/work/mod.rs'
printf '%s\n' '== architecture documentation =='
sed -n '55,90p' "$doc"
printf '%s\n' '== selector-adjacent tests and error branches =='
rg -n -C 4 \
'worker count failed|falls back|fallback|cached_source|MetricSource::WorkerThreads|query.*error|with_status\(5|with_status\(50' \
"$work" \
--glob '*.rs' | head -n 500
printf '%s\n' '== read-only selector invariant check =='
python3 - "$work" <<'PY'
from pathlib import Path
import re
import sys
text = Path(sys.argv[1]).read_text()
start = text.index("async fn gather_scaling_inputs")
end = text.index("\n// Function that creates or removes", start)
selector = text[start:end]
checks = {
"default source is WorkerThreads": "cached_source.unwrap_or(MetricSource::WorkerThreads)" in selector,
"fallback is gated on uncached source": "Ok(None) if cached_source.is_none()" in selector,
"gateway presence query precedes gateway selection": selector.index("llm_gateway_metrics_present") < selector.index("get_gateway_target"),
"gateway presence uses request counter": "llm_api_gateway_http_requests_total" in text[text.index("async fn llm_gateway_metrics_present"):text.index("fn select_gateway_target")],
"worker query errors retain WorkerThreads": "cache_source = false" in selector and "metric_source = MetricSource::WorkerThreads" not in selector[selector.index("Err(error)"):],
"initial control-plane fallback exists": "MetricSource::ControlPlane" in selector,
}
for name, ok in checks.items():
print(f"{'PASS' if ok else 'FAIL'}: {name}")
if not all(checks.values()):
raise SystemExit(1)
PYRepository: NVIDIA/nvcf Length of output: 5488 Narrow the fallback wording The autoscaler falls back only when the initial worker-count query returns no series. It does not fall back after a worker query error or after a cached worker source returns no series. Document these conditions or add handling and tests for them. 🤖 Prompt for AI Agents |
||
|
|
||
| For a split deployment, the compute-plane profile enables the NVCA collector but | ||
| does not automatically route worker metrics to the control-plane backend. | ||
| Configure the compute-plane exporter to send worker metrics to the backend | ||
| queried by the autoscaler, or use a backend reachable from both planes. See | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we actually even be recommending this "configure the compute plane exporter to send worker metrics to the backend" does that actually work, what is the compute plane exporter |
||
| [Cluster Monitoring](../cluster-management/monitoring.md) for compute-plane | ||
| metrics endpoints. | ||
|
|
||
| The backend can be bundled VictoriaMetrics or an existing PromQL-compatible | ||
| service. See [Observability Configuration](../observability.md) for backend, | ||
| endpoint, and authentication settings. | ||
|
|
||
| The autoscaler reports `not ready` until the query endpoint responds. | ||
|
|
||
| ## Coordination and Self-Healing | ||
|
|
||
|
|
@@ -62,3 +100,4 @@ Coordination relies on Cassandra TTLs to recover from failures without operator | |
| - [Configure Autoscaling](../configure-autoscaling.md) for setting per-function scaling bounds, factors, thresholds, and stickiness via the NVCF API. | ||
| - [Function Autoscaler Operations](./operations.md) for health endpoints and common issues. | ||
| - [Function Autoscaler Observability](./observability.md) for emitted metrics, traces, and logs. | ||
| - [Observability Configuration](../observability.md) for profiles and metrics backend settings. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,37 +1,55 @@ | ||
| # Function Autoscaling | ||
|
|
||
| The NVCF Function Autoscaler is a distributed Rust service that monitors function utilization and uses it to determine the ideal instance count per function on the NVCF control plane. It runs as a horizontally scaled deployment on the same Kubernetes cluster as the rest of the control plane. | ||
|
|
||
| On an interval, the function autoscaler reads metrics from the timeseries database, decides how many instances each function should have, and calls the NVCF API to apply that decision. | ||
|
|
||
| The function autoscaler depends on a Prometheus-compatible timeseries database fed by the worker pods and invocation-plane services. Without it, the service reports `not ready` and makes no scaling decisions. See [Timeseries database](./architecture.md#timeseries-database) for the required metrics and endpoints. | ||
| The NVCF Function Autoscaler reads function metrics, calculates a desired | ||
| instance count, and sends that count to the NVCF API. It runs in the | ||
| self-hosted control-plane cluster. | ||
|
|
||
| ## Function Autoscaler vs Horizontal Pod Autoscaler | ||
|
|
||
| Function autoscaling is distinct from Kubernetes horizontal pod autoscaling (HPA). HPA scales pods within a single cluster, so it cannot reach NVCF worker pods that are spread across multiple clusters. Function autoscaling orchestrates scaling across clusters using global load patterns. | ||
| Function autoscaling is distinct from Kubernetes horizontal pod autoscaling | ||
| (HPA). HPA scales a Kubernetes workload in one cluster. The Function | ||
| Autoscaler sets the desired instance count for an NVCF function version, which | ||
| can run across NVCF compute clusters. | ||
|
|
||
| ## Key Functionality | ||
|
|
||
| - Discovers active functions from invocation and worker metrics in the timeseries database and persists the active set in Cassandra. | ||
| - Periodically computes a desired instance count per function from recent utilization and the function's scaling policy. | ||
| - Discovers active functions from invocation and worker metrics in the | ||
| timeseries database and persists the active set in Cassandra. | ||
| - Periodically computes a desired instance count per function from recent | ||
| utilization and the function's scaling policy. | ||
| - Applies the desired count by calling the NVCF API's predictions endpoint. | ||
| - Coordinates work across replicas using hash-based bucket assignment and Cassandra Lightweight Transaction (LWT) distributed locks. | ||
| - Coordinates work across replicas using hash-based bucket assignment and | ||
| Cassandra lightweight transaction (LWT) locks. | ||
|
|
||
| ## Self-hosted deployment | ||
|
|
||
| The self-managed control-plane stack defaults to the `control` observability | ||
| profile. The `control` and `all` profiles install the Function Autoscaler. The | ||
| `compute` and `disabled` profiles do not. | ||
|
|
||
| State Metrics must be enabled for `control` and `all`. With the default | ||
| component modes, the control-plane stack also installs the shared collector and | ||
| VictoriaMetrics. See [Observability Configuration](../observability.md) for | ||
| profile and backend settings. | ||
|
|
||
| ## Architecture Overview | ||
|
|
||
| ```mermaid | ||
| flowchart LR | ||
| Workers[Workers / Invocation Services] --> TSDB[(Time Series DB)] | ||
| Services[Metrics endpoints] --> Collector[OpenTelemetry Collector] | ||
| Collector --> TSDB[(VictoriaMetrics or external backend)] | ||
| TSDB --> Autoscaler[Function Autoscaler] | ||
| Autoscaler <--> Cassandra[(Cassandra)] | ||
| Autoscaler --> NVCF[NVCF API] | ||
| ``` | ||
|
|
||
| See [Architecture](./architecture.md#sequence-diagram) for the end-to-end sequence diagram and the bucket model. | ||
| See [Architecture](./architecture.md#sequence-diagram) for the end-to-end | ||
| sequence and bucket model. | ||
|
|
||
| ## See Also | ||
|
|
||
| - [Architecture](./architecture.md) for components, data flow, and the Cassandra LWT lock behavior that elects the discovery leader. | ||
| - [Configure Autoscaling](../configure-autoscaling.md) for setting per-function scaling bounds, factors, thresholds, and stickiness via the NVCF API. | ||
| - [Function Autoscaler Operations](./operations.md) for health endpoints and operational guidance. | ||
| - [Function Autoscaler Observability](./observability.md) for the metrics, traces, and logs emitted by the service. | ||
| - [Observability Configuration](../observability.md) for profiles and metrics backend configuration. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,14 @@ | ||
| # Function Autoscaler Observability | ||
|
|
||
| The function autoscaler emits structured logs, Prometheus metrics that explain dependency health statuses and scaling decisions, and OpenTelemetry spans for outbound calls to its dependencies. The Prometheus exporter serves metrics on the address configured in `server.metrics.exporters`. The local settings file at `crates/server/resources/settings-local.yaml` uses `0.0.0.0:41338`. | ||
| The Function Autoscaler emits structured logs, Prometheus metrics, and | ||
| OpenTelemetry spans. The chart exposes its Prometheus exporter through the | ||
| `function-autoscaler` service on the `metrics` port, which defaults to `41338`. | ||
| The shared stack's default monitors do not include this service. Add a monitor | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The default monitors should include this service - can you file a follow up issue for this. |
||
| or scrape target for it to collect these metrics. | ||
|
|
||
| Job and namespace labels follow the standard NVCF naming convention for the cluster that runs the function autoscaler. | ||
| These service metrics describe the autoscaler itself. They are separate from | ||
| the function metrics that the autoscaler reads from VictoriaMetrics or an | ||
| external backend. | ||
|
|
||
| ## Metric reference | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,65 +1,73 @@ | ||
| # Function Autoscaler Operations | ||
|
|
||
| This page covers operating the function autoscaler after deployment, including health probes, common operational issues, and pointers to the Helm chart values. For log filter syntax, metrics, and traces, see [Function Autoscaler Observability](./observability.md). | ||
| The self-managed stack deploys the Function Autoscaler for the `control` and | ||
| `all` observability profiles. State Metrics must remain enabled for both. See | ||
| [Observability Configuration](../observability.md) for profile and metrics | ||
| backend settings. | ||
|
|
||
| ## Health endpoints | ||
|
|
||
| The function autoscaler exposes three HTTP health endpoints. Their exact paths differ from the rest of the NVCF control plane: liveness and readiness are namespaced under `/admin/health/`. | ||
|
|
||
| | Endpoint | Purpose | Use as | | ||
| |----------|---------|--------| | ||
| | `GET /admin/health/liveness` | Always returns 200. Indicates the process is alive. | Kubernetes liveness probe. | | ||
| | `GET /admin/health/readiness` | Returns 200 when all components are healthy, 503 otherwise. | Kubernetes readiness probe. | | ||
| | `GET /health` | Returns per-component health for `cassandra_client` and `timeseries_db_client`. | Operator-facing detail and dashboards. | | ||
|
|
||
| The liveness probe deliberately does not check Cassandra or the timeseries database. Restarting the pod when those are unreachable does not help, so the function autoscaler stays running and lets readiness flip instead. | ||
| Apply an environment change from the self-managed stack directory: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. apply what change? Why is this here |
||
|
|
||
| ## Common operational issues | ||
| ```bash | ||
| make apply HELMFILE_ENV=<environment-name> | ||
| ``` | ||
|
|
||
| ### Cassandra connection failures | ||
| ## Verify the deployment | ||
|
|
||
| Symptoms: readiness flips to 503, `/health` reports the `cassandra_client` component as unhealthy, log lines from `rs_autoscaler::cassandra` show connection errors. | ||
| Check State Metrics and the Function Autoscaler: | ||
|
|
||
| Checks: | ||
| ```bash | ||
| kubectl get deployment -n nvcf \ | ||
| -l app.kubernetes.io/instance=state-metrics | ||
| kubectl get deployment -n nvcf \ | ||
| -l app.kubernetes.io/instance=function-autoscaler | ||
| kubectl rollout status deployment/function-autoscaler -n nvcf | ||
| ``` | ||
|
|
||
| - SSL certificates are mounted at the path expected by `cassandra.ssl`. The function autoscaler container expects the cert directory to exist; create `/etc/app/config` if it is missing. | ||
| - Credentials in the secrets file are valid for the configured keyspace. | ||
| - The contact points resolve from the pod's network namespace. | ||
| Confirm the resolved PromQL endpoint. This ConfigMap does not contain the | ||
| backend credentials: | ||
|
|
||
| ### Timeseries database query failures | ||
| ```bash | ||
| kubectl get configmap -n nvcf function-autoscaler-env \ | ||
| -o jsonpath='{.data.TIMESERIES_DB__TIMESERIES_DB_URL}{"\n"}' | ||
| ``` | ||
|
|
||
| Symptoms: `nvcf_autoscaler.timeseries_db.requests_total` shows a rising error count, `auth_failure_total` or `server_side_failure_total` is non-zero, log lines from `rs_autoscaler::timeseries_db` show 4xx or 5xx responses. | ||
| For the bundled backend, the result should point to `vmsingle` in the | ||
| configured monitoring namespace. For an existing backend, it should match | ||
| `metricsBackend.promqlEndpoint`. | ||
|
|
||
| Checks: | ||
|
|
||
| - `timeseries_db.timeseries_db_url` is reachable from the pod. | ||
| - The bearer token in the secrets file is current. Token rotation is the most common cause of `auth_failure_total` spikes. | ||
| - Query time ranges fit the retention window of the backing store. | ||
|
|
||
| ### NVCF API errors | ||
|
|
||
| Symptoms: `nvcf_autoscaler.nvcf_api.request_duration_milliseconds` shows a sustained rise in 4xx or 5xx, scaling decisions stop applying. | ||
| ## Health endpoints | ||
|
|
||
| Checks: | ||
| The Function Autoscaler exposes three health endpoints: | ||
|
|
||
| - The OAuth2 token endpoint is reachable and the client credentials in the secrets file are valid. | ||
| - The functions being scaled are still in a deployable status. Functions in unexpected states are skipped, not retried. | ||
| - `nvcf_api.disable_auth` is set as intended for the deployment. Leave it `false` whenever the NVCF API enforces authentication. | ||
| | Endpoint | Purpose | Use as | | ||
| | --- | --- | --- | | ||
| | `GET /admin/health/liveness` | Always returns 200. Indicates the process is alive. | Kubernetes liveness probe. | | ||
| | `GET /admin/health/readiness` | Returns 200 when all components are healthy, 503 otherwise. | Kubernetes readiness probe. | | ||
| | `GET /health` | Returns per-component health for `cassandra_client` and `timeseries_db_client`. | Operator-facing detail and dashboards. | | ||
|
|
||
| ### Discovery is stalled | ||
| Inspect the detailed endpoint through the service: | ||
|
|
||
| Symptoms: the active function set in Cassandra stops growing despite traffic to new functions, `nvcf_autoscaler.distributed_lock.acquisition_failures_total` is rising across all replicas. | ||
| ```bash | ||
| kubectl port-forward -n nvcf service/function-autoscaler 8181:8181 | ||
| curl http://127.0.0.1:8181/health | ||
| ``` | ||
|
|
||
| Checks: | ||
| The liveness probe does not check Cassandra or the metrics backend. Dependency | ||
| failures change readiness instead. | ||
|
|
||
| - Inspect the `locks` table for the discovery lock row and its TTL. If the row never expires, the previous leader may have stopped refreshing without releasing it. | ||
| - Confirm at least one replica's `nvcf_autoscaler.distributed_lock` gauge reports the leader state. | ||
| - Restart the holding replica if the cluster is otherwise healthy. The lock expires within `discovery_lock_duration_seconds`. | ||
| ## Troubleshooting | ||
|
|
||
| See [Architecture](./architecture.md#cassandra-lightweight-transactions-lwts) for the lock state machine. | ||
| | Symptom | Check | | ||
| | --- | --- | | ||
| | Function Autoscaler is not installed | Use the `control` or `all` profile. Keep `stateMetrics.enabled: true`. | | ||
| | `cassandra_client` is unhealthy | Check contact-point DNS, credentials, and the configured TLS files. | | ||
| | `timeseries_db_client` is unhealthy | Check the resolved PromQL endpoint, authentication mode, credentials, and backend retention. | | ||
| | Scaling decisions are not applied | Check NVCF API authentication and function status. | | ||
| | Discovery does not find active functions | Confirm the backend contains the request and worker metrics listed in [Architecture](./architecture.md#metrics-backend). Check the discovery lock metrics and TTL. | | ||
|
|
||
| ## See also | ||
|
|
||
| - [Function Autoscaler Observability](./observability.md) for the metrics and traces referenced in the symptoms above. | ||
| - [Configure Autoscaling](../configure-autoscaling.md) for setting per-function scaling bounds and policy via the NVCF API. | ||
| - [Architecture](./architecture.md) for the component layout these symptoms map to. | ||
| - [Observability Configuration](../observability.md) for shared stack settings. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the shared metrics stage. I think this deployment order section is too many details and we should drop it. Instead link from this doc to the installation instructions page?