
Alibabacloud Elasticsearch Instance Diagnose
- 118 installs
- 208 repo stars
- Updated August 4, 2026
- aliyun/alibabacloud-aiops-skills
alibabacloud-elasticsearch-instance-diagnose is a Claude skill that diagnoses Alibaba Cloud Elasticsearch cluster health and incidents by combining OpenAPI, CloudMonitor, and ES REST API signals.
About
This skill diagnoses Alibaba Cloud Elasticsearch instances for cluster health checks, troubleshooting, and performance analysis. It collects signals from the Alibaba Cloud OpenAPI control plane, CloudMonitor, and the Elasticsearch REST API, then produces root-cause analysis with an evidence chain and prioritized remediation. A developer uses it for red/yellow clusters, unassigned shards, slow searches, write failures, and OOM.
- Diagnoses Alibaba Cloud Elasticsearch cluster health and incidents
- Combines OpenAPI control-plane, CloudMonitor, and ES REST API signals
- Produces root-cause analysis, evidence chain, and remediation guidance
Alibabacloud Elasticsearch Instance Diagnose by the numbers
- 118 all-time installs (skills.sh)
- Ranked #306 of 911 Databases skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
alibabacloud-elasticsearch-instance-diagnose capabilities & compatibility
Requires Alibaba Cloud credentials; diagnostic calls are read-only
- Capabilities
- debugging · database · data analysis
- Works with
- aws · elasticsearch
- Use cases
- debugging · database · data analysis
- Runs
- Runs locally
- Pricing
- Bring your own API key
What alibabacloud-elasticsearch-instance-diagnose says it does
Alibaba Cloud Elasticsearch instance diagnosis skill. Use for cluster health checks, troubleshooting, and performance analysis on Elasticsearch instances.
npx skills add https://github.com/aliyun/alibabacloud-aiops-skills --skill alibabacloud-elasticsearch-instance-diagnoseAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 118 |
|---|---|
| repo stars | ★ 208 |
| Last updated | August 4, 2026 |
| Repository | aliyun/alibabacloud-aiops-skills ↗ |
What it does
Diagnose Alibaba Cloud Elasticsearch cluster health, slow searches, write failures, and shard issues.
Who is it for?
Root-causing Alibaba Cloud Elasticsearch cluster issues like red/yellow status, shard problems, and OOM
Skip if: Elasticsearch instance lifecycle changes or non-Elasticsearch products
When should I use this skill?
An Alibaba Cloud Elasticsearch cluster is red/yellow, has unassigned shards, slow searches, write failures, or OOM
What you get
Produces a root-cause analysis, evidence chain, and prioritized remediation for the Elasticsearch incident.
- Root-cause analysis with evidence chain
- Prioritized remediation guidance and incident timeline
By the numbers
- 6 issue-type triggers
- combines control-plane and data-plane signal sources
Files
Alibaba Cloud Elasticsearch Instance Diagnosis
Collect signals from Alibaba Cloud OpenAPI (control plane) and the Elasticsearch REST API (data plane), combine them with the SOP knowledge base under references/, and produce root-cause analysis, an evidence chain, prioritized remediation guidance, and—when multiple dimensions fire—a recency-ordered incident timeline (severity vs time in window; see Timeline and recency (MUST) in §5 Step 4).
Architecture: Alibaba Cloud Elasticsearch OpenAPI + Alibaba CloudMonitor (CMS) + Elasticsearch REST API + diagnostic SOPs
Closure: If MUST applies and ES_* is set, finish authenticated ES API evidence before the final report (see Feasibility order in §5).
---
1. Prerequisites
1.1 Aliyun CLI
Pre-check: Aliyun CLI >= 3.3.1 required (for RAM permission checks and OpenAPI CLI fallback)
Runaliyun versionto verify the version is >= 3.3.1. If the CLI is missing or too old, seereferences/cli-installation-guide.md.
After installation, run aliyun configure set --auto-plugin-install true to enable automatic plugin installation (do not pass plaintext AccessKey pairs on this command line; see §1.2).1.2 Alibaba Cloud account authentication and security (MUST)
Security rules (mandatory):
- NEVER read, echo, or print AccessKey ID or AccessKey Secret values.
- NEVER prompt or ask the user to paste plaintext AccessKeys in the conversation.
- NEVER embed AccessKeys in scripts, CLI arguments, or curl URLs.- NEVER use aliyun configure set (or similar) to pass literal AccessKey ID/Secret on the command line.- NEVER accept AccessKeys that the user pastes into the chat, even if offered voluntarily.
- ONLY use configured CLI profiles (aliyun configure) or environment variables such asALIBABA_CLOUD_ACCESS_KEY_ID/ALIBABA_CLOUD_ACCESS_KEY_SECRETthat the user has set in their local shell (the agent must not echo those values in the session).
⚠️ If the user provides AccessKeys in the chat (e.g. “my AK is xxx”)
>
1. Stop immediately: do not run any Alibaba Cloud command that requires credentials.
2. Decline politely and give only the names of approved configuration methods (do not repeat any secret the user may have leaked):
- Recommended: run aliyun configure in a local terminal and enter credentials when prompted; credentials are stored in the local profile file.- Alternatively: setALIBABA_CLOUD_ACCESS_KEY_ID/ALIBABA_CLOUD_ACCESS_KEY_SECRETin the local shell (the user types values only in the terminal, not in chat).
3. Resume the diagnosis request only after credentials are configured correctly.
Verify credentials without exposing secrets:
>
```bash
aliyun configure list
aliyun --profile <profile_name> sts get-caller-identity
```
>
Credential policy:
1. Prefer analiyun configureprofile (default or--profile).
2. If there is no valid identity (configure list/get-caller-identityfails), STOP and guide the user to configure locally; do not guess or fabricate credentials.
3. Never pass plaintext AccessKeys through the conversation.
1.3 Elasticsearch direct-connect credential boundary
- NEVER ask the user to paste ES_PASSWORD in chat; NEVER echo, print, or log the password; NEVER copy a password from chat into commands, hooks, or repo files.- Shell expansion for curl -u "$ES_USERNAME:$ES_PASSWORD" (or equivalent) is allowed when vars are pre-exported in the user’s local shell; NEVER put the secret as a literal in chat, scripts checked into repos, or command output.- If the user tries to send a password in chat: STOP as well and ask them to setES_PASSWORDonly locally viaexport(see §2.2).
---
2. Environment setup
2.1 Control plane OpenAPI (via Aliyun CLI)
All control-plane and CMS data collection for this skill uses the Aliyun CLI.
[MUST] `elasticsearch` / `cms` — plugin-mode shell only (avoid legacy CLI)
Whenever the agent emits executablealiyunlines (chat, reproducibility exports, or copy-paste steps), use plugin subcommands (lowercase-hyphenated) and kebab-case flags — the same shape asscripts/openapi_cli_collect.pyand references/verification-method.md.
- Do not use legacy POP-style invocations: a PascalCase verb immediately afterelasticsearchorcmson the samealiyunline (the old “action name = subcommand” style), or CamelCase flags like--InstanceId,--Namespace,--StartTimein new commands. Use plugin verbs only (describe-instance,describe-metric-list, …).
- Naming split:DescribeInstance,ListSearchLog,DescribeMetricList, etc. are OpenAPI action names (PascalCase — docs, RAM, console). The token afteraliyun elasticsearchoraliyun cmsin a shell must be the CLI plugin name (describe-instance,list-search-log,describe-metric-list, …).
- Prefer python3 scripts/check_es_instance_health.py for the standard control-plane + CMS bundle so subprocess calls stay aligned with this repo.- CLI references: Elasticsearch CLI 中心, 云监控 CLI 中心.
AI-Mode and plugin baseline (required) — wrap every diagnosis session that runs aliyun OpenAPI/CMS commands:
aliyun configure ai-mode enable
aliyun configure ai-mode set-user-agent --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-elasticsearch-instance-diagnose"
aliyun plugin update
# … diagnosis: aliyun / python3 scripts/check_es_instance_health.py …
aliyun configure ai-mode disable`configure ai-mode` missing or failing: Skip the wrapper above; use `ALIBABA_CLOUD_USER_AGENT` (next block). Log the CLI failure (e.g. subcommand unavailable). Whether the profile is valid is determined only by `aliyun configure list` and `sts get-caller-identity` — write valid / validity, not vaild.
User-Agent (required): set a User-Agent for Alibaba Cloud API calls:
export ALIBABA_CLOUD_USER_AGENT="AlibabaCloud-Agent-Skills/alibabacloud-elasticsearch-instance-diagnose"CLI hardening (recommended): when authoring raw aliyun commands, use §2.1 MUST plugin shape first, then add `--connect-timeout 3 --read-timeout 10` (increase read-timeout for large responses or CMS), consistent with the instance-management skill examples, to avoid indefinite hangs on network faults. If the global User-Agent is not set, add `--user-agent AlibabaCloud-Agent-Skills/alibabacloud-elasticsearch-instance-diagnose` per invocation. For optional Elasticsearch probes inside check_es_instance_health.py (when ES_* is set), the same knobs exist as `--connect-timeout` / `--read-timeout` on that script — they map to curl for engine calls only, not to the Aliyun OpenAPI client.
Run before diagnosis:
aliyun version
aliyun configure list
aliyun --profile <profile_name> sts get-caller-identity2.2 Elasticsearch API direct access (curl)
Have the user set connection variables in a local terminal after you confirm the Elasticsearch endpoint (VPC or public) and admin credentials—do not hardcode user-specific values in chat:
export ES_ENDPOINT="http://<elasticsearch-endpoint-ip>:9200"
export ES_USERNAME="elastic"
export ES_PASSWORD="<elasticsearch-admin-password>"Public access and `http` vs `https`: From `DescribeInstance`, use `publicDomain` / `domain` and the reported `protocol`. When `protocol` is `HTTP` (typical public listener), set `ES_ENDPOINT` to `http://<publicDomain>:9200`. Using `https://` against an HTTP-only endpoint causes TLS errors (e.g. `WRONG_VERSION_NUMBER`). Use `https://` only when `protocol` is `HTTPS` (or TLS is actually enabled on the port you use), and supply CA / fingerprint options as in HTTPS options below.
>
If `http://` “does not work” — when to try `https://`: Treat `DescribeInstance` `protocol` as the source of truth for the REST listener. `000`, timeouts, or connection refused on `http://` usually mean network path / allowlist / security group / wrong host or port — not “try HTTPS next” when `protocol` is still `HTTP`. Do switch to `https://` when `protocol` is `HTTPS` (or the console / product doc states TLS on that endpoint) and the failure on http:// is a TLS or scheme symptom (e.g. `WRONG_VERSION_NUMBER`, `error:0A00010B`, immediate SSL alert while probing with the wrong scheme). If `protocol` is `HTTP` and only plain TCP is advertised, HTTPS is not a fallback for reachability.Credential safety
- NEVER echo, print, or log ES_PASSWORD; NEVER copy credentials from chat into shell history or saved files.- NEVER ask the user to paste the password in plaintext in chat.
- ONLY use the following checks to verify that variables are set:
```bash
[[ -n "$ES_ENDPOINT" ]] && echo "ES_ENDPOINT: $ES_ENDPOINT" || echo "ES_ENDPOINT: NOT SET"
[[ -n "$ES_PASSWORD" ]] && echo "ES_PASSWORD: SET" || echo "ES_PASSWORD: NOT SET"
```
Network connectivity and access control
>
| Issue | How to check | Mitigation |
|------|--------------|------------|
| Public network access disabled | Elasticsearch console → Network | Enable public access or use the VPC endpoint |
| Public access allowlist | Console → Security → Public access allowlist | Add the agent host’s public IP |
| VPC isolation | e.g. telnet <ES_IP> 9200 | VPC peering, Express Connect, or equivalent || Security group | Inbound rules on the ECS/security group hosting Elasticsearch | Allow TCP 9200 (or the configured port) |
Connectivity probe:curl -sS -o /dev/null -w "%{http_code}" --connect-timeout 5 "${ES_ENDPOINT}"— HTTP code000usually means the path is unreachable. `401` without `-u` is normal (auth required); ifES_PASSWORDis SET, proceed to authenticatedGET /_cluster/health(§7). `401` with `-u` → wrong credentials. `000` / refused / timeout → network, allowlist, or TLS/scheme mismatch.
HTTPS — prerequisites (what must be true)
1. Listener: The Elasticsearch HTTP port you call (9200 unless changed) must actually speak TLS — align with `DescribeInstance` `protocol` (`HTTPS`) or console/network documentation.
2. URL: `https://<host>:<port>` with the same host (e.g. `publicDomain`) you would use for HTTP.
3. Client trust of the server certificate: Your client must trust the cluster’s certificate chain (cluster / cloud CA PEM, or corporate proxy CA if TLS is intercepted). `curl`: prefer `curl --cacert /path/to/ca.crt ...`; `-k` / `--insecure` only for short, non-production diagnosis.
4. Auth: Same `ES_USERNAME` / `ES_PASSWORD` as for HTTP (Basic auth over TLS).
>
HTTPS — how this skill documents it
- Manual `curl` (§7 and [es-api-call-failures.md](references/es-api-call-failures.md)): Add `--cacert` (or `-k` for testing) to every `curl` when using `https://` if the default trust store does not include your cluster CA.
- `check_es_instance_health.py` optional ES probes: They invoke `curl` with `-u` only; they do not read `ES_CA_CERTS` / `ES_SSL_FINGERPRINT` / `ES_VERIFY_CERTS` (those names are common for Python Elasticsearch clients). For HTTPS instances, use §7 `curl` with `--cacert` for deep checks, or extend the script later to pass `--cacert` from an env var.
- Python-style env vars (reference for other tooling):ES_CA_CERTS,ES_SSL_FINGERPRINT,ES_VERIFY_CERTS=false(testing only) — not wired into this repo’s optional `curl` path today.
---
3. RAM permission check
[MUST] RAM permission pre-check
>
Before running this skill, verify the principal has the required RAM permissions.
See references/ram-policies.md for the full list.If the user reports insufficient permissions, direct them to attach the corresponding policies in the RAM console.
---
4. Parameter confirmation
IMPORTANT: Parameter confirmation
Confirm the following with the user before any command or API call.
Do not assume undeclared defaults or hardcode user-specific parameters.
Boundary controls (MUST)
- Region and `instance-id` must not be guessed or taken from unverified defaults; if they disagree with DescribeInstance or the user’s explicit statement, reconfirm.- Do not apply metrics, logs, orDescribeInstanceconclusions from instance A to instance B;ES_ENDPOINTmust match the instance under diagnosis (see Pre-flight validation for Elasticsearch API below).
- This skill is read-only diagnosis: do not invoke mutating control-plane APIs (create, resize, restart, delete instance, etc.). If the user requests a change, provide recommendations only; execution belongs in the console or an approved change workflow.
| Parameter | Required | Description | Default |
|---|---|---|---|
instance-id | Yes | Elasticsearch instance ID, e.g. es-cn-xxxxx. `aliyun` flag is `--instance-id` (not --InstanceId). | - |
region | Yes | Region ID (e.g. cn-hangzhou). `aliyun` flag is `--region` (not --region-id). | - |
profile | No | Aliyun CLI profile (explicit --profile recommended) | default |
ES_ENDPOINT | No | Elasticsearch endpoint (direct API access only) | - |
ES_PASSWORD | No | Elasticsearch admin password (direct API access only) | - |
--window | No | check_es_instance_health.py: analysis window in minutes (default 60) | 60 |
--connect-timeout, --read-timeout | No | check_es_instance_health.py: curl timeouts for optional ES engine probes when ES_* is set (--connect-timeout → curl --connect-timeout; `--read-timeout` contributes to `curl -m` together with connect). Defaults 5 / 10 seconds. | 5 / 10 |
---
5. End-to-end diagnostic workflow
Agent hard rules (non-negotiable)
Aliyun CLI shape: For `aliyun elasticsearch` and `aliyun cms`, follow §2.1 MUST (plugin mode only) in every new executable command — do not resurrect legacyDescribeInstance/ListSearchLog-as-subcommand lines or--InstanceId-style flags in session exports or user-facing step lists (they drift fromopenapi_cli_collect.pyand fail static checks).
OpenAPI/CMS cannot replace MUST engine APIs. For any §5 MUST table row or `check_es_instance_health.py` rule-engine MUST, Alibaba Cloud OpenAPI and CloudMonitor do not replace the listed Elasticsearch REST calls for engine-level root cause—when feasibility holds, run those curl endpoints (see §7); they are complementary layers, not interchangeable.>
Feasibility is decided only by checks, not by assumption. Whether the agent may call Elasticsearch must be determined by actually running the Feasibility order (§5): at minimum verifyES_ENDPOINT/ES_PASSWORDper §2.2, alignES_ENDPOINTwithDescribeInstance, then authenticatedGET /_cluster/health. Do not assumeES_*is unset or the path is unreachable without performing these steps in the session.
For Elasticsearch incidents, follow these four steps; each has a distinct role.
Execution strategy (root-cause driven)
Full policy: es-api-diagnosis-strategy.md
Data-plane curl collection requires both:
1. Feasibility: ES_ENDPOINT and ES_PASSWORD are set and the network path works. 2. Necessity: root-cause analysis needs data-plane evidence that the control plane or CMS cannot establish alone.
For endpoints listed under a fired MUST table row or rule-engine MUST, necessity for those calls is already satisfied by the trigger—still require feasibility (Feasibility order). For optional engine curl not in those lists, apply feasibility and necessity per es-api-diagnosis-strategy.md.MUST triggers (if any CMS condition below holds, collect the listed Elasticsearch evidence):
| Trigger | Scenario | Required Elasticsearch evidence |
|---|---|---|
ClusterStatus max ≥ Yellow / Red | Cluster health | allocation/explain, _cat/shards |
NodeCPUUtilization max > 80% | CPU overload | _nodes/hot_threads, _tasks |
NodeHeapMemoryUtilization max > 85% | Memory pressure | _nodes/stats/breaker, GET /_cluster/settings?include_defaults=true ( *`indices.breaker.`** in transient / persistent ) |
Thread pool rejected > 0 | Performance | _nodes/hot_threads, _nodes/stats/thread_pool |
| Inter-node resource CV > 0.3 | Load imbalance | _cat/shards, _cat/allocation |
| Write failures or index read-only | Disk / watermark / blocks | _cluster/settings, _all/_settings?filter_path=*.settings.index.blocks, _cat/allocation |
| Intermittent Elasticsearch API timeouts + CMS CPU > 80% | Possible cascading failure | _nodes/hot_threads, _nodes/stats/thread_pool, _tasks |
Thread-pool row: interpret search vs write / bulk using sop-query-thread-pool.md vs sop-write-performance.md (see also Write-path / bulk saturation below).
Rule-engine MUST: If check_es_instance_health.py prints a §5 MUST / §5–§7 callout for this run, treat it like a row above—collect that listed ES evidence when feasibility holds.Binding rule (MUST triggers): If any MUST-trigger row or the rule-engine MUST line above applies, necessity is satisfied for that evidence set—OpenAPI/CMS cannot replace those calls for engine-level root cause (cluster-health:allocation/explain+_cat/shardsfor Yellow/Red). Confirm feasibility per Feasibility order below. If reachable with auth, run the MUST-listed endpoints in Step 2 in parallel with control-plane collection. If still blocked after authenticatedGET /_cluster/health, lead with blocking reason: unsetES_*; transport failure (000, refused, timeout); 401 with `-u`; scheme/TLS mismatch—not 401 on an unauthenticated probe whenES_PASSWORDis SET.
Write-path / bulk saturation
If `ThreadPool.WriteRejected` or `write` pool stress matches high-QPS bulk indexing, read and follow `references/sop-write-performance.md` — §2, subsection “Evidence interpretation: bulk QPS → write pool” for the evidence chain, `rejected` semantics (cumulative since node start), report ordering vs Old GC / heap (causal chain or dual P0 — write path before JVM-only headline), per-node `rejected`/`completed` numbers (reject share), per-node asymmetry, and write-only vs search. Do not lead with a JVM-only narrative when that subsection applies. For write-queue–style acceptance prompts, the opening conclusion should read as write-capacity (data-plane counters + optional CMS rule names), not only a GC/heap headline.
Search-primary vs write (both pools show cumulative rejected)
When `_nodes/stats/thread_pool` shows `search.rejected` ≫ `write.rejected` on the same node(s) and `ThreadPool.SearchRejected` / query-driven overload applies, lead the executive summary and P0 ordering with `search` (high concurrent query / terms / slow query; hot index when verified) — not `write` first. `write.rejected` may remain P0/P1 as parallel or secondary (bulk, catch-up); Old GC / CPU / node disconnect stay co-stress or cascade. Checker listing order is not proof of narrative order — see acceptance-criteria.md §6.5 and sop-query-thread-pool.md Report narrative.
>
Recency overrides this magnitude default when time-resolved evidence exists: do not rank the opening story by `search.rejected` vs `write.rejected` alone — cumulative counters lack timestamps. Full rubric: acceptance-criteria.md §6.5 (P0 / executive order vs `search` ≫ `write`: unless write dominated by time) and §6.6 (Executive order, No false recency from counters). Binding: Timeline and recency (MUST) below (same skill).
activating / change workflow stuck (cross-layer root cause)
When an instance stays in `activating`, a change is unfinished, and Red or unassigned shards coexist, follow `references/sop-activating-change-stuck.md` end-to-end (MUST includesListActionRecords,DescribeInstancebefore/after remediation, collection order section 3.1, reporting section 4).
Pre-flight validation for Elasticsearch API
[IMPORTANT] `ES_ENDPOINT` must match the diagnosed instance
>
ComparepublicDomain/domainand `protocol` fromDescribeInstancewithES_ENDPOINT.
If they differ, warn:⚠️ ES_ENDPOINT does not match the current instance; run export ES_ENDPOINT="http://{publicDomain}:9200"when `protocol` is `HTTP`, orhttps://…only when `protocol` is `HTTPS` (adjust host/port to match the deployment).
When Elasticsearch credentials are missing or connections fail
[CRITICAL] Guide the user to fix connectivity explicitly; classify failure modes (do not default persistent timeouts to “allowlist only”). Do not imply the agent “forgot” Elasticsearch — if the first answer is CMS/OpenAPI-heavy, give the blocking reason per Feasibility order below: unsetES_*; transport errors; 401 with valid `-u`; TLS/scheme—not 401 on a probe without-uwhenES_PASSWORDis SET (use authenticatedcurlfirst).
Progressive playbook (read in order): references/es-api-call-failures.md (sections 1 → 4). MUST / strategy context: references/es-api-diagnosis-strategy.md (sections 1–3 and 3.5 summary table).
Mandatory warning when MUST applies but Elasticsearch is not configured
[CRITICAL] If a MUST trigger fires but data-plane evidence is missing, put a warning at the top of the report: follow section 4 of references/es-api-call-failures.md (blocking reason first, then MUST list, missing evidence; if ES_* unset, pointer to section 2.2 of this SKILL; if vars are set, use es-api-call-failures sections 1–2 for auth vs transport).Step 1: Quick health scan (initial signals)
Run the lightweight rules engine (17 metric rules) to list P0 / P1 / P2 findings and steer deeper collection:
python3 scripts/check_es_instance_health.py -i <InstanceId> -r <RegionId> [--window <minutes, default 60>] [--profile <profile_name>]Feasibility order (agent)
1. Run §2.2 ES_* checks (password = SET only)—do not skip; never infer feasibility without this step. 2. ES_ENDPOINT matches DescribeInstance domain / publicDomain (scheme/port). 3. Authenticated GET /_cluster/health—do not stop at 401 on an unauthenticated probe if ES_PASSWORD is SET. 4. MUST scope: table rows and/or rule-engine MUST line in §5.
Step 2: Collect evidence in parallel
Based on Step 1, run collection in parallel (prioritize dimensions with signals). If a MUST-trigger row or rule-engine MUST applies: run Feasibility order, then run that Required Elasticsearch evidence via curl in the same round (see §7). If no MUST applies, add optional data-plane curl only when feasibility and necessity both hold per the strategy doc.
Re-run `check_es_instance_health.py` with the same invocation pattern as Step 1; for this parallel round, `--window 120` and explicit `--profile <profile_name>` are common.
To backfill control-plane evidence (DescribeInstance, ListSearchLog, CMS-style calls), use `aliyun` patterns in references/verification-method.md (epoch times, profiles, namespaces).
Note: data-plane access still requiresES_ENDPOINT/ES_PASSWORD; the Aliyun CLI cannot replacecurlto the cluster.
>
For MUST-trigger rows, necessity for the listed endpoints is already established—do not skip them when feasibility including reachability holds. Outside those rows, avoid unrelated bulkcurlsolely becauseES_*is set; use the strategy doc’s feasibility + necessity test instead.
Step 3: Read SOPs by signal
Map signals to SOPs and read for deeper reasoning. With multiple signals, process P0 → P1 → P2 for severity, then apply Timeline and recency (MUST) in Step 4 so the narrative order matches when signals mattered in the window—not only static rule-engine print order.
| Observed signal | Read |
|---|---|
| Cluster Red/Yellow, node loss, pending tasks | references/sop-cluster-health.md |
Long activating, unfinished change records, Red / unassigned shards | references/sop-cluster-health.md + references/sop-activating-change-stuck.md |
| High CPU, load, imbalance | references/sop-cpu-load.md |
| Per-node load imbalance (CPU/memory/disk/shard count) | references/sop-node-load-imbalance.md |
| JVM pressure, GC, circuit breaker, OOM | references/sop-memory-gc.md |
| Disk watermark, IO, write failures (read-only) | references/sop-disk-storage.md |
| Watermark misconfiguration, index blocks, “normal” disk % but write failures | references/sop-disk-storage.md (Section 3 — watermark misconfiguration) |
| Write timeouts / rejections / latency / QPS drop | references/sop-write-performance.md |
| Query timeouts / rejections / slow queries | references/sop-query-thread-pool.md |
Nodes look down but CPU still reported; all shards failed | references/sop-service-avalanche.md |
| Intermittent Elasticsearch timeouts + CMS CPU > 80% | references/sop-service-avalanche.md |
| Risky settings, Ngram issues, API anomalies | references/sop-configuration.md |
| Event code definitions | references/health-events-catalog.md |
Step 4: Synthesize and write the structured report
Acceptance-style optional checklists: references/acceptance-criteria.md §6.1–§6.6 — Red/Yellow; read-heavy CPU + search pool (+ CMS alignment); JVM / breakers / fielddata; write-queue vs GC + `rejected`/`completed`; read-heavy search pool vs GC-only headline (expand in sop-query-thread-pool.md Report narrative: search pool vs GC / CPU headlines); timeline/recency. Bulk/write: references/sop-write-performance.md §2. Shard `reroute`: references/sop-node-load-imbalance.md §1.3 (allocator / change control only).[CRITICAL] Remediation must match the diagnosed root cause — avoid generic templates. Wrong breaker or concurrency fixes (e.g.in_flight_requestsvsrequest, “split query” when concurrency is the issue) → see `sop-memory-gc.md` and the fired signal’s SOP.
`activating` + data-plane anomaly: include the one-line cross-layer root cause; see references/sop-activating-change-stuck.md section 4.Report skeleton (copy/fill): references/report-template.md.
Timeline and recency (MUST for synthesized reports)
Problem:check_es_instance_health.pyand P0/P1/P2 bands express severity, not when a signal mattered most within the analysis window. Cumulative engine counters (search.rejected,write.rejected) do not encode recency—write and search issues can both be “real” while only one path dominated the recent past (e.g. search pressure closer to window end than write pressure).
Binding rules for the agent:
1. Two axes — Treat severity (P0/P1/P2) and temporal relevance (proximity to window end / “now”) as orthogonal. Do not infer recency from priority alone (e.g. “write is P0 so it must be the current headline”) when time-resolved evidence says otherwise. 2. Mandatory human-facing section — When more than one major finding fires (e.g. write pool + search pool + GC/CPU), the synthesized report must include an `### Incident timeline (recency-ordered)` (or equivalent) block before or immediately after the executive summary, unless the user explicitly asks for a minimal report. In that block:
- Order bullets or rows by time (earlier → later), or state which signal cluster peaked / persisted in the latter portion of `{begin} ~ {end}`.
- Call out divergence: e.g. “write-path stress earlier in window; search-path / CPU more recent” when CMS or logs support it.
3. Evidence for recency (use what exists; do not invent timestamps):
- CloudMonitor: per-metric time series — note peak timestamp or sustained-high interval for
NodeCPUUtilization,NodeHeapMemoryUtilization, GC-related metrics,ThreadPool.*if exposed as rates or non-cumulative series in the collected JSON. - Slow logs / `ListSearchLog`: correlate query vs index slow entries to minutes.
- Engine (optional): two
_nodes/stats/thread_poolsamples at known times to show delta onrejected/completed; or `_tasks` / `hot_threads` for current skew vs historical cumulative counters.
4. Executive summary ordering — The opening 2–4 sentences should reflect recency-weighted user impact: if search pressure is closer to current than write pressure, lead with search/query concurrency and co-stress (GC/CPU) as appropriate, and place historical write saturation as context or second wave—without dropping P0 write findings if they remain valid for remediation backlog. 5. Explicit uncertainty — If only cumulative counters exist and no time series differentiates paths, state one line: recency is undifferentiated; recommend narrower window, slow logs, or delta sampling for the next run.
---
6. Data collection details (CLI OpenAPI + injected input)
One-shot entry
Use the same `check_es_instance_health.py` command as §5 Step 1 (optional `--window` / `--profile`; default window 60 minutes if omitted).
Injected input mode (paired with CLI)
check_es_instance_health.py accepts external JSON to avoid duplicate calls:
python3 scripts/check_es_instance_health.py \
-i <InstanceId> -r <RegionId> \
--data-source input \
--input-json-file /path/to/diag-input.jsonInput JSON shape:
{
"status_info": {},
"metrics": {},
"events": [],
"logs": []
}--data-source modes:
auto: prefer injected fields; backfill gaps via Aliyun CLI.cli: ignore injection; fetch everything via CLI.input: injection only; no OpenAPI calls.
Manual control-plane CLI backfill
For additional OpenAPI examples, see references/verification-method.md.
---
7. Elasticsearch direct API access (data-plane deep dive)
When feasibility holds (including reachability), execute the REST calls required by any MUST-trigger row (§5). For endpoints not listed in a fired MUST row, call them only when feasibility and necessity both hold per the strategy doc.
ES_ENDPOINTmay behost:portor a full URL. For the samples below, normalize tohttp://${ES_ENDPOINT#http://}(usehttps://consistently when the cluster serves TLS).
>
Timeouts: everycurlmust use--connect-timeout 10 --max-time 30.
Red / Yellow (MUST) — recommended set
Scope: The cluster-health MUST row uses ClusterStatus max ≥ Yellow (includes Red). Use this set for unassigned / misallocated shard root cause on the engine.
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_cluster/health?pretty"
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
-H "Content-Type: application/json" \
-X POST "http://${ES_ENDPOINT#http://}/_cluster/allocation/explain?pretty" \
-d '{}'
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_cat/shards?v&h=index,shard,prirep,state,node,unassigned.reason&s=state"
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_cluster/pending_tasks?pretty"
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_nodes/stats/thread_pool?pretty"Query / write performance (MUST) — recommended set
Include `_cluster/settings` when heap / GC / breaker rules fired in Step 1 or `_nodes/stats/breaker` shows concern — read transient and persistentindices.breaker.*/network.breaker.*.
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_nodes/hot_threads?threads=3"
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_nodes/stats/breaker?pretty"
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_cluster/settings?include_defaults=true&pretty"`/_cluster/pending_tasks` and `GET /_nodes/stats/thread_pool` are also listed under Red / Yellow (MUST) above—one call each per session when both sections apply. If you run only this performance block, add those two curl lines from that block.Resource anomalies without a closed loop (SHOULD) — recommended set
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_cat/nodes?v&s=cpu:desc&h=name,ip,cpu,heap.percent,ram.percent,load_1m"
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_nodes/stats/jvm?pretty"
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_cat/allocation?v&bytes=gb"`GET /_cluster/settings?include_defaults=true` also appears under Query / write performance (MUST) above—reuse one response when both blocks apply. If you run only this SHOULD block, add the same curl line from that block.Protocol sanity (avoid WRONG_VERSION_NUMBER): usually http/https scheme mismatch on ES_ENDPOINT — fix scheme/port and retry.
Scenario → endpoint index: references/es-api-catalog.md.
---
8. Diagnostic coverage
The knowledge base covers 48+ health-event-style rules and chained scenarios (e.g. disk pressure → allocation → Red). Per-category counts, P0/P1/P2 mix, and event codes: references/health-events-catalog.md — scenario runbooks: references/sop-*.md (index: references/README.md).
---
9. Best practices
Read-only: no mutating control-plane APIs; no teardown.
1. Layered + evidence-bound: scan → SOP depth; every conclusion cites metrics/logs/events; if ES is unreachable, state limits (es-api-call-failures.md). 2. Priority vs narrative: P0→P2 for urgency; Incident timeline when multiple dimensions differ in time (Step 4). Credentials / TLS / parameters: §1–2 and §4. 3. Green is not “all clear” — watermarks, blocks, mis-set limits still matter; MUST + reachable ES: do not skip §5/§7 evidence because the cluster is Green or OpenAPI “explains” symptoms. 4. Thread-pool `rejected`: cumulative unless you show a delta — sop-query-thread-pool.md §1–2; write/bulk: sop-write-performance.md §2.
---
10. Reference links
references/verification-method.md— Verification (how to validate diagnosis; metrics, APIs, workflows)references/report-template.md— Structured diagnosis report skeletonreferences/README.md— Language map (reference assets andsop-*.mdrunbooks; English in this repo)references/ram-policies.md— RAM policy listreferences/acceptance-criteria.md— Correct/incorrect patterns and acceptance (includes credential and safety anti-patterns)references/cli-installation-guide.md— Aliyun CLI installationreferences/es-api-catalog.md— Elasticsearch REST API catalogreferences/health-events-catalog.md— Health event catalogreferences/sop-*.md— Scenario SOPs (e.g.sop-activating-change-stuck.mdforactivating/ change stuck, cross-layer root cause)references/es-api-diagnosis-strategy.md— Elasticsearch API diagnosis strategy
Acceptance criteria: alibabacloud-elasticsearch-instance-diagnosis
Scenario: Elasticsearch instance diagnosis Purpose: Skill test / acceptance checklist
---
Version notes (2026-03)
- Control-plane OpenAPI collection uses the aliyun CLI only.- Health diagnosis entry point: python3 scripts/check_es_instance_health.py ....- Engine-level deep collection usescurlagainst ES REST APIs (noinvoke_es_api.py).
1. Environment dependencies
1.1 CLI dependency
✅ CORRECT
aliyun version❌ INCORRECT
# Error: aliyun CLI not available
aliyun: command not found---
2. Credential configuration
2.1 OpenAPI credentials (CLI profile)
✅ CORRECT
aliyun configure list
aliyun --profile <profile_name> sts get-caller-identity❌ INCORRECT
# Error: profile does not exist
aliyun --profile not-exist sts get-caller-identity2.2 Direct ES credentials
✅ CORRECT
[[ -n "$ES_ENDPOINT" ]] && echo "ES_ENDPOINT: SET" || echo "ES_ENDPOINT: NOT SET"
[[ -n "$ES_PASSWORD" ]] && echo "ES_PASSWORD: SET" || echo "ES_PASSWORD: NOT SET"❌ INCORRECT
# Error: ES password not configured
unset ES_PASSWORD---
3. Running the diagnosis
3.1 Main health-check entry
✅ CORRECT
python3 scripts/check_es_instance_health.py \
-i es-cn-xxxxx -r cn-hangzhou \
--data-source cli \
--profile <profile_name>Expected output:
- Structured report (P0/P1/P2, evidence, remediation)
- When multiple major dimensions fire, an incident timeline (recency-ordered) section aligning narrative with when signals peaked in the window (see §6.6)
- Summary of key monitoring metrics
- No dependency on deprecated scripts
3.2 Injected-input + auto backfill
✅ CORRECT
python3 scripts/check_es_instance_health.py \
-i es-cn-xxxxx -r cn-hangzhou \
--data-source auto \
--input-json-file /path/to/diag-input.json \
--profile <profile_name>Expected output:
- Input JSON fields take precedence when present
- Missing fields are backfilled via CLI OpenAPI
---
4. OpenAPI coverage
4.1 Elasticsearch OpenAPI
✅ CORRECT
aliyun --profile <profile_name> elasticsearch describe-instance \
--region cn-hangzhou \
--instance-id es-cn-xxxxx
aliyun --profile <profile_name> elasticsearch list-search-log \
--region cn-hangzhou \
--instance-id es-cn-xxxxx \
--type INSTANCELOG \
--query "*" \
--begin-time <epoch_ms> \
--end-time <epoch_ms>
aliyun --profile <profile_name> elasticsearch list-action-records \
--region cn-hangzhou \
--instance-id es-cn-xxxxx
aliyun --profile <profile_name> elasticsearch list-all-node \
--region cn-hangzhou \
--instance-id es-cn-xxxxx❌ INCORRECT (legacy CLI — do not use for this skill)
Do not copy old tutorials that put a PascalCase OpenAPI action name as the aliyun <product> <verb> verb, or use CamelCase query flags. The ✅ CORRECT block above is the only canonical shell shape for this skill.
4.2 CMS OpenAPI
✅ CORRECT
aliyun --profile <profile_name> cms describe-metric-list \
--region cn-hangzhou \
--namespace acs_elasticsearch \
--metric-name ClusterStatus \
--dimensions '[{"clusterId":"es-cn-xxxxx"}]' \
--start-time <epoch_ms> \
--end-time <epoch_ms> \
--period 300
aliyun --profile <profile_name> cms describe-system-event-attribute \
--region cn-hangzhou \
--product elasticsearch \
--search-keywords es-cn-xxxxx \
--start-time <epoch_ms> \
--end-time <epoch_ms>
aliyun --profile <profile_name> cms describe-metric-meta-list \
--region cn-hangzhou \
--namespace acs_elasticsearchExpected output:
- Success shape (
Code=200orSuccess=true) - Key fields present (instance status, logs, metrics, events, nodes, change records)
---
5. Engine-level ES API checks (curl)
If calls fail or return 401 / timeouts, classify the failure using [es-api-call-failures.md](es-api-call-failures.md) before judging PASS / PARTIAL.
5.1 Calls
✅ CORRECT
curl -sS -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_cluster/health?pretty"
curl -sS -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" -H "Content-Type: application/json" \
-X POST "http://${ES_ENDPOINT#http://}/_cluster/allocation/explain?pretty" -d '{}'
curl -sS -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/_nodes/stats/thread_pool?pretty"❌ INCORRECT
# Error: wrong URL path (missing leading /)
curl -sS -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}_cluster/allocation/explain"---
6. Report format
✅ CORRECT report shape
## Diagnosis summary
**Instance**: es-cn-xxxxx (cn-hangzhou)
**Window**: 2026-03-24 10:00 ~ 2026-03-24 12:00
### Incident timeline (recency-ordered)
- Optional in minimal reports; **required** when search vs write vs GC show **different** emphasis over time (SKILL Step 4).
### Findings (by priority)
#### P0 - Critical (immediate action)
- [HealthCheck.ClusterUnhealthy] Cluster status Red
- Evidence: ClusterStatus=2, UNASSIGNED primary shards
- Likely cause: shard allocation failure
- Immediate action: run `POST /_cluster/allocation/explain`6.1 Cluster Red / Yellow — optional “full checklist” (acceptance-style)
Use when you want the report to align with structured acceptance rubrics (control plane vs data plane already correct). These are additive, not a substitute for allocation/explain + sop-cluster-health.md.
| Item | What to add (one line each when data exists) |
|---|---|
| Red vs Yellow (B5) | State `unassigned_primary_shards` > 0 (or equivalent: “at least one primary shard is UNASSIGNED”) for Red; for Yellow, primaries assigned but replicas unassigned. |
| Shard arithmetic (B6) | e.g. number_of_shards=3, number_of_replicas=1 → 3 primary shard copies + 3 replica shard copies (one replica shard per primary), 6 logical copies → all may show UNASSIGNED when allocation cannot place any copy. Avoid wording that sounds like “number_of_replicas = 3”. |
| `unassigned.reason` (C4) | From GET /_cat/shards / explain: cite reason when present (ALLOCATION_FAILED, filter / require deciders, etc.). Optional (stricter scoring): mention `INDEX_CREATED` when it appears — often consistent with “shard never allocated since creation” under a failing filter (e.g. require._name to a non-existent node). |
| Blast radius (B8) | Name affected indices (from _cat/shards); if only one hot index, say other indices were not failing (if _cat/shards supports that claim). |
| Scale-out vs `total_shards_per_node` (B9) | Do not promise Green from “add a few nodes” when a per-index per-node cap stays tight — verify (data nodes × cap) ≥ total shard copies for that index (see sop-cluster-health.md §2 Yellow; e.g. cap=1 + 2p/1r ⇒ 4 copies ⇒ 3 nodes often still Yellow). |
| Post-fix verification (D3) | After remediation, suggest re-check: GET /_cluster/health, GET /_cat/shards/{index}?v (and allocation/explain if any shard still unassigned). |
| Ruling out disk / node / CPU | Prefer: “In this report’s metrics window and collected evidence, disk / node loss / CPU are not the dominant driver” — not an absolute “unrelated everywhere” claim (other clusters or later windows may differ). |
| ClusterStatus single voice | If one paragraph cites CMS `ClusterStatus` max = Yellow (or Red) for `{begin} ~ {end}` and another cites `GET /_cluster/health` = green at a single probe time, reconcile in one sentence: e.g. worst status in the monitoring window vs snapshot after recovery vs instantaneous engine API — do not leave Green and Yellow side by side without time / aggregation qualifier (parallel sections should not contradict). |
| CMS `ClusterShardCount` (or total-shard) swings | If CMS shows large step changes in total shard count (e.g. 76 → 38 → 76) within or across windows, do not imply “half the shards were lost” unless `GET /_cat/shards` / engine health confirms loss — reconcile with Alibaba Cloud console change / ops events, metric definition (scope: data nodes vs cluster, replication, aggregation lag), and instance lifecycle. Prefer wording such as “pending cross-check with ops records and engine shard view” when the drop is not explained by allocation state. |
6.2 Read-heavy CPU + search pool (optional checklist)
Optional lines when query-driven overload is present (e.g. _tasks shows *search* on a hot index with match_all-style bodies):
| Item | What to add |
|---|---|
| CPU ↔ same workload | One explicit sentence: NodeCPU / `hot_threads` and `search` pool queue or `rejected` stem from the same concurrent search load (name index + task shape when known). |
| Shard counts / layout in prose | Once `GET {index}/_settings` (and templates) and `_cat/shards` confirm counts and placement, use those values consistently in the report — they override assumptions from any other environment. Optionally one line on provenance (template, console, legacy index). |
| Hot node vs skew + `rejected` | Summarize the overloaded side as a hot node when `rejected` / heap / GC align there. Cite primary/replica skew as one factor in local work and pressure, plus parallel read-path explanations (coordinator / single client path / preference=_primary / routing) — not “primaries necessarily answer most default searches.” See sop-query-thread-pool.md §2. |
| CMS vs thread_pool time alignment | State whether CMS CPU overlaps the search queue / reject episode — including CPU no longer high while `rejected` is cumulative and `queue` already zero (post-spike phenomenology). |
| CMS CPU metric hygiene | If CMS NodeCPU looks modest vs strong `search.rejected`, add one reconciliation block: burst early in window vs CMS whole-window stat; metric name + `Dimensions` (this instance’s data nodes, not wrong rollup); optional `_nodes/stats/os` vs sample period. See sop-cpu-load.md decision-tree notes. |
| Per-node CPU % vs search “hot” node | If a per-node CPU table (e.g. 5-minute mean or window aggregate) shows lower CPU on the node that logs / `thread_pool.search` / `EsRejectedExecutionException` identify as the search hotspot, add one sentence so readers are not stuck: spike moment ≠ coarse mean; CMS bucket / dimension may not align with sub-minute pool saturation; engine or INSTANCELOG lines anchor which node ran the saturated `search` pool — the table is imbalance context, not a disproof of pool rejections on that node. |
| Shard placement phrasing | Use consistent qualifiers — all vs N / N vs almost all — title and tables must match; do not imply exceptions without a shard row to cite. |
| Short / ambiguous index names | For generic names (e.g. `stats`), add purpose (built-in / monitoring vs business-owned) or full index pattern so readers do not conflate unrelated indices. |
| `rejected` counter | Call out cumulative since process start (unless you show a delta); do not imply the full counter equals rejects “only in the report window.” |
| `hot_threads` / logs | Say whether `hot_threads` ran successfully vs timeout / empty after spike; for OpenAPI logs, success vs failure (e.g. metrics API unavailable). Treat failures as evidence gaps, not silent omissions. |
| Slow-log node vs search-pool node in other logs | SEARCHSLOW / fetch-phase lines may name one data node while INSTANCELOG / thread_pool lines at another minute name a different node as `search` saturated — both can be true: query routing, primary/replica, coordinator vs data role, and time skew. Add one sentence: each line reflects that phase / time / shard copy; ground routing with `GET /_cat/shards/{index}` (and which shard the slow query hit) so the report does not read as self-contradictory. |
| Wording | Prefer co-occurring signals over a strict single-arrow causal chain unless ordering is evidenced. |
| P0 / P1 band | Match the strongest fired rule in the window (often P0 CPU and/or P0 ThreadPool.Search* per health-events-catalog.md); avoid a P1-only headline when P0 rules already fired. |
6.3 JVM / fielddata / circuit breakers (optional checklist)
Use when heap, GC, breaker, or fielddata signals appear — cluster may still be Green.
| Item | What to add |
|---|---|
| `_cluster/settings` first-class | `GET _cluster/settings?include_defaults=true` — read transient and persistent for `indices.breaker.fielddata.limit`, `indices.breaker.request.limit`, and related keys; they are often changed together. |
| Headline vs Old GC | If settings show very low breaker limits and/or `_nodes/stats/breaker` shows `tripped` > 0 / logs show `CircuitBreakingException`, lead with breaker + settings + query/mapping — Old GC rate as parallel or secondary, not the only story. See sop-memory-gc.md §5. |
| `tripped` vs P2-only wording | Low `fielddata.limit` without trips is config risk; `tripped` > 0 or matching exceptions → incident-grade narrative (usually alongside P0-class breaker handling in the catalog). |
| Index-level closure | Name indices and mapping culprits (text + `fielddata`, large `terms` / `cardinality`, deep paging) when engine evidence exists. |
| Heap skew across nodes | Correlate uneven heap with `_nodes/stats/breaker`, `_nodes/stats/indices/fielddata`, `_cat/shards` — not only shard counts. |
6.4 Write-path saturation + CPU + JVM (optional checklist)
Use when ingest / bulk, `ThreadPool.WriteRejected`, CPU peaks, and/or Old GC / heap signals co-occur — for example sustained high-QPS bulk indexing that stresses the write pool.
Write-queue / bulk prompts (rubric alignment): Graders often treat `ThreadPool.WriteRejected` + `_nodes/stats/thread_pool` as the primary storyline. A conclusion that only headlines Old GC / heap while relegating write-pool saturation to “P1 / participating factor” can read as a JVM/GC report, not a write-capacity diagnosis. Prefer one of:
- Dual P0 (parallel): Opening treats quantified write-pool stress (`write` `rejected` and `completed`, or reject share per node or cluster) and Old GC wall-clock / `GCTimeRatioTooHigh` as co-equal P0-class signals (see health-events-catalog.md `ThreadPool.WriteRejected` / `HealthCheck.ThreadPoolSaturation`).
- Causal chain (upstream first): First sentence states bulk / ingest saturates the `write` pool → merges / heap → Old GC + CPU — so `write.rejected` is in the lead, not buried below a GC headline.
Add at least one line of numbers: e.g. `rejected` / `completed` on the busiest node(s), optional reject share (approximately rejected / (rejected + completed)) for the same pool, and rule / event names when citing CMS (e.g. `ThreadPool.WriteRejected`).
Align structured reports with [health-events-catalog.md](health-events-catalog.md): CMS P0 for write rejects usually requires sustained reject rate + traffic, not cumulative counters alone — human-written reports should still quote cumulative `rejected`/`completed` with context so the data-plane story is concrete.
Engine snapshot (`check_es_instance_health.py`): `rejected` > 0 is emitted as P1 when `JVMMemory.GCTimeRatioTooHigh` is not in the same finding set. When `GCTimeRatioTooHigh` (P0) does fire, the script promotes `ThreadPool.WriteRejected` from P1 → P0 so severity bands match a dual-P0 or causal-chain narrative — see table below. Co-occurrence is not proof of causation; use `hot_threads` / `_tasks` to confirm an ingest-heavy path before asserting write overload → GC as the only story.
| Item | What to add |
|---|---|
| Headline priority (dual P0) | When write-path evidence and `JVMMemory.GCTimeRatioTooHigh` / Old GC are both material, prefer two P0 headlines (or one causal chain, not JVM-only): e.g. write pool saturation / rejects and Old GC wall-clock share — not “GC only.” Optional chain: write overload → merge / heap → Old GC → CPU spikes (only if evidence supports ordering). |
| GC collector wording | Do not assume G1 vs CMS (or other) from ES/JDK version alone. Prefer “old-generation / Old GC” or cite `GET _nodes/stats/jvm` (gc.collectors.*) / node GC logs — avoids technical challenges from a wrong collector name. |
| Script vs narrative | If the checker still prints WriteRejected as P1 (no GCTimeRatioTooHigh in the window) but CMS/catalog would grade P0, say so in one line — do not silently downgrade the user-facing conclusion. |
| `rejected` + `completed` + `queue` / `active` | Include `completed` (same pool, per node or total) next to `rejected` to size reject share; state cumulative since node start for `rejected` / `completed`; add current queue / active so readers do not confuse history with ongoing overload. |
| Per-node skew | When `rejections_by_node` is uneven, tie to hot shards / routing / transient skew — same direction as CPU imbalance checks. |
| Shard count vs `write.rejected` skew | If shards per data node are even (e.g. similar counts from `_cat/shards` / routing) but `write.rejected` is much higher on one node, state explicitly: imbalance is unlikely from shard count alone — favor hot shards / routing / client targets; cite numbers for both shards/node and per-node `rejected` when available. |
| Parent breaker `tripped` | `tripped` is cumulative (breaker semantics: trips since JVM start). A non-zero `parent.tripped` (e.g. 183) is aligned with historical peaks / past pressure and need not contradict current _cat/nodes heap ~50% — add half a sentence that `tripped` reflects cumulative history, not instantaneous heap %. Relate to historical heap pressure alongside `rejected`; reconcile with current heap in one sentence. |
| Bulk / client guidance | Under reject / capacity-tight conditions, prefer: lower parallel bulk streams, smaller per-request bytes/doc count, backoff / fewer in-flight bulks; align total throughput to SLO. If mentioning larger batches, immediately caveat timeouts / memory spikes / OOM — avoid implying “bigger single requests” as the fix. See sop-write-performance.md §2 (bulk QPS → write pool). |
6.5 Read-heavy scenarios (search pool vs GC-only headline)
Use when the incident is query-driven (high concurrent search, terms / QPS patterns, “search reject → cascade” timelines). Section 6.4 already guards write-path vs GC-only headlines; section 6.2 covers search pool + CPU alignment — this subsection fixes the remaining gap: Old GC / CPU as the only lead when `search` pool saturation is the primary plausible storyline. Long-form narrative, Chinese templates, and evidence closure: sop-query-thread-pool.md Report narrative: search pool vs GC / CPU headlines (keep this section as a short rubric; avoid duplicating those paragraphs here).
Search-pool-primary vs write (both pools have cumulative `rejected`): For query-saturation cases where the catalog targets `ThreadPool.SearchRejected` and `_nodes/stats/thread_pool` shows `search.rejected` ≫ `write.rejected` on the same data nodes, the executive lead and first P0 bullets must not read like a write-primary report with search as a footnote — put `search` pool / query concurrency first (or before write in the same band). `write.rejected` may remain P0/P1 as parallel or secondary (bulk, catch-up, historical ingest); say so explicitly so readers do not infer “mainly an ingest/write incident.” Tie the search lead to high concurrent query / terms / slow query and hot index name when verified.
| Item | What to add |
|---|---|
| Headline order | Do not make “Old GC (P0) + CPU spike (P1)” the sole executive story when `ThreadPool.SearchRejected` / `search` pool capacity is still plausible — treat query concurrency > `search` pool as first or co-equal; GC/CPU as co-stress, cascade, or second wave unless engine evidence proves otherwise. Parallel to §6.4: dual P0 (search capacity + Old GC) or causal chain with `search.rejected` / queue in the first sentence when the prompt is read-heavy — mirror sop-write-performance.md §2 ordering, swap `write` → `search`. |
| P0 / executive order vs `search` ≫ `write` (cumulative) | If `search.rejected` ≫ `write.rejected` per node (or cluster totals) and `ThreadPool.SearchRejected` applies, do not place `ThreadPool.WriteRejected` above search in the opening summary or first P0 line unless time-resolved evidence shows write dominated the window. Script print order (e.g. checker listing write before search) is not narrative order — override for human-facing text when data-plane magnitudes and scenario type say search-first. |
| Quantification | Same spirit as §6.4: cite `search.rejected` with `search.completed` (optional reject share, cumulative semantics) when stating capacity — not only “queue was high.” |
| Rules + summary | If both GC P0-class and `ThreadPool.SearchRejected` (or catalog equivalent) appear in the same window, list both in the opening summary — do not imply only GC is P0. |
| Engine API incomplete | Use the self-limiting templates in sop-query-thread-pool.md (Report narrative: search pool vs GC / CPU headlines): state `GET /_nodes/stats/thread_pool` (`search`) as pending verification when timeouts prevented collection. |
| Customer-facing wording | Prefer “引擎层必查清单(SKILL 文档第 5 节)” over §-prefixed section labels in external deliverables. |
6.6 Timeline vs severity (recency-ordered narrative)
Use when multiple of: `ThreadPool.WriteRejected`, `ThreadPool.SearchRejected`, GC / heap / CPU appear together. Severity bands (P0/P1) are not a substitute for when each path stressed the cluster inside {begin} ~ {end}.
| Item | What to add |
|---|---|
| Section present | An `### Incident timeline (recency-ordered)` (or equivalent) with time-ordered or “latter-window emphasis” bullets — unless the report is explicitly minimal and recency cannot be distinguished (then one uncertainty line). |
| No false recency from counters | `search.rejected` / `write.rejected` are cumulative since node start — do not say “write happened first” from counter magnitude alone; use CMS series, slow logs, or paired deltas on rejected/completed. |
| CMS peaks | Where available, cite which metric peaked when (e.g. CPU vs GC duration vs pool-related CMS names) relative to window start vs end. |
| Executive order | Whichever path peaked or persisted closer to window end should lead the opening summary (recency-weighted): e.g. if search-path pressure is more recent than write-path, lead with search / query concurrency (and co-stress) as appropriate; if write-path is more recent, lead with write / bulk. Same time-over-magnitude rule as §6.5 row P0 / executive order vs `search` ≫ `write` (override when time-resolved evidence shows the other path dominated). Do not drop P0 findings for the other path from Findings (by priority). |
| Script print order | `check_es_instance_health.py` listing order is not proof of temporal order — override for narrative when time-resolved evidence supports it. |
---
7. Common mistakes
| Issue | Bad example | Correct approach |
|---|---|---|
| Hard-coded secrets | AK/SK/password in command line | CLI profile + environment variables |
| Wrong scheme | http:// vs https:// mismatch | Match the instance endpoint |
| Unconfirmed params | Guessing region / instance id | Confirm with the user first |
| Skipping RAM | Ignoring permission errors | Validate RAM Actions first |
| P0 order = time order | Listing write-path P0 before search P1 because “P0 first” when CMS shows search stress later in the window | Add Incident timeline; lead the executive summary with recency-weighted impact; keep full Findings by priority |
Aliyun CLI Installation & Configuration Guide
Complete guide for installing and configuring Aliyun CLI.
Aliyun CLI 3.3.1+: Supports installing and using all published Alibaba Cloud product plugins. Make sure to upgrade to 3.3.1 or later for full plugin ecosystem coverage.
Installation
macOS
Using Homebrew (Recommended)
brew install aliyun-cli
# Upgrade to latest
brew upgrade aliyun-cli
# Verify version (>= 3.3.1)
aliyun versionUsing Binary
# Download
wget https://aliyuncli.alicdn.com/aliyun-cli-macosx-latest-amd64.tgz
# Extract
tar -xzf aliyun-cli-macosx-latest-amd64.tgz
# Move to PATH
sudo mv aliyun /usr/local/bin/
# Verify
aliyun versionLinux
Debian/Ubuntu
# Download
wget https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
# Extract and install
tar -xzf aliyun-cli-linux-latest-amd64.tgz
sudo mv aliyun /usr/local/bin/
# Verify
aliyun versionARM64 Architecture
# Download ARM64 version
wget https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-arm64.tgz
# Extract and install
tar -xzf aliyun-cli-linux-latest-arm64.tgz
sudo mv aliyun /usr/local/bin/Windows
1. Download from: https://aliyuncli.alicdn.com/aliyun-cli-windows-latest-amd64.zip 2. Extract the ZIP file 3. Add the directory to your PATH environment variable 4. Verify: aliyun version
Configuration
Quick Start
aliyun configure set \
--mode AK \
--access-key-id <your-access-key-id> \
--access-key-secret <your-access-key-secret> \
--region cn-hangzhouEnvironment Variables
export ALIBABA_CLOUD_ACCESS_KEY_ID=your_access_key_id
export ALIBABA_CLOUD_ACCESS_KEY_SECRET=your_access_key_secret
export ALIBABA_CLOUD_REGION_ID=cn-hangzhouVerification
# Check configuration
aliyun configure list
# Test authentication
aliyun ecs describe-regionsReferences
- Official Documentation: https://help.aliyun.com/zh/cli/
- Access Key Management: https://ram.console.aliyun.com/manage/ak
Elasticsearch REST API call failures (progressive guide)
Use this document in order when curl to the data plane fails or returns no useful JSON. For when engine APIs are mandatory vs optional, see es-api-diagnosis-strategy.md (sections 1–3: feasibility, necessity, MUST triggers).
Security: never print ES_PASSWORD or ask for it in chat — only SKILL.md section 2.2 patterns (local export in the same shell the agent uses).
---
0. Mandatory order (agents and operators)
Do not infer “this environment has no Elasticsearch credentials” from a lone unauthenticated curl (for example a probe that omits -u), even if the response is 401. 401 without `Authorization` is expected on secured clusters.
Always run §1.1 first in the same shell that will execute the diagnosis curl chain (for Cursor: the integrated terminal session the agent uses). Then:
| Step | Action |
|---|---|
| 1 | §1.1 presence checks for ES_ENDPOINT / ES_PASSWORD (and ES_USERNAME if you use non-default). |
| 2 | If both ES_ENDPOINT and ES_PASSWORD are SET → run authenticated minimal APIs immediately (§1.3). Do not ask the user to export secrets until a authenticated attempt fails. |
| 3 | If either is NOT SET → blocking reason is missing engine credentials in this shell; point to SKILL.md §2.2 and have the user export in that same terminal, then re-run §1.1 → §1.3. |
| 4 | If authenticated calls return 401 → §1.2 (wrong user/password/realm or URL scheme). |
| 5 | If authenticated calls return 000 / refused / 28 → §2 (transport). |
This order matches actual runs: many failures are “agent skipped §1.1” or “wrong http/https,” not missing cloud APIs.
---
1. Preconditions — why the first answer might skip ES JSON
Engine curl needs both:
| Gate | Meaning |
|---|---|
| Executable | ES_ENDPOINT + ES_PASSWORD set; TCP/TLS path to Elasticsearch works; authenticated calls return JSON. |
| Necessary | The question needs engine proof that CMS / OpenAPI cannot supply (see strategy doc). |
If Executable fails, the agent is not “forgetting” Elasticsearch: calls either were not possible (no env), were sent without auth and got 401, used the wrong auth or URL scheme, or hit transport errors — so _cluster/health, /_cluster/allocation/explain, etc. do not yield business JSON.
1.1 Default habit (same shell as the agent)
Run presence only (never echo secrets):
[[ -n "$ES_ENDPOINT" ]] && echo "ES_ENDPOINT: SET" || echo "ES_ENDPOINT: NOT SET"
[[ -n "$ES_PASSWORD" ]] && echo "ES_PASSWORD: SET" || echo "ES_PASSWORD: NOT SET"
[[ -n "$ES_USERNAME" ]] && echo "ES_USERNAME: SET" || echo "ES_USERNAME: NOT SET"Interpretation:
- `ES_ENDPOINT` + `ES_PASSWORD` both SET → proceed to §1.3 immediately (minimal authenticated checks). Optional: print only the host/scheme for sanity (
echo "$ES_ENDPOINT"is OK if it contains no secrets; do not echo password). - Either NOT SET → state clearly: this shell has no engine credentials, not “Elasticsearch is unreachable.” Point to SKILL.md section 2.2; user
exportin the integrated terminal (same shell), then you re-run §1.1 then §1.3 — do not treat an earlier unauthenticated 401 as proof that credentials are absent.
1.2 HTTP 401 Unauthorized (after you know whether auth was sent)
Classify 401:
| Situation | Meaning | What to do |
|---|---|---|
401 on a request without -u / Authorization | Normal for secured ES; not a credential verdict | Run §1.1; if vars SET, retry with auth (§1.3). |
401 on a request with ES_USERNAME / ES_PASSWORD (or -u) | Auth rejected | Fix local env only: password, username (often elastic), `http://` vs `https://` on ES_ENDPOINT (must match DescribeInstance protocol / actual listener), port, or trailing path typos. See SKILL.md §2.2. |
Principle: “We saw 401” is not actionable until the table above is satisfied.
1.3 Minimal authenticated checks (run as soon as §1.1 passes)
Use timeouts on every call (see SKILL.md §7). Normalize base URL once:
- If
ES_ENDPOINTishost:portwith no scheme, prepend `http://` or `https://` consistently with the cluster (Alibaba CloudDescribeInstancereportsprotocolfor the ES endpoint). - Strip trailing
/before appending paths.
Example pattern (do not log password):
BASE="${ES_ENDPOINT}"
case "$BASE" in
http://*|https://*) ;;
*) BASE="http://${BASE}" ;;
esac
BASE="${BASE%/}"
curl -sS --connect-timeout 10 --max-time 30 -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" "${BASE}/_cluster/health?pretty"For `https://`, add `--cacert /path/to/ca.pem` (or `-k` for short, non-production tests) if the system trust store does not trust the cluster certificate. Do not switch from `http://` to `https://` as a blind fix for `000`/timeout when `DescribeInstance` `protocol` is `HTTP` — prefer allowlist / SG / path checks; see SKILL.md §2.2 (If `http://` does not work — when to try `https://` and HTTPS — prerequisites).
When MUST triggers require allocation evidence and the cluster is Red, prefer targeted explain after a quick shard listing — see §1.4 (empty explain body can pick a replica while the business-critical failure is an unassigned primary).
1.4 POST /_cluster/allocation/explain — practical pitfall
POST /_cluster/allocation/explain with an empty body {} returns one explanatory shard, which may be a replica ("primary" : false). For Red clusters, the P0 signal is usually an unassigned primary.
Runbook:
1. GET _cat/shards?v&h=index,shard,prirep,state,node,unassigned.reason&s=state — find UNASSIGNED rows with `p` (primary). 2. POST /_cluster/allocation/explain with body, for example:
{
"index": "<index_from_cat>",
"shard": 0,
"primary": true
}Then read allocate_explanation, unassigned_info, and node_allocation_decisions[].deciders[] (see sop-cluster-health.md).
---
2. Transport and TLS outcomes (classify before blaming “network”)
| Pattern | Typical symptom | First direction | See also |
|---|---|---|---|
| Connection refused | curl exit 7, Connection refused | Process down, public access off, wrong port | sop-cluster-health.md |
| Persistent timeout | exit 28, all calls time out | Context-dependent — section 2.1 below | Allowlist + CMS triage |
| Intermittent timeout | some curls OK, some timeout | Often overload / meltdown | sop-service-avalanche.md |
| Auth failure | HTTP 401 with auth headers sent | Wrong/missing password, user, or scheme | §1.2 |
| TLS mismatch | e.g. WRONG_VERSION_NUMBER | http:// vs https:// on ES_ENDPOINT | Match `DescribeInstance` `protocol`: public HTTP listener → `http://<publicDomain>:9200`; `https://` on HTTP-only causes TLS errors. |
2.1 Persistent timeout (exit 28) — context-aware
Do not equate exit 28 with “allowlist only.” Exit 28 means the TCP connection did not complete in time — triangulate with control plane + CMS.
Suggested order:
1. Allowlist: DescribeInstance publicIpWhitelist / networkConfig.whiteIpGroupList (whiteIpType=PUBLIC_ES) vs client egress IP. 2. If allowlist looks OK but still timing out:
| If… | Lean toward… | Action |
|---|---|---|
CMS NodeCPUUtilization > 80% or NodeHeapMemoryUtilization > 85% | Server overload — ES too busy to finish TLS/TCP quickly | Treat as degradation; sop-service-avalanche.md |
| CMS OK, security group missing inbound 9200 | Security group | Open path from client |
| CMS OK, allowlist + SG OK | Path / middlebox | telnet / nc hop check |
Principle: exit 28 is a transport-timeout signal, not proof of a firewall drop. If CMS shows resource pressure, prefer overload before “pure network.”
2.2 Intermittent timeouts
When some curl calls succeed and others time out in the same session:
1. Do not label as “preconditions not met” if ES_* is set. 2. Must cross-check CMS NodeCPUUtilization. 3. If CPU > 80%, treat as suspected meltdown — sop-service-avalanche.md. 4. Use successful responses as partial evidence; state coverage limits in the report.
Principle: flaky connectivity is itself a signal — often overload with a live process, not a simple misconfig.
2.3 Flaky API collection tactics
When the cluster is hot: longer --connect-timeout / --max-time, start with light APIs (_cat/nodes, _cluster/health), retry _nodes/hot_threads a few times — see sop-service-avalanche.md (intermittent timeout entry).
---
3. Evidence boundary (one screen)
- With only control plane + CMS, or with no successful authenticated engine JSON, you may still state high-confidence facts such as: CMS `ClusterStatus` = Red ⇒ at least one primary shard is unassigned.
- You cannot uniquely pin allocation-explain-class causes (e.g. bad
routing.allocation.require._name, exact decider text) without at least one authenticated successful/_cluster/allocation/explaintargeting the relevant shard (or equivalent) — see §1.4. - Say explicitly: the gap is missing authenticated data-plane evidence or wrong shard in explain output, not “Elasticsearch cannot be diagnosed.”
---
4. Report checklist (when MUST data is missing)
Put at the top of the report:
1. One line blocking reason — only after §1.1: e.g. ES_PASSWORD NOT SET in this shell, `401` with authenticated curl (then scheme/user/password), connection refused, persistent vs intermittent timeout — before a long generic “evidence boundary” paragraph. 2. Which MUST conditions fired (from CMS / script). 3. Which engine evidence types would be collected after auth/path works (allocation/explain with primary shard if Red, hot_threads, …). 4. Pointer to SKILL.md section 2.2 only when §1.1 shows vars not set; if vars are set but calls fail, point to §1.2 / §2 instead.
---
5. Related references
| Doc | Role |
|---|---|
| es-api-diagnosis-strategy.md | MUST / SHOULD / executable vs necessary |
| verification-method.md | curl examples and checklists |
| acceptance-criteria.md | PASS / partial when engine checks blocked |
| sop-service-avalanche.md | CPU + intermittent timeouts + all shards failed |
| sop-cluster-health.md | Real node loss vs cluster issues |
Elasticsearch REST API catalog (curl)
Use curl directly against the Elasticsearch data plane.
export ES_ENDPOINT="<host:9200 or http://host:9200>"
export ES_USERNAME="elastic"
export ES_PASSWORD="<elasticsearch-admin-password>"
# Generic template (HTTP)
curl -sS -u "${ES_USERNAME:-elastic}:${ES_PASSWORD}" \
"http://${ES_ENDPOINT#http://}/<endpoint>?pretty"If the cluster only serves HTTPS, switch tohttps://and add CA options or-kfor testing only.
---
Cluster layer
| Endpoint | Purpose |
|---|---|
GET /_cluster/health | Cluster health (green/yellow/red) |
GET /_cluster/stats | Cluster statistics (nodes/shards/disk/JVM) |
GET /_cluster/settings | Cluster dynamic settings |
GET /_cluster/pending_tasks | Master pending tasks |
POST /_cluster/allocation/explain | Explain unassigned shards (requires unassigned shards) |
---
Node layer
| Endpoint | Purpose |
|---|---|
GET /_cat/nodes?v | Node list (IP, CPU, heap, load) |
GET /_cat/nodes?v&s=cpu:desc | Nodes sorted by CPU |
GET /_nodes/hot_threads?threads=3 | Hot threads (when CPU is high) |
GET /_nodes/stats/thread_pool | Thread pool queue / rejected |
GET /_nodes/stats/breaker | Circuit breaker trips |
GET /_nodes/stats/jvm | JVM / GC stats |
Version note
- The?localflag onGET /_cat/nodeswas deprecated in 7.x and removed in 8.0 — do not use it.
- Other node APIs are compatible across 6.x / 7.x / 8.x.
---
Index and shard layer
| Endpoint | Purpose |
|---|---|
GET /_cat/indices?v&s=pri.store.size:desc | Indices by primary store size |
GET /_cat/indices?v&s=pri:desc | Indices by primary shard count |
GET /_cat/shards?v&s=state | Shards including unassigned reasons |
GET /_cat/allocation?v&bytes=gb | Per-node allocation and disk |
GET /_cat/fielddata?v&s=size:desc | Fielddata memory (6.x may need extra settings) |
GET /_cat/recovery?v&active_only=true | Active shard recovery |
---
Task layer
| Endpoint | Purpose |
|---|---|
GET /_cat/tasks?v&detailed=true | Running tasks with descriptions |
GET /_tasks?detailed=true | Task details (search/write timeouts) |
---
Snapshots and ILM
| Endpoint | Purpose |
|---|---|
GET /_snapshot/_status | In-flight snapshot operations |
GET /_cat/snapshots/<repo>?v | Snapshot list (repository required) |
GET /_ilm/status | ILM status (Elasticsearch 7.0+ only) |
---
Version compatibility
| ES version | Compatible endpoints | Not supported | Notes |
|---|---|---|---|
| 7.x – 8.x | 18 / 18 (100%) | — | Full |
| 6.x | 17 / 18 (94%) | _ilm/status | ILM introduced in 7.0 |
Notes
_ilm/status: ILM is not available on 6.x.- Do not use
?localon_cat/nodeson 8.x. _cat/fielddataon 6.x may require additional settings to return data.
---
Scenario quick map
| Scenario class | Primary endpoints |
|---|---|
| Cluster Red/Yellow, unassigned shards | POST /_cluster/allocation/explain + GET /_cat/shards |
| Sustained high CPU, hot threads | GET /_nodes/hot_threads + GET /_cat/nodes |
| JVM pressure, GC | GET /_nodes/stats/jvm + GET /_nodes/stats/breaker |
| Thread pool saturation / rejections | GET /_nodes/stats/thread_pool |
| Disk pressure, large indices | GET /_cat/allocation + GET /_cat/indices |
| Slow search/write, timeouts | GET /_cat/tasks + GET /_tasks?detailed=true |
| Snapshot failures | GET /_snapshot/_status + GET /_cat/snapshots/<repo> |
| Master backlog | GET /_cluster/pending_tasks |
| ILM issues | GET /_ilm/status |
Elasticsearch REST API diagnosis strategy (MUST rules)
This note captures Q&A from skill usage: when SKILL.md says ES APIs are MUST, why some paths still rely on control plane + CMS only, and how skill text relates to tooling.
When `curl` fails (401, timeouts, refused): use the progressive guide es-api-call-failures.md first, then return here for MUST / SHOULD rules.
SKILL alignment: MUST-trigger workflow (reachability including ES_* and endpoint match, then required `curl` per fired row) is normative in SKILL.md §5 (Binding rule (MUST triggers)), Step 2, and §7. The CMS tables in this file are supplementary; if workflow nuance differs, follow `SKILL.md` for agent execution.
---
1. Decision rules in the skill (evidence-driven)
Calling engine-layer curl (REST) needs both:
| Condition | Meaning |
|---|---|
| Executable | ES_ENDPOINT and ES_PASSWORD are set, path to port 9200 works (scheme, allowlists, security group, etc.). |
| Necessary | Root-cause reasoning needs engine-layer proof that control plane / CMS cannot supply or refute. |
Summary
- MUST (run ES APIs)
- Cluster Red/Yellow: unassigned shard reasons, allocation filters.
- Search/write performance: thread pools, rejections, hot threads, breakers, task backlog.
- Cases where control plane looks fine but the engine is not.
- SHOULD (prefer ES APIs)
- CPU/memory/load anomalies that disagree with control-plane signals — cross-check.
- Post-change incidents — confirm stuck recovery or long-running tasks on the engine.
- CAN SKIP
- Root cause is already closed on the control plane and engine data would not change the answer (e.g. clear RAM denial, instance in a controlled change window, billing/resource state making the instance unavailable).
---
2. MUST trigger signals (CMS)
Treat as MUST when any of the following CMS signals appear:
| CMS signal | MUST theme | Typical ES API evidence |
|---|---|---|
ClusterStatus max ≥ 1 (Yellow) or ≥ 2 (Red) | Cluster health | /_cluster/allocation/explain, /_cat/shards |
ClusterDisconnectedNodeCount max > 0 | Node loss | /_cat/nodes, /_cluster/health |
NodeCPUUtilization max > 80% | CPU overload | /_nodes/hot_threads, /_tasks |
NodeHeapMemoryUtilization max > 85% | Memory pressure | /_nodes/stats/jvm, /_nodes/stats/breaker |
NodeDiskUtilization max > 85% | Disk pressure | /_cat/allocation, /_cat/shards |
Thread pool rejected > 0 on any node | Performance | /_nodes/hot_threads, /_nodes/stats/thread_pool |
| CPU / memory / disk CV > 0.3 across nodes | Imbalance | /_cat/shards, /_cat/allocation |
| Every diagnosis (ALWAYS) | Disk watermarks / index read-only | /_cluster/settings, /_all/_settings?filter_path=*.settings.index.blocks, /_cat/allocation |
Intermittent ES API timeouts + NodeCPUUtilization > 80% | Possible meltdown | /_nodes/hot_threads, /_nodes/stats/thread_pool, /_tasks |
Mandatory hint: If a MUST situation is detected and ES_ENDPOINT is not set, the report must start with a warning listing the missing engine-layer evidence.
---
2.5 ALWAYS checks (when ES is reachable)
These do not wait on CMS thresholds; run whenever `ES_ENDPOINT` (and password) is available:
| Check | ES API | What it catches | Why |
|---|---|---|---|
| Watermark settings | GET _cluster/settings?include_defaults=true&filter_path=**.watermark | Absolute-byte or bad % watermarks | CMS disk % can look fine while transient watermarks already force read-only |
| Index read-only blocks | GET _all/_settings?filter_path=*.settings.index.blocks | read_only_allow_delete: true | Cluster can be Green with “normal” disk % while indices are already read-only from flood_stage |
| Free space vs absolute watermark | GET _cat/allocation?format=json&bytes=b | Free bytes below absolute flood_stage | Only needed when watermarks use absolute bytes; % breach is compared to CMS in the script |
Rationale (watermark edge case): Low disk utilization and cluster Green can still coexist with transient absolute-byte watermarks that block writes. CMS-only views miss that class of misconfiguration.
---
3. Why sometimes only control plane + CMS?
MUST addresses necessity: in the situations above, methodology says you should use engine APIs for deep proof.
But the skill also states executable preconditions. If ES_ENDPOINT / ES_PASSWORD are missing, or TCP to 9200 fails, curl cannot run. Then you can only:
- Use
aliyunCLI + CMS + logs; - State the evidence boundary in the report: no ES REST path — no engine-level root cause.
So: not “MUST can be skipped on purpose”, but “MUST cannot run until preconditions hold.”
---
3.5 Connection failures — differentiate patterns
Full playbooks (credential probe, HTTP 401 meaning, exit 28 triage, intermittent timeouts, evidence boundary, report checklist): es-api-call-failures.md
Summary table (read the linked doc for steps):
| Pattern | Typical symptom | First pointer |
|---|---|---|
| Refused | curl exit 7 | Process / port / public access — sop-cluster-health.md |
| Persistent timeout | exit 28, all calls | Allowlist + CMS triage — not “network only by default” |
| Intermittent timeout | mixed success | Overload / meltdown — sop-service-avalanche.md |
| Auth failure | HTTP 401 | ES_PASSWORD / ES_USERNAME / scheme |
| TLS mismatch | wrong version errors | http:// vs https:// on ES_ENDPOINT |
---
4. Documentation vs check_es_instance_health.py today
When ES_ENDPOINT and ES_PASSWORD are set, _check_cluster_config_optional automatically calls:
| Area | API | Role |
|---|---|---|
| Liveness | GET /_cluster/health | Fail fast if ES is unreachable |
| Settings | GET /_cluster/settings?include_defaults=true | Fielddata breaker + disk watermark rules (incl. absolute-byte branch with /_cat/allocation?format=json&bytes=b when needed) |
| Replicas | GET /_cat/indices?h=index,rep&format=json | Business indices with number_of_replicas=0 |
| Read-only | GET /_all/_settings?filter_path=*.settings.index.blocks | read_only_allow_delete blocks |
| Thread pools | GET /_nodes/stats/thread_pool | Non-zero rejected counters |
Finding remediation text may recommend /_cluster/allocation/explain, /_cat/shards, /_nodes/hot_threads, etc. Those are operator / agent next steps — the script does not HTTP-fetch hot_threads or allocation/explain bodies by itself. When rule findings imply a §5 MUST row, check_es_instance_health.py prints a short §5 MUST — engine APIs footer (deduped paths); the agent must still execute those calls after §2.2 reachability.
Skill / agent workflow: for Red/Yellow, thread-pool saturation, and other MUST rows in SKILL.md, the agent should still run the listed curl (or Console) steps to collect engine evidence beyond what the script auto-pulls.
Planned vs implemented
Older drafts described stderr banners such as [MUST采集] … auto allocation/explain. That auto-fetch is not in the current script — allocation/explain and hot_threads bodies remain manual MUST. The script may print a §5 MUST — engine APIs footer (stdout) when findings map to SKILL.md §5; that is a checklist, not an HTTP substitute.
---
5. Summary
| Question | Answer |
|---|---|
| MUST scenarios — must ES APIs be used? | Methodologically yes, for evidence control plane/CMS cannot replace. |
| Why sometimes not? | Usually executable preconditions fail (no creds, no route, wrong endpoint). |
| What does the health script auto-call? | Health + cluster settings (breakers/watermarks) + zero-replica cat + read-only settings + thread-pool stats — not allocation/explain or hot_threads bodies. |
| Practical advice | When 9200 is reachable, set env vars; run additional MUST curls from SKILL.md / SOPs where the script stops at recommendations. |
---
6. Related references
- Main skill:
../SKILL.md(workflow, credentials, direct ES access) - REST call failures (progressive): es-api-call-failures.md
- Cluster health SOP:
sop-cluster-health.md - Performance SOPs:
sop-write-performance.md,sop-query-thread-pool.md
Elasticsearch health event catalog
18 event codes / 49 reason codes across 8 categories. Each row: reason code under its event code.
---
Quick nav: TOP 15 by case frequency
| Rank | Reason code | Event code | Priority | Threshold (summary) | SOP |
|---|---|---|---|---|---|
| 1 | CPU.PeakUsageHigh | HealthCheck.CPULoadHigh | P1 | P99 > 95% for 3m | sop-cpu-load.md |
| 2 | JVMMemory.OldGenUsageCritical | HealthCheck.JVMMemoryPressure | P0 | avg > 85% for 2m | sop-memory-gc.md |
| 3 | Node.Disconnected | HealthCheck.ClusterUnhealthy | P0 | disconnected nodes > 0 for 10m | sop-cluster-health.md |
| 4 | CPU.PersistUsageHigh | HealthCheck.CPULoadHigh | P0/P1 | avg > 70% (P0) / > 60% (P1) for 10m | sop-cpu-load.md |
| 5 | JVMMemory.GCRateTooHigh | HealthCheck.JVMMemoryPressure | P1 | Old GC > 1/min for 10m | sop-memory-gc.md |
| 6 | Disk.UsageCritical | HealthCheck.DiskUsageHigh | P0 | max > 85% for 5m | sop-disk-storage.md |
| 7 | JVMMemory.OldGenUsageHigh | HealthCheck.JVMMemoryPressure | P1 | avg > 75% for 5m | sop-memory-gc.md |
| 8 | ThreadPool.WriteRejected | HealthCheck.ThreadPoolSaturation | P0 | write rejected > 0.1/s and TPS > 1/s | sop-write-performance.md |
| 9 | JVMMemory.GCTimeRatioTooHigh | HealthCheck.JVMMemoryPressure | P0 | GC time / wall clock > 10% for 5m | sop-memory-gc.md |
| 10 | ThreadPool.WriteQueueHigh | HealthCheck.ThreadPoolSaturation | P0 | write queue > threads×80% for 5m | sop-write-performance.md |
| 11 | ThreadPool.SearchRejected | HealthCheck.ThreadPoolSaturation | P0 | search rejected > 0.1/s and QPS > 1/s for 5m | sop-query-thread-pool.md |
| 12 | Balancing.NodeCPUUnbalanced | HealthCheck.LoadUnbalanced | P1 | CPU CV > 0.3 for 10m | sop-cpu-load.md |
| 13 | Disk.UsageHigh | HealthCheck.DiskUsageHigh | P1 | max > 75% for 10m | sop-disk-storage.md |
| 14 | ThreadPool.SearchQueueHigh | HealthCheck.ThreadPoolSaturation | P0 | search queue > threads×80% for 5m | sop-query-thread-pool.md |
| 15 | Cluster.StatusRed | HealthCheck.ClusterUnhealthy | P0 | ClusterStatus == 2 for 2m | sop-cluster-health.md |
---
1. Cluster health (3 reason codes)
Event code: HealthCheck.ClusterUnhealthy
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Cluster.StatusRed | P0 | ClusterStatus == 2 for 2m | 1 | ClusterStatus | Node loss / disk full / allocation misconfiguration |
Cluster.StatusYellow | P1 | ClusterStatus == 1 for 30m | 2 | ClusterStatus | Too few nodes / disk pressure / change in progress |
Node.Disconnected | P0 | ClusterDisconnectedNodeCount > 0 for 10m | 3 | ClusterDisconnectedNodeCount | OOM / CPU pegged / disk full / network |
Log-based (no CMS rule):Cluster.UnavailableShards—UnavailableShardsExceptionin logs, primary inactive; same event codeHealthCheck.ClusterUnhealthy.
Metric source: ClusterStatus, ClusterDisconnectedNodeCount from CMS (fetch_metrics_batch).
---
2. Master stability (3 reason codes)
Event code: HealthCheck.MasterStabilityRisk
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Master.TasksPendingCritically | P0 | pending_tasks > node_count×50 for 3m | 4 | metric TBD | Small master / huge shard count / ILM backlog |
Master.TasksPendingHigh | P1 | pending_tasks > 50 for 5m | 5 | same | Same, early warning |
Master.ElectionTooMany | P0 | Master elections > 0 in 1h | 6 | same | Master OOM / network / CPU pegged / long GC pauses |
Metric status:ClusterPendingTasksCount,MasterElectionCountnot in CMS yet — collect via ES API (GET _cluster/pending_tasks,GET _cat/master).
---
3. Service availability (1 reason code)
Event code: HealthCheck.ClusterRequestError
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Cluster.RequestErrorTooHigh | P1 | HTTP 5xx rate > 5% and QPS > 1/s for 3m | 7 | ClusterRequest5xxQPS | Version bug / resource exhaustion / metadata issues |
Historical typo Cluster.RequstErrorTooHigh may appear in older exports; canonical name: `Cluster.RequestErrorTooHigh`.---
4. Resource anomalies (17 reason codes)
4.1 JVM memory pressure
Event code: HealthCheck.JVMMemoryPressure
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
JVMMemory.OldGenUsageHigh | P1 | heap avg > 75% for 5m | 8 | NodeHeapMemoryUtilization | Small heap / heavy queries / fielddata / leak |
JVMMemory.OldGenUsageCritical | P0 | heap avg > 85% for 2m | 9 | NodeHeapMemoryUtilization | Same, more urgent |
JVMMemory.HeapGrowthRateFast | P1 | +9% in 3m and +15% in 15m | 10 | NodeHeapMemoryUtilization | Bulk queries / leak / traffic spike |
JVMMemory.GCRateTooHigh | P1 | Old GC > 1/min for 10m | 17 | JVMGCOldCollectionCount | Heap pressure / fielddata / large aggs |
JVMMemory.GCTimeRatioTooHigh | P0 | GC time / wall clock > 10% for 5m | 18 | JVMGCOldCollectionDuration | Old Gen pressure / frequent Full GC |
JVMMemory.GCDurationTooLong | P0 | avg GC duration > 5000ms | 19 | JVMGCOldCollectionDuration | Bad G1 tuning / large heap objects |
JVMMemory.FielddataCacheTooLarge | P1 | Fielddata > 30% heap | 20 | metric TBD | text field aggs / unbounded fielddata |
JVMMemory.BreakerTripped | P0 | breaker trips ≥ 5 per 5m | 35 | metric TBD | Huge result sets / fielddata blow-up / heavy aggs |
JVMMemory.BreakerLimitConfigLow | P2 | indices.breaker.fielddata.limit < 40% (settings check, ES API) | — | GET /_cluster/settings | Limit below recommendation — small aggs can trip |
JVMMemory.OOM | P0 | OutOfMemoryError in logs | — | instance logs | OldGen full / fielddata explosion |
4.2 High CPU
Event code: HealthCheck.CPULoadHigh
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
CPU.PeakUsageHigh | P1 | CPU P99 > 95% for 3m | 11 | NodeCPUUtilization | Heavy queries / ingest / GC / imbalance |
CPU.PersistUsageHigh (P0) | P0 | CPU avg > 70% for 10m | 12 | NodeCPUUtilization | Sustained load — node loss risk |
CPU.PersistUsageHigh (P1) | P1 | CPU avg > 60% for 10m | 12 | NodeCPUUtilization | Same, warning band |
CPU.UsageGrowthRateFast | P0 | +9% in 3m and +15% in 15m | 15 | NodeCPUUtilization | Slow requests / burst traffic |
CPU.PersistUsageHigh uses dual thresholds: avg > 70% → P0, 60–70% → P1 (same reason_code, different priority).4.3 Disk utilization
Event code: HealthCheck.DiskUsageHigh
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Disk.UsageHigh | P1 | max > 75% for 10m | 13 | NodeDiskUtilization | Data growth / snapshots not cleaned |
Disk.UsageCritical | P0 | max > 85% for 5m | 14 | NodeDiskUtilization | Near ES flood-stage (~95%) read-only |
Disk.UsagePredictiveRisk | P1 | predict_linear shows < 5% free in 24h | 22 | NodeDiskUtilization | Upward trend |
Disk.IndexReadOnly | P0 | block count > 0 | 36 | ClusterIndexWritesBlocked | Disk ≥95% auto read-only |
Disk.WatermarkAbsoluteFloodBreached | P0 | free bytes < absolute flood_stage | — | ES API: _cluster/settings + _cat/allocation | Absolute watermark tripped |
Disk.WatermarkAbsoluteFloodMarginLow | P1 | free space barely above flood_stage (margin < 500MB) | — | ES API: same | Absolute watermark, tiny margin |
Disk.WatermarkAbsoluteValue | P1 | watermarks configured as absolute bytes (not %) | — | ES API: _cluster/settings | Non-default — does not scale with disk growth |
4.4 Disk IO
Event code: HealthCheck.DiskIOBottleneck
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Disk.IOPerformancePoor | P0 | IO util > 90% for 5m | 19 | NodeStatsDataDiskUtil | Slow disk / bad disk / heavy write / merges |
Disk.IOBandwidthThrottling | P0 | disk bandwidth util > 90% for 5m | 16 | NodeStatsDataDiskIoCloudDiskBaseBandwidthRate | Cloud disk cap / concentrated write |
IO rule priority was P1 → updated to P0 (rule #19).
4.5 File descriptors
Event code: HealthCheck.SystemFileDescriptorsHigh
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
System.FileDescriptorsUsageHigh | P0 | open_fd / max_fd > 90% for 10m | 21 | metric TBD | Too many connections / shards / leaks |
---
5. Performance bottlenecks (10 reason codes)
5.1 Thread pool saturation
Event code: HealthCheck.ThreadPoolSaturation
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
ThreadPool.SearchQueueHigh | P0 | search queue > threads×80% (or > 100) for 5m | 23 | SearchThreadpoolQueue | Slow queries / high QPS / low CPU headroom |
ThreadPool.SearchRejected | P0 | search rejected > 0.1/s and QPS > 1/s for 5m | 24 | SearchThreadpoolRejected | Queue full — new searches rejected |
ThreadPool.WriteQueueHigh | P0 | write queue > threads×80% (or > 100) for 5m | 25 | WriteThreadpoolQueue | Heavy ingest / slow disk / low CPU |
ThreadPool.WriteRejected | P0 | write rejected > 0.1/s and TPS > 1/s for 5m | 26 | WriteThreadpoolRejected | Queue full — writes rejected (HTTP 429) |
ThreadPool.GenericQueueHigh | P1 | generic queue > threads×80% for 10m | 27 | metric TBD | High recovery concurrency / node_concurrent_recoveries too high |
5.2 High latency
Event code: HealthCheck.LatencyHigh
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Latency.IndexingSlow | P0 | indexing latency > 1000ms and QPS > 5/s for 1m | 28 | ClusterIndexingLatency | Slow disk / CPU / aggressive refresh |
Latency.SearchSlow | P0 | search latency > 2000ms and QPS > 5/s for 1m | 29 | ClusterSearchLatency | Slow queries / CPU / memory / cold data |
Latency.SearchTaskRunningLong | P1 | search task runtime > 5 minutes | 30 | metric TBD | delete_by_query / reindex / heavy aggs |
Latency.RefreshSlow | P1 | refresh > 1000ms for 5m | 31 | metric TBD | Too many segments / many fields / complex mappings |
5.3 Slow recovery
Event code: HealthCheck.RecoverySlow
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Recovery.SlowWarning | Info | recovery rate < 50% of configured cap or ETA > 4h | 45 | metric TBD | Low recovery throttle / slow disk / limited bandwidth |
---
6. Capacity planning (6 reason codes)
6.1 Shard misconfiguration
Event code: HealthCheck.ShardMisconfigured
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Shard.SegmentCountTooMany | P1 | segments > 100 per node for 30m | 32 | metric TBD | Rare forcemerge / short refresh interval |
Shard.TotalCountTooMany | P1 | total shards > nodes×CPU×20 for 1h | 41 | ClusterShardCount | Too many indices / shards per index |
Shard.SizeUnreasonable | P2 | avg shard < 10GB or > 50GB for 1h | 42 | metric TBD | Wrong shard count / bad sizing |
Shard.DocumentNearLimit | P0 | docs per shard > 2B (Lucene ~2.1B cap) for 30m | 43 | metric TBD | No rollover / ILM |
Shard.NodeCountTooHigh | P1 | shards per node > 1000 for 30m | 44 | metric TBD | Too many shards / too few nodes |
6.2 Load imbalance
Event code: HealthCheck.LoadUnbalanced
Imbalance spans traffic, data placement, and resource levels. See sop-node-load-imbalance.md.
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Balancing.NodeCPUUnbalanced | P1 | CPU CV > 0.3 for 10m | 40 | NodeCPUUtilization | Hot shards / no coordinating nodes / skew |
Balancing.NodeTrafficUnbalanced | P1 | QPS/TPS CV > 0.3 for 10m | — | thread pool active/queue | No coordinating nodes / uneven clients / routing skew |
Balancing.NodeDataUnbalanced | P2 | shard count or store CV > 0.3 for 30m | — | _cat/allocation | New nodes / large index concentration / routing skew |
Balancing.NodeDiskUnbalanced | P1/P0 | disk util CV > 0.3, hot node >75% (P1) / >85% (P0) | — | NodeDiskUtilization | Large shards on few nodes / old data |
Balancing.NodeMemoryUnbalanced | P1 | heap util CV > 0.3 and max node > 75% for 10m | — | NodeHeapMemoryUtilization | Fielddata skew / hot query caches |
---
7. High-availability risk (4 reason codes)
7.1 Cluster scale
Event code: HealthCheck.ClusterScaleLow
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Scale.NodesInsufficient | P1 | total nodes < 3 for 10m | 33 | ClusterNodeCount | Nodes lost / under-provisioned |
Scale.MasterEligibleNodesInsufficient | P1 | master-eligible < 3 for 5m | 39 | metric TBD | No dedicated masters / master nodes down |
7.2 Missing replication
Event code: HealthCheck.ReplicationMissing
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Replication.MissingReplicas | P1 | index with 0 replicas and no snapshot | 37 | metric TBD | Manual setting / leftover during resize |
7.3 Backup failure
Event code: HealthCheck.BackupFailure
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Backup.SnapshotFailed | P0 | auto snapshot status == 2 (failed) | 34 | ClusterAutoSnapshotLatestStatus | Space / permissions / cluster load |
Backup.SnapshotOutdated | P2 | no successful snapshot for 24h | 38 | metric TBD | Policy missing / repeated failures |
---
8. Configuration risk (3 reason codes)
Event code: HealthCheck.ConfigurationRisk
| Reason code | Priority | Trigger | Rule # | Key metrics | Typical root cause |
|---|---|---|---|---|---|
Config.JVMGCStrategyNotOptimal | Info | Old GC rate > 1/min for 30m | 46 | JVMGCOldCollectionCount | CMS instead of G1 / wrong heap sizing |
Config.RiskClusterSettings | P1 | concurrent_rebalance > 16 or concurrent_recoveries > 8 or recovery > 200MB/s | 47 | metric TBD | Ops tuned migration too hot for nodes |
Config.RiskndexSettings | P1 | Ngram max_gram > 100, or too many shards on small index, or 0 replicas without snapshot | 48 | metric TBD | Bad Ngram / shard planning |
---
Appendix A: Threshold cheat sheet (health script subset)
Thresholds implemented in scripts/check_es_instance_health.py (baseline 20260318) may differ slightly from CMS-only rule numbers below — use the script THRESHOLDS for ground truth.
| Metric | Warning (P1) | Critical (P0) | reason_code |
|---|---|---|---|
| Heap utilization | avg > 75% | avg > 85% | JVMMemory.OldGenUsageHigh / Critical |
| CPU sustained | avg > 60% | avg > 70% | CPU.PersistUsageHigh |
| CPU peak | — | max ≥ 95% (with sustained avg ≤ 60%) | CPU.PeakUsageHigh (P0); 80–94% band → P1 |
| Disk utilization | max > 75% | max > 85% | Disk.UsageHigh / Critical |
| Disk IO util | — | max > 90% | Disk.IOPerformancePoor |
| Old GC rate | > 1/min (max in window) | — | JVMMemory.GCRateTooHigh |
| GC time ratio | — | > 10% of wall time | JVMMemory.GCTimeRatioTooHigh |
| CPU imbalance CV | CV > 0.3 (with CPU floor) | — | Balancing.NodeCPUUnbalanced |
---
Appendix B: How metrics are collected
Available via CMS fetch_metrics_batch
References: Basic metrics (Alibaba Cloud Help) |
Cluster metrics guide
ClusterStatus Cluster health (0=Green, 1=Yellow, 2=Red)
ClusterAutoSnapshotLatestStatus Snapshot status (-1=none/0=ok/1=running/2=failed)
ClusterDisconnectedNodeCount Disconnected node count
ClusterNodeCount Node count
ClusterShardCount Total shard count
ClusterQueryQPS Cluster search QPS
ClusterIndexQPS Cluster indexing QPS
ClusterSearchLatency Avg search latency (ms)
ClusterIndexingLatency Avg indexing latency (ms)
ClusterSlowSearchingCount Slow query count
NodeCPUUtilization Node CPU (%)
NodeHeapMemoryUtilization Node heap (%)
NodeDiskUtilization Node disk (%)
NodeFreeStorageSpace Free storage (MiB)
NodeLoad_1m 1m load
NodeStatsDataDiskUtil Disk IO utilization (%)
NodeStatsDataDiskRm Disk read bandwidth (MiB/s)
NodeStatsDataDiskWm Disk write bandwidth (MiB/s)
NodeStatsDataDiskR Read IOPS
NodeStatsDataDiskW Write IOPS
JVMGCOldCollectionCount Old GC count (per sample bucket)
JVMGCOldCollectionDuration Old GC duration ms (per sample bucket)
NodeStatsFullGcCollectionCount Full GC count
NodeStatsExceptionLogCount Exception log count
...Requires additional ES API (for deeper diagnosis)
# Thread pools (ThreadPool.*)
GET _nodes/stats/thread_pool?filter_path=nodes.*.thread_pool
# Breakers (JVMMemory.BreakerTripped)
GET _nodes/stats/breaker
# Heap / mem (JVMMemory.FielddataCacheTooLarge)
GET _nodes/stats/jvm?filter_path=nodes.*.jvm.mem
# Running tasks (Latency.SearchTaskRunningLong)
GET _tasks?detailed=true
# Pending tasks (Master.TasksPending*)
GET _cluster/pending_tasks
# Shard states (Cluster.StatusRed/Yellow)
GET _cat/shards?v&s=state&h=index,shard,prirep,state,node,unassigned.reason
# Unassigned reason
GET _cluster/allocation/explain
# Recovery (Recovery.SlowWarning)
GET _cat/recovery?v&active_only=true
# Snapshots (Backup.*)
GET _cat/snapshots?v
# ILM (often tied to Master.TasksPending*)
GET _ilm/status
# Read-only blocks (Disk.IndexReadOnly / watermarks)
GET _all/_settings?filter_path=*.settings.index.blocks
# or
GET _cat/indices?v&h=index,status,health
# Watermarks (Disk.WatermarkAbsolute*)
GET _cluster/settings?include_defaults=true&filter_path=**.watermark,**.flood_stage
GET _cat/allocation?format=json&bytes=bRAM permission list
Minimum read-only RAM permissions required for this skill (no write actions):
Alibaba Cloud Elasticsearch OpenAPI
elasticsearch:DescribeInstance— Instance details (including clusterTasks)elasticsearch:ListInstance— List instanceselasticsearch:ListSearchLog— Instance runtime logselasticsearch:ListActionRecords— Instance change / action recordselasticsearch:ListAllNode— Cluster node information
Cloud Monitor (CMS)
cms:DescribeMetricList— Time-series metrics (CPU, memory, disk, load, cluster health)cms:DescribeSystemEventAttribute— System events (control-plane changes, restarts, etc.)cms:DescribeMetricMetaList— Metric metadata (available metric catalog)
Optional but recommended
sts:GetCallerIdentity— Validate the CLI profile (aliyun sts get-caller-identity)
Runtime dependencies
aliyun CLI >= 3.3.1
curlReferences (references/)
Operational knowledge for the Alibaba Cloud Elasticsearch instance diagnosis skill: APIs, verification, event catalog, acceptance rules, and scenario SOPs (sop-*.md).
Discoverability: skill trigger keywords (including 中文 for Chinese-speaking users) live in repo root `SKILL.md` frontmatter and `metadata.yaml` (triggers). Markdown here stays English; triggers bridge user language to the skill.
---
Index
APIs and access
| File | Purpose |
|---|---|
| related-apis.md | Related Alibaba Cloud OpenAPIs for diagnosis |
| es-api-catalog.md | Elasticsearch REST endpoints used in workflows |
| ram-policies.md | RAM policy snippets for CLI / OpenAPI |
Verification, strategy, and quality bar
| File | Purpose |
|---|---|
| verification-method.md | How to verify diagnosis (metrics, logs, APIs) |
| report-template.md | Structured diagnosis report skeleton (Markdown) |
| es-api-diagnosis-strategy.md | When to call which ES API; CMS vs engine; MUST summary |
| es-api-call-failures.md | Progressive: curl failures (401, timeouts, refused), evidence boundary, report checklist |
| acceptance-criteria.md | PASS / PARTIAL / expectations; §6.1 Red/Yellow + ClusterStatus one voice (CMS window vs engine snapshot) + CMS `ClusterShardCount` swings (cross-check engine + ops, avoid “half shards lost”); §6.2 read-heavy CPU + search pool + CPU table vs log hotspot + slow-log node vs search-pool node (routing / phase / time); §6.3 JVM / breakers / fielddata; §6.4 write-queue narrative (dual P0 or causal lead + rejected/completed quant) / GC / bulk / tripped vs current heap; §6.5 search vs GC headline; `search.rejected` ≫ `write.rejected` → search-first P0/executive order; §6.6 timeline / recency-weighted executive lead (search vs write by time) |
| health-events-catalog.md | CMS-style events ↔ skill findings |
Tooling
| File | Purpose |
|---|---|
| cli-installation-guide.md | Aliyun CLI install and configure |
Scenario SOPs (sop-*.md)
| File | Typical signals |
|---|---|
| sop-activating-change-stuck.md | Long activating, change records + engine Red |
| sop-cluster-health.md | Red/Yellow, node loss, pending tasks, master election |
| sop-configuration.md | Risky cluster/index settings, API error rate, slow recovery |
| sop-cpu-load.md | Sustained or peak CPU, load imbalance |
| sop-disk-storage.md | Disk watermarks, IO bottleneck, read-only / flood |
| sop-memory-gc.md | Heap pressure, GC, circuit breakers, OOM |
| sop-node-load-imbalance.md | CPU / traffic / data skew (CV-style imbalance) |
| sop-query-thread-pool.md | Search rejects, queue, slow queries |
| sop-service-avalanche.md | “Node down” but process up; all shards failed + high CPU |
| sop-write-performance.md | Write rejects, ingest latency, indexing dropped |
---
For agents
1. Follow the workflow in the repo root [`SKILL.md`](../SKILL.md) (especially the signal → SOP routing table). 2. Prefer `SKILL.md` over ad-hoc reading order; open SOPs only when the observed signal matches. 3. Report text and evidence keys in `scripts/check_es_instance_health.py` are English — keep doc examples aligned (e.g. cluster_status_latest, affected_nodes, configured_watermark_low).
---
Contributing
Edits to references should stay consistent with `SKILL.md` and the checker script’s field names. Prefer small, accurate updates over duplicating long procedures that already live in a SOP.
Related APIs
Complete list of Alibaba Cloud OpenAPIs and Elasticsearch REST APIs used by this skill.
---
Control plane (OpenAPI)
OpenAPI action names follow the official Alibaba Cloud API (PascalCase), e.g. Elasticsearch API and CloudMonitor (CMS) API. Use the Aliyun CLI plugin subcommands (lowercase-hyphenated) when showing shell examples.
Elasticsearch OpenAPI
| Product | API action | Description | Entry point |
|---|---|---|---|
| elasticsearch | DescribeInstance | Instance details (status, version, cluster-related fields) | check_es_instance_health.py / openapi_cli_collect.py |
| elasticsearch | ListInstance | List instances | aliyun elasticsearch list-instance |
| elasticsearch | ListSearchLog | Instance logs (instance, slow, GC, etc.) | check_es_instance_health.py / openapi_cli_collect.py |
| elasticsearch | ListActionRecords | Change / action records | aliyun elasticsearch list-action-records |
| elasticsearch | ListAllNode | Cluster node information | aliyun elasticsearch list-all-node |
Alibaba Cloud Monitor (CMS) OpenAPI
| Product | API action | Description | Entry point |
|---|---|---|---|
| cms | DescribeMetricList | Time-series metrics | check_es_instance_health.py / openapi_cli_collect.py |
| cms | DescribeSystemEventAttribute | System events | check_es_instance_health.py / openapi_cli_collect.py |
| cms | DescribeMetricMetaList | Metric metadata (available metric catalog) | aliyun cms describe-metric-meta-list |
---
Data plane (Elasticsearch REST API)
Cluster health and state
| API | Endpoint | Description | Invocation |
|---|---|---|---|
| Cluster health | GET /_cluster/health | Cluster health (green/yellow/red) | curl |
| Cluster stats | GET /_cluster/stats | Cluster statistics | curl |
| Pending tasks | GET /_cluster/pending_tasks | Master pending tasks | curl |
| Allocation explain | POST /_cluster/allocation/explain | Unassigned shard reasons | curl |
Nodes
| API | Endpoint | Description | Invocation |
|---|---|---|---|
| Nodes stats | GET /_nodes/stats | Node stats (CPU/memory/disk) | curl |
| Hot threads | GET /_nodes/hot_threads | Hot thread stacks | curl |
| Nodes JVM | GET /_nodes/stats/jvm | JVM statistics | curl |
| Thread pools | GET /_nodes/stats/thread_pool | Thread pool stats | curl |
| Circuit breakers | GET /_nodes/stats/breaker | Breaker trips | curl |
| Cat nodes | GET /_cat/nodes | Node overview | curl |
| Cat nodes CPU | GET /_cat/nodes?h=name,cpu,load_1m | CPU-oriented view | curl |
Indices and shards
| API | Endpoint | Description | Invocation |
|---|---|---|---|
| Cat indices | GET /_cat/indices | Index list | curl |
| Cat indices by size | GET /_cat/indices?s=store.size:desc | Indices sorted by size | curl |
| Cat shards | GET /_cat/shards | Shard layout | curl |
| Cat allocation | GET /_cat/allocation | Disk / shard allocation | curl |
Tasks and recovery
| API | Endpoint | Description | Invocation |
|---|---|---|---|
| Tasks | GET /_tasks | Running tasks | curl |
| Tasks detailed | GET /_tasks?detailed=true | Detailed tasks | curl |
| Cat tasks | GET /_cat/tasks | Task overview | curl |
| Cat recovery | GET /_cat/recovery | Shard recovery | curl |
Snapshots and ILM
| API | Endpoint | Description | Invocation |
|---|---|---|---|
| Snapshot status | GET /_snapshot/_status | In-flight snapshots | curl |
| ILM status | GET /_ilm/status | ILM status (Elasticsearch 7.0+) | curl |
---
Dependencies
aliyun CLI >= 3.3.1
elasticsearch>=7,<9 # client library if used by tooling (optional for curl-only path)---
Permissions
See ram-policies.md.
Structured diagnosis report (skeleton)
Use with [acceptance-criteria.md](acceptance-criteria.md) (§6.x) and repo root [SKILL.md](../SKILL.md) §5 Step 4. Copy the block below and fill placeholders.
Before publish: Reconcile ClusterStatus wording if CMS window max (e.g. Yellow) and a single /_cluster/health snapshot (e.g. green) both appear — qualify time vs aggregation (acceptance-criteria.md §6.1). If per-node CPU % seems to contradict which node was `search` pool–bound, add one sentence on sampling / window mean vs spike (acceptance-criteria.md §6.2). If slow-log node name ≠ node named in pool-rejection / INSTANCELOG lines, add one sentence on routing / phase / time (acceptance-criteria.md §6.2). If CMS `ClusterShardCount` (or similar) jumps (e.g. half then back), do not imply shard loss without `_cat/shards` + ops record cross-check (acceptance-criteria.md §6.1).
## Diagnosis summary
**Instance**: {instance_id} ({region_id})
**Analysis window**: {begin} ~ {end}
### Cross-layer root cause (required when `activating` coexists with Red / unassigned)
**One-line root cause**: {Chain per `sop-activating-change-stuck.md` section 4: change waiting for recovery ← Red ← allocation explain}
(Omit or mark “N/A” if there is no `activating` or the cluster is Green.)
### Incident timeline (recency-ordered)
{Earlier → later, or “latter-window emphasis”: which dimensions (search / write / GC / CPU / disk) peaked or persisted when; cite CMS peak times or log alignment}
### Findings (by priority)
#### P0 - Critical (immediate)
- [Event code] Description
- Evidence: {metrics / log keywords / events}
- Root-cause reasoning: {analysis}
- Immediate actions: {commands or steps}
#### P1 - Warning (within 30 minutes)
...
### Root-cause chain diagram
{Propagation path, e.g. disk full → shards cannot allocate → cluster Red}
### Open questions / follow-ups
{Uncertainties and next checks}SOP: Instance activating / change stuck
Covers: ManagementPlane.ActivatingStuck; often appears together with HealthCheck.ClusterUnhealthy (cluster Red) and unassigned shards on the engine.
Related: For engine-side Red / allocation, follow sop-cluster-health.md (Section 1 — cluster Red). This SOP explains the cross-layer causality between control-plane lifecycle activating and engine health — so the report does not only list “one control-plane line + one engine line” without a closed loop.
---
1. What activating means
activating is not a random standalone fault. It is the control-plane lifecycle state while a change has not finished (console / OpenAPI). Typical causes:
- Rolling orchestration after
RestartInstanceand similar; - Tasks still in
updating, e.g. plugin install/remove or config changes.
User experience: “The instance has been changing / activating for hours.”
---
2. Cross-layer causality (closed-loop root cause)
2.1 Control-plane facts
DescribeInstance:status == activating(or equivalent), often withupdatedAtto detect “stuck too long” (aligned with rule engineManagementPlane.ActivatingStuck).ListActionRecords: change type (e.g. rolling restart, plugin op), phase, timeline.ListAllNode: node roles, whether under rolling, abnormal nodes.
2.2 Orchestration constraint (why “change never finishes” shows as activating)
Many changes require the cluster to reach an acceptable health state (e.g. rolling waits for shard assignment, waits until the cluster is servicable) before the next step. If that condition cannot be met for a long time, the orchestration task stays in updating and the instance stays `activating`.
2.3 Engine-side closure (why “the cluster never recovers”)
Do not duplicate /_cluster/allocation/explain, _cat/shards, unassigned.reason playbooks here — use sop-cluster-health.md (Section 1 — cluster Red).
In the “long activating” context, remember: orchestration is waiting for “cluster can recover / shards can allocate”; the engine Red root cause still comes from allocation explain (e.g. allocation filter to a non-existent node, disk, allocation disabled). Until that is fixed, “wait for cluster recovery” may never succeed → instance stays activating.
Takeaway: On the control plane,activatingmeans “change not finished”. The technical closure that explains why it cannot finish is still `allocation/explain`, not a paraphrase ofactivatingtext instead of engine evidence.
2.4 Remediation order
1. When `activating` is confirmed, complete control-plane evidence before touching the engine: at least `DescribeInstance` + `ListActionRecords` (MUST), and `ListAllNode` is recommended. ListActionRecords gives change type (e.g. RestartInstance), phase, rolling progress, stuck node / pendingOperation, etc. Reporting only “activating + RestartInstance” without this API is an incomplete control-plane chain (a common gap when reviews expect full change-task evidence). 2. Then follow sop-cluster-health.md (Red / allocation section) for engine explain / shard root cause and fixes (delete index, change settings, etc.). 3. Before destructive or recovery actions (e.g. DELETE index, PUT allocation-related settings): keep a pre-action snapshot — same-moment DescribeInstance + ListActionRecords summary (or explicit timestamps and key fields) so the report can state “control-plane state while the change was stuck”. 4. After engine blockers are cleared, expect intermediate Yellow, throttling, same_shard, CMS lag, etc. while moving toward Green (see cluster-health SOP) — that is normal. Re-check control plane after remediation: `DescribeInstance` again (and `ListActionRecords` if needed) to see whether activating ended and to validate “engine recovered → change completed → lifecycle normalized”; if still activating, continue from the new records.
---
3. Evidence checklist (MUST / SHOULD)
| Dimension | Source | Requirement |
|---|---|---|
| Lifecycle | DescribeInstance | MUST: status, updatedAt, etc.; at least once before and after remediation |
| Change task detail | ListActionRecords | MUST whenever activating / change-stuck: type, progress, stuck or pending nodes; do not skip this call with only Describe text |
| Nodes | ListAllNode | SHOULD: rolling and abnormal nodes |
| Cluster health (control/CMS) | DescribeMetricList (ClusterStatus, etc.) | SHOULD: cross-check with engine |
| Engine root cause | allocation/explain, /_cat/shards | MUST when Red / unassigned: steps in sop-cluster-health Section 1 |
3.1 Recommended collection order
1. DescribeInstance → confirm activating and instance fields. 2. `ListActionRecords` → task detail (distinguish from “we guessed RestartInstance”: must come from API). 3. ListAllNode (recommended) → corroborate with change records. 4. Engine: allocation/explain, _cat/shards, etc. (cluster-health Red section). 5. Before risky remediation: another snapshot of DescribeInstance + ListActionRecords if time has passed since steps 1–2 or you are about to delete indices. 6. Execute remediation → watch _cluster/health / CMS for intermediate states. 7. After remediation: DescribeInstance (+ optional ListActionRecords) → confirm activating cleared.
---
4. Report expectations (skill template)
When both `activating` (or `ManagementPlane.ActivatingStuck`) and engine Red / unassigned primary exist:
- Do not write only “control plane and engine in parallel” with no causal link.
- Evidence must include a `ListActionRecords` summary (change type, phase/progress, abnormal or pending nodes), cross-checked with `DescribeInstance`; if remediation ran, add before/after control-plane comparison (Section 3.1 recommended collection order).
- Must add a one-line cross-layer root cause that states explicitly:
Change waiting for cluster recovery ← cluster stays Red ← concrete reason from allocation explain (e.g. require points to a non-existent node)
Example sentence (replace index name and explain conclusion with real values):
The rolling change on the control plane waits for cluster health; on the engine, index{index}hasindex.routing.allocation.require._namepointing at a non-existent node, so primaries cannot allocate and the cluster stays Red — orchestration cannot proceed → instance remainsactivating.
If there is no activating or the engine is already Green, write “N/A” or omit this subsection.
Related skills
FAQ
What data sources does it use?
Alibaba Cloud Elasticsearch OpenAPI (control plane), CloudMonitor, and the Elasticsearch REST API (data plane), plus SOP references.
How does it handle credentials?
It never reads, echoes, or prints AccessKeys or ES passwords and only uses profiles or environment variables set in the local shell.