PCA Mock Exam · Set 1
Forty-five multiple-choice questions, weighted question-for-question to the five domains of the official PCA curriculum — thirteen on PromQL, nine on Prometheus Fundamentals, eight each on Observability Concepts and Alerting & Dashboarding, seven on Instrumentation and Exporters. This is the first of two PCA papers on this course: it leans on definitions, the four metric types, and reading a PromQL expression cold — the same recall-first shape the real associate-level paper favours — before Set 2 pushes further into layered, multi-clue scenario traps. The PCA is a knowledge-based exam — no cluster, no terminal, nothing to break — so sit this one cold, in one uninterrupted block, with no documentation open. Answer first, then read the explanation directly beneath your choice; on a paper this heavy on PromQL, the explanation is doing as much teaching as the question itself, and the domain tag on every item tells you exactly which page to reread if you miss it.
This is a practice quiz, not a building exercise — you pick the best answer out of four, and it tells you straight away whether you got it right and why. The trick is answering before you check anything, even the ones you're only half-sure about, because a wrong answer here is free — it just points you back to the exact page you need to reread. There's no cluster to break and nothing to install; the whole test lives in your head, the same way the real one does.
How this paper is weighted
☺ Like you're 10: The questions are shared out the same way the real test shares out its marks — the biggest topic gets the most questions.
The PCA's five official domain weights — 28, 20, 18, 18, 16 — sum to exactly 100%, and against forty-five questions the arithmetic comes out almost too cleanly to be an accident. 28% of 45 is 12.6, 20% is 9.0, and each 18% is 8.1, with 16% landing at 7.2. Round each to the nearest whole question and you get 13, 9, 8, 8 and 7 — which sum to exactly 45, with nothing left over to argue about. That works because PromQL rounds up by 0.4 while the other four domains round down by a combined 0.4 (0 + 0.1 + 0.1 + 0.2): the rounding errors cancel exactly. So this paper's proportions track the real blueprint precisely, question for question — your score by domain is a faithful little mirror of where the real 100% actually goes.
| Domain | Official weight | Questions here | Where to revise |
|---|---|---|---|
| 🐘 PromQL | 28% | 13 | PCA — the exam · Prometheus |
| 🦉 Prometheus Fundamentals | 20% | 9 | Prometheus · PCA — the exam |
| 🐿️ Observability Concepts | 18% | 8 | The OpenTelemetry data model |
| 🐢 Alerting & Dashboarding | 18% | 8 | Grafana · PCA — the exam |
| 🦫 Instrumentation and Exporters | 16% | 7 | OpenTelemetry Collector |
Score your domains, not just your total. A 78% built from "solid everywhere except PromQL" is a much more dangerous result than the same 78% built from "strong everywhere, weak on Instrumentation," because PromQL alone carries nearly twice the weight of the smallest domain. Fix in weight order, not in the order you happened to notice the mistakes.
Sit it like the real thing
☺ Like you're 10: No notes, no open tabs, one sitting, straight through — and never leave a question blank, because a guess has a real chance of being right and a blank one never does.
The PCA is delivered online and remote-proctored, closed-book, with no documentation allowance — there is no "keep the Prometheus docs open" concession the way some hands-on exams grant, because there is no terminal to work in at all. Sit this paper the same way: close every other tab, set a single timer, and commit to an answer on every item even when you're genuinely unsure. Nothing published states whether Linux Foundation multiple-choice exams penalize a wrong guess beyond simply not earning the point — treat that as unconfirmed rather than fact — but the practical advice holds regardless: eliminate what you can, then commit. Never leave a question blank.
What's safe to state structurally: the PCA is a CNCF/Linux Foundation associate-level, knowledge-based multiple-choice exam — not hands-on like the five core Kubernetes exams in the Kubernetes course or a performance-based exam like the CNPE — delivered online under remote proctoring, with no formal prerequisite. Two numbers the Linux Foundation does publish and this paper is calibrated against: a 90-minute duration, and 75% or above to pass (the Linux Foundation's Multiple Choice Exam FAQ states this pass mark applies to every LF multiple-choice exam). What is not published is the real question count — third-party figures for it are unverified, so this paper's size of forty-five was chosen only because it divides the five domain weights with clean rounding, not because it matches a real number. Price, retake terms, eligibility window and certification validity are all revised over time too. Confirm everything on the official Linux Foundation PCA page and the CNCF certification page before you register or pay — this page is a study aid, not a substitute for reading them.
The paper — 45 questions across three blocks
☺ Like you're 10: Forty-five questions, three blocks, every domain mixed into every block — read the question, pick one answer (or two, when it says so), then check yourself before moving to the next.
Each question names its domain in parentheses so you can total your score by domain afterward — the real exam won't label them, so once you've sat this cold, consider a second pass with the labels covered to see how many you can still place from content alone. A couple of questions are marked (Select TWO); full credit there needs both correct letters.
Block 1 — Q1–15
Q1 (PromQL). Which label matcher below correctly selects every http_requests_total series where code is 500 or 503, for the job checkout?
- A.
http_requests_total{job="checkout", code="500|503"} - B.
http_requests_total{job="checkout", code=~"500|503"} - C.
http_requests_total{job="checkout", code!~"500|503"} - D.
http_requests_total{job!="checkout", code=~"500|503"}
Check the answer
B. =~ is the regex-match operator; a plain = never treats its value as a pattern, so option A is a literal (and non-matching) string comparison. Option C negates the match with !~, and option D excludes the checkout job entirely with !=.
Q2 (Prometheus Fundamentals). Which statement correctly describes the relationship between the Prometheus server and Alertmanager?
- A. Alertmanager runs inside the Prometheus server process and cannot be deployed separately
- B. The Prometheus server evaluates alerting rules itself and forwards any that are firing to Alertmanager, a separate process responsible for grouping, silencing, inhibition and routing to receivers
- C. Alertmanager scrapes targets directly; Prometheus only stores the resulting data
- D. Alertmanager and Prometheus communicate exclusively through the Pushgateway
Check the answer
B. Rule evaluation — deciding whether an alert should fire — happens inside the Prometheus server. Alertmanager is a distinct, separately deployed process that receives already-firing alerts and handles what happens next: grouping related ones, applying silences, inhibiting downstream noise, and routing to the right receiver.
Q3 (Observability Concepts). Which of these is the most accurate one-line definition of a "metric," as distinct from a log line or a trace span?
- A. A metric is a discrete record of one specific event, with full contextual detail attached
- B. A metric is a numeric measurement, usually aggregated over time, that answers a known question cheaply — at the cost of the fine-grained, per-event detail a log or trace preserves
- C. A metric can only ever describe CPU or memory usage
- D. A metric and a log are simply two names for the identical concept
Check the answer
B. Metrics trade detail for cheapness: they're numbers, typically pre-aggregated, that answer questions decided in advance — requests per second, memory in use. That's the opposite trade-off to a log line (rich per-event detail, expensive at scale) or a trace span (detail about one specific request's journey).
Q4 (Alerting & Dashboarding). What is a Grafana "panel," at its core?
- A. A raw, un-queried table of every metric ever scraped
- B. A single PromQL (or other data source) query paired with a chosen visualization — a graph, a single stat, a table — for one specific slice of data
- C. A synonym for an entire dashboard
- D. A configuration file that controls Alertmanager routing
Check the answer
B. A panel is the atomic unit of a dashboard: one query against a data source, rendered with one visualization type. A dashboard is a collection of panels arranged together, often sharing template variables so the same layout can serve many services without duplicating panels.
Q5 (Instrumentation and Exporters). An engineer instruments a new endpoint and needs to track request duration. Which client-library metric type is the correct default choice, and why?
- A. Gauge, because duration can be read directly at any moment
- B. Counter, because durations only ever increase over the service's lifetime
- C. Histogram, because it buckets observations into pre-chosen boundaries, letting a fleet-wide percentile like p99 be computed later with
histogram_quantile() - D. Summary, because it is always preferable to a histogram for latency
Check the answer
C. Latency is the textbook histogram use case: pre-chosen buckets let you compute an aggregatable, fleet-wide quantile after the fact. A gauge would only ever show the single last observed value, and a Summary's client-side quantiles — while sometimes appropriate — specifically cannot be aggregated across instances the way histogram buckets can.
Q6 (PromQL). Two engineers write these two expressions against the same counter. Which is correct, and why?Expr 1: sum(rate(http_requests_total[5m]))Expr 2: rate(sum(http_requests_total)[5m])
- A. Both are equivalent; PromQL is commutative here
- B. Expr 2 is correct, because summing first reduces the volume of data
rate()has to process - C. Expr 1 is correct —
rate()must run per-series on the raw counter first, so it can handle each series' own resets; summing first destroys that information - D. Neither is valid PromQL syntax
Check the answer
C. rate() needs to see one series' own counter history to detect and correct for that series' resets, such as a restart. Sum first and multiple independent counters get blended into one series with no meaningful reset pattern of its own — rate() second still returns a number, just not a correct one.
Q7 (Prometheus Fundamentals). In a scrape_config's relabel_configs, what does an action: keep step with a regex do?
- A. It renames the matched label to a new
target_label - B. It drops any target whose extracted source label value does NOT match the given regex, before the scrape ever happens
- C. It deletes the matched label from every sample after scraping
- D. It has no effect unless
metric_relabel_configsis also present
Check the answer
B. relabel_configs run before the scrape and decide which discovered targets are even scraped at all. An action: keep step is an allowlist: anything failing the regex is dropped from the target list entirely — how "only scrape pods with this annotation" opt-in scraping gets implemented.
Q8 (Observability Concepts). A deployment tool records "Deployment X rolled out at 14:02, revision 47." In observability terms, what is this record?
- A. A metric, because it has a timestamp
- B. A trace span
- C. An event — a discrete, timestamped record of something that happened once, distinct from both a continuously-sampled metric and a free-text log line
- D. A histogram bucket
Check the answer
C. An event is its own category: a discrete, structured, timestamped record of a specific occurrence — a deploy, a config change — that's neither a continuously-sampled numeric metric nor an unstructured log line. Dashboards often overlay events as annotations directly on metric graphs, because "what changed right before this moved" is such a common question.
Q9 (Alerting & Dashboarding). An alerting rule's expr has been true continuously for eight minutes, and its for: field is set to 10m. What is the alert's current state?
- A. Firing — any true expression fires immediately regardless of
for: - B. Pending — the condition is true but hasn't held continuously for the full
for:duration yet, so it hasn't transitioned to firing - C. Inactive —
for:overridesexprand the alert never fires until 10m have passed from rule creation - D. Resolved
Check the answer
B. for: requires the expression to keep evaluating true continuously across that whole duration before the alert is promoted from pending to firing. At eight minutes into a ten-minute requirement, it's still pending — exactly the mechanism that stops a brief, self-resolving blip from paging anyone.
Q10 (Instrumentation and Exporters). Instrumenting an HTTP handler, an engineer adds a raw url_path label containing the full, unsanitized request path — including path parameters like /users/48213. What's the risk?
- A. None — Prometheus deduplicates identical label values automatically
- B. Every distinct path value creates a new time series, so a path containing a variable ID effectively creates unbounded cardinality — the same failure mode as embedding a request ID or user ID directly in a label
- C. Prometheus caps label cardinality automatically at 1,000 series per metric
- D.
url_pathis a reserved label name and would be silently ignored
Check the answer
B. This is instrumentation-side cardinality risk, introduced directly in the code doing the instrumenting. A raw path containing an ID behaves exactly like a request ID or user ID label — a fresh, effectively unbounded value on every request. The fix is a normalized route template (/users/:id) as the label value instead of the literal path.
Q11 (PromQL). node_memory_MemAvailable_bytes is a gauge scraped every 15s. Which expression gives the lowest value that gauge took at any point in the last hour?
- A.
min(node_memory_MemAvailable_bytes[1h]) - B.
min_over_time(node_memory_MemAvailable_bytes[1h]) - C.
rate(node_memory_MemAvailable_bytes[1h]) - D.
increase(node_memory_MemAvailable_bytes[1h])
Check the answer
B. min_over_time() is an aggregation-over-time function and correctly accepts a range vector. min() aggregates over dimensions (across series), not time, and cannot take a range vector directly. rate() and increase() are for counters, not gauges.
Q12 (Prometheus Fundamentals). Which of the following is an accurate, exam-relevant limitation of Prometheus as shipped, out of the box?
- A. It is a clustered, horizontally-scalable database with unlimited retention by default
- B. It stores data locally on a single node and is not built for long-term retention on its own — long-term, globally-queryable storage is what projects like Thanos, Mimir or Cortex layer on top of it
- C. It cannot scrape more than one target at a time
- D. It requires a message queue between every target and the server
Check the answer
B. "Understanding Prometheus Limitations" is a named competency for a reason: a single Prometheus server keeps its TSDB locally and isn't a clustered, infinitely-retentive database on its own. Long-term storage and multi-tenant scale are explicitly the job of the ecosystem projects layered on top.
Q13 (Observability Concepts). A single user request touches five microservices before returning a response. Which observability signal is purpose-built to show exactly where time was spent across that whole call chain?
- A. A single Prometheus counter incremented once per request
- B. Distributed tracing — a tree of spans, each timing one hop, stitched together by a request ID propagated across all five services
- C. A dashboard's average latency panel
- D. A histogram with only two buckets
Check the answer
B. Distributed tracing is a tree of timed spans, one per hop, linked by a request ID (or trace ID) propagated service to service. A single aggregate metric can tell you the whole request was slow, but not which of the five hops actually cost the time.
Q14 (Alerting & Dashboarding). A single node failure causes fifty different alerting rules to fire almost simultaneously across every service on that node. Which Alertmanager feature exists specifically to stop this from becoming fifty separate pages?
- A. Silencing
- B. Grouping — collapsing related, simultaneously-firing alerts into a single notification
- C. Recording rules
- D. The Pushgateway
Check the answer
B. Grouping bundles alerts sharing common labels into one notification instead of firing individually — exactly the scenario a single node dying and taking fifty dependent alerts down with it is built for. Inhibition is the related-but-different mechanism for suppressing a downstream alert once a parent alert covering the same root cause is already firing.
Q15 (Instrumentation and Exporters). A team needs metrics from a machine with no Prometheus-aware code running on it at all — just an operating system. What's the standard tool for this?
- A. The Pushgateway
- B.
node_exporter, which reads OS-level metrics (CPU, memory, disk, network) and exposes them in the exposition format for Prometheus to scrape - C. Alertmanager, configured in "exporter mode"
- D. A custom client-library integration is always required; there is no standard exporter for this
Check the answer
B. node_exporter is the standard exporter for host-level metrics — it runs on the machine and translates kernel and OS statistics into the exposition format, needing zero changes to whatever software happens to be running there. It's the canonical example of what an "exporter" is for: translating something that doesn't natively speak Prometheus.
Block 2 — Q16–30
Q16 (PromQL). What does http_requests_total{job="checkout"}[5m] return on its own, without wrapping it in a function?
- A. A single number: the average rate over five minutes
- B. A range vector — every raw sample recorded for each matching series over the last five minutes — which cannot be graphed directly
- C. An instant vector with one sample per series, from exactly five minutes ago
- D. A syntax error; duration selectors can only be used inside
rate()
Check the answer
B. The [5m] duration selector converts an instant-vector selection into a range vector: every sample in that window, per series. It has to pass through a function like rate(), avg_over_time() or increase() before it collapses back down to something you can chart or read directly.
Q17 (Prometheus Fundamentals). In the global block of prometheus.yml, what does evaluation_interval control, as distinct from scrape_interval?
- A. It's a synonym for
scrape_intervalwith no functional difference - B. How often recording and alerting rules are evaluated against already-stored data — independent of how often targets are actually scraped
- C. How often Alertmanager checks for new silences
- D. The retention period of the local TSDB
Check the answer
B. scrape_interval controls how often data is pulled in; evaluation_interval controls how often the rule engine re-runs recording and alerting rule expressions against whatever's already stored. They're commonly set equal, but they govern two genuinely different loops.
Q18 (Observability Concepts). Which correctly characterizes Prometheus's default model, and its one built-in exception?
- A. Prometheus is entirely push-based; targets push metrics to it on their own schedule
- B. Prometheus pulls (scrapes) targets on an interval; the one exception is the Pushgateway, a narrow accommodation for short-lived batch jobs that would otherwise finish and vanish before ever being scraped
- C. Push and pull are simply two names for the same mechanism in Prometheus
- D. Prometheus can only ever scrape exactly one target in its entire configuration
Check the answer
B. Prometheus's core model is pull: the server decides when to fetch data. The Pushgateway is a deliberate, narrow exception for jobs that complete and exit before Prometheus's next scheduled scrape would reach them — not a general-purpose push endpoint for long-running services.
Q19 (Alerting & Dashboarding). A platform team owns forty services and doesn't want to hand-build forty near-identical dashboards. What Grafana feature solves this directly?
- A. Recording rules
- B. Template variables — a dropdown (e.g.
$service) that substitutes into every panel's query, letting one dashboard definition serve every service - C. The Pushgateway
- D. Alertmanager routing trees
Check the answer
B. Template variables parameterize a dashboard: define a variable like $service, reference it inside each panel's PromQL query, and the same dashboard definition serves whichever service is picked from the dropdown, rather than needing one hand-copied dashboard per service.
Q20 (Instrumentation and Exporters). In a Python client library, why does a Counter object only expose an .inc() method and no way to set or decrease its value?
- A. It's an arbitrary API design choice with no relation to the metric type
- B. It enforces the counter's core contract at the code level — counters must only ever increase, aside from an implicit reset to zero on process restart — because
rate()andincrease()depend on that guarantee to correctly detect resets - C. Counters are actually just gauges with a different display name in Grafana
- D.
.inc()is deprecated in favor of.set()in current client libraries
Check the answer
B. The monotonic-increase guarantee isn't just convention — it's the exact assumption rate() and increase() rely on to distinguish a genuine reset from ordinary noise. A client library that let you decrement a Counter would make that detection unreliable, which is why the API deliberately doesn't expose a way to do it.
Q21 (PromQL). A target is scraped every 30 seconds. An engineer writes rate(http_requests_total[20s]) hoping for a fast-reacting rate. What actually happens?
- A. It works fine —
rate()re-samples internally to fill any gap - B. The range is shorter than a single scrape interval, so the query typically has too few samples in the window to compute a meaningful rate, and usually returns no data or an unstable result
- C. Prometheus automatically widens the range to match the scrape interval
- D. It returns the exact same result as
rate(http_requests_total[5m])
Check the answer
B. rate() needs at least two samples inside its window, so the range should comfortably span several scrape intervals — a common rule of thumb is at least four times the scrape interval. A 20-second window against a 30-second scrape interval routinely contains fewer samples than rate() needs.
Q22 (Prometheus Fundamentals). A specific metric turns out to have unexpectedly high cardinality in production, and the team needs an emergency brake without touching the client's code. Which mechanism is built for exactly this?
- A.
relabel_configs, since it always runs after the scrape - B.
metric_relabel_configs, which runs on the samples returned by a scrape (after the fact), and can drop a whole metric or specific label values before they're ever written to the TSDB - C.
evaluation_interval, by simply lengthening it - D. There is no way to do this without redeploying the instrumented service
Check the answer
B. metric_relabel_configs operates on samples a scrape already returned — the deliberate opposite ordering to relabel_configs, which decides what gets scraped in the first place. It's the standard emergency brake for a cardinality problem, with no client-side redeploy required.
Q23 (Observability Concepts). Why is service discovery specifically important in a Kubernetes environment, more so than in a small, static, hand-configured environment?
- A. It isn't important in Kubernetes; static configuration is always preferred there
- B. Pods are ephemeral and don't have stable IPs, so Prometheus needs to continuously ask an authoritative source (the Kubernetes API) what targets currently exist, rather than being told by hand every time something changes
- C. Service discovery only matters for exporters, never for application pods
- D. Kubernetes forbids static scrape configs entirely
Check the answer
B. Pods are created, rescheduled and destroyed constantly, and their IPs change every time. kubernetes_sd_configs continuously re-derives the current target list by querying the API server directly — the mechanism that makes the pull model scale in a dynamic environment at all.
Q24 (Alerting & Dashboarding). A dashboard needs to display an expensive, multi-line PromQL aggregation on every page load, for many viewers, many times a minute. What is the standard fix?
- A. Simplify the dashboard by removing the panel entirely
- B. A recording rule that precomputes the expensive expression on a schedule and stores the result under a new metric name, so every dashboard load queries the cheap, precomputed series instead
- C. Increase
scrape_intervaluntil the query becomes cheap - D. Move the query into an alerting rule instead, since only alerting rules can be precomputed
Check the answer
B. A recording rule runs the expensive expression once, on its own schedule, and saves the result as a new, ordinary series — conventionally named level:metric:operation. Every dashboard panel can then read that cheap precomputed series instead of re-evaluating the full aggregation on every page load.
Q25 (Instrumentation and Exporters). Why does the curriculum treat choosing histogram bucket boundaries as something to do deliberately, rather than accepting a library's default buckets unexamined?
- A. Bucket boundaries have no effect on query accuracy, only on storage size
- B. If real latencies cluster below the smallest bucket boundary or above the largest,
histogram_quantile()loses the resolution to distinguish values within that range — buckets should be chosen to bracket the latencies the service actually produces - C. Buckets must always be evenly spaced linear intervals
- D. Only one bucket boundary is ever needed per histogram
Check the answer
B. histogram_quantile() interpolates within whichever bucket a percentile falls into, so if every real observation lands inside one bucket, the interpolation has almost no resolution to work with. Buckets should be chosen around the actual latency profile of the service, not left at a generic library default.
Q26 (PromQL). sum by (job) (rate(http_requests_total[5m])) and sum without (instance) (rate(http_requests_total[5m])) can produce the same result under one specific condition. What is it?
- A. They can never produce the same result under any condition
- B. Only when
jobandinstanceare the only two labels remaining after everything else has already been removed, so droppinginstanceleaves exactlyjobstanding - C. Always —
byandwithoutare simply two names for the identical operation - D. Only when there is exactly one target being scraped
Check the answer
B. by (job) keeps only the job label; without (instance) keeps everything except instance. The two expressions land on the same output only if job is the sole label left standing once instance is stripped — in general they answer different questions and shouldn't be treated as interchangeable.
Q27 (Prometheus Fundamentals). A team adds a request_id label — a fresh, effectively unique value on every single request — to an existing counter. What is the most direct consequence?
- A. Nothing changes; Prometheus deduplicates identical metric names automatically
- B. Every unique combination of label values is a separate time series, so a near-unique label multiplies the series count by roughly the number of requests — a cardinality explosion that can exhaust memory and slow or crash the server
- C. The metric silently becomes a gauge instead of a counter
- D. Prometheus rejects the scrape outright and logs a fatal configuration error
Check the answer
B. A metric name plus its full label set defines one time series, and every distinct combination is tracked separately. A label that's effectively unique per request turns one bounded metric into an unbounded, ever-growing set of series — the textbook cardinality explosion this curriculum names by name.
Q28 (Observability Concepts). A team internally targets 99.9% availability for checkout, and separately signs a customer contract promising 99.5% with service credits for any shortfall. Which term describes the 99.5% figure?
- A. SLI
- B. SLO
- C. SLA
- D. Error budget
Check the answer
C. The externally promised, contractual figure — with consequences attached, here service credits — is the SLA. The internal 99.9% target is the SLO, deliberately set tighter than the SLA to leave headroom; the SLI would be the actual measurement mechanism, which this scenario doesn't state.
Q29 (Alerting & Dashboarding, Select TWO). Which TWO of the following are genuine Alertmanager responsibilities, distinct from what a bare alerting rule defined inside Prometheus itself does on its own?
- A. Deciding whether an expression is currently true (evaluating
expr) - B. Silencing — temporarily muting notifications for alerts matching a label set, for known, expected work
- C. Inhibition — suppressing a downstream alert once a related parent alert is already firing, so one root cause doesn't generate a pile of redundant pages
- D. Applying the
for:duration before an alert is allowed to fire - E. Scraping targets on an interval
Check the answer
B and C. Silencing and inhibition are specifically Alertmanager's job, applied after Prometheus has already decided an alert is firing. Evaluating expr and applying for: (A and D) happen inside the Prometheus server's own rule engine, before an alert is ever handed to Alertmanager; scraping (E) is an unrelated, earlier stage of the pipeline entirely.
Q30 (Instrumentation and Exporters). A team wants to know within seconds if their public-facing checkout endpoint stops responding — including failures caused by DNS, an expired TLS certificate, or the endpoint being entirely unreachable, none of which the application's own internal metrics would ever see. What's the right tool?
- A.
node_exporter - B.
blackbox_exporter, which probes an endpoint from outside — over HTTP, TCP, ICMP or DNS — with no awareness of the application's internals, catching exactly the class of failure internal instrumentation structurally cannot - C. A client-library Counter added to the checkout handler
- D. A recording rule
Check the answer
B. blackbox_exporter tests a target the way an external user actually experiences it, with no visibility into the application's internals — precisely what lets it catch infrastructure-layer failures like DNS, TLS expiry, or a load balancer being down, because the request never even reaches the application.
Block 3 — Q31–45
Q31 (PromQL). Which statement about increase() versus rate(), both applied to the same counter and the same [5m] range, is correct?
- A. They are unrelated functions that measure different metric types
- B.
increase()is defined asrate()multiplied by the number of seconds in the range — both extrapolate to cover the full window and both require a counter - C.
increase()returns the literal difference between the first and last raw sample only, with no extrapolation - D.
rate()can be used on gauges butincrease()cannot
Check the answer
B. increase(v[t]) is calculated as rate(v[t]) × the number of seconds in [t]. Both functions handle counter resets, and both extrapolate slightly to cover the edges of the range rather than reading only the two boundary samples verbatim — why increase() over a partial scrape interval can return a non-whole number.
Q32 (Prometheus Fundamentals). Which is a correct statement about what Prometheus is deliberately NOT designed to be?
- A. A general-purpose, per-request event log or a source of billing-grade exact counts — it samples on an interval rather than recording every individual event
- B. A time-series database at all
- C. A system that can alert based on query results
- D. Compatible with any client library other than Go
Check the answer
A. Prometheus samples on an interval rather than recording every discrete event, which is exactly why it's unsuitable as a per-request audit log or a source of exact, billing-grade counts — a request that starts and finishes entirely between two scrapes leaves no direct trace. Purpose-built logging and tracing systems fill that gap.
Q33 (Observability Concepts). A service has a 99.9% SLO. What does its "error budget" represent?
- A. The dollar amount allocated to fixing bugs each quarter
- B. The allowed amount of unreliability — here, 0.1% — that the SLO explicitly permits before the SLO itself is breached
- C. A synonym for the SLA
- D. The number of alerting rules configured for that service
Check the answer
B. The error budget is "100% minus the SLO," expressed as the allowance for failure a team is explicitly permitted to spend — on genuine incidents, planned risk like a rollout, or anything else. It's the number an error-budget policy is triggered against once it runs out.
Q34 (Alerting & Dashboarding). A team pages on-call the instant any node's CPU crosses 80%. What's the core problem with this alert, per the "when, what and why" competency?
- A. 80% is numerically too low a threshold and should simply be raised
- B. It alerts on a cause/resource-saturation signal rather than a user-felt symptom — CPU at 80% may be entirely fine and self-correcting, and paging on it risks becoming noise nobody trusts
- C. CPU should never be measured by Prometheus at all
- D. The alert should use a recording rule instead of an alerting rule
Check the answer
B. The exam's alerting philosophy is explicit: alert on symptoms users actually feel — elevated error rate, real latency, genuine saturation impact — not on a resource number in isolation that may be perfectly healthy. An alert that fires on noise erodes trust in the whole on-call rotation, and eventually gets ignored even when it's right.
Q35 (Instrumentation and Exporters). Which metric name best follows Prometheus naming conventions?
- A.
httpRequestsTotal - B.
http_requests_total - C.
http-requests - D.
HTTPRequests_Total_Count_Metric
Check the answer
B. Convention is snake_case, a base unit where relevant (seconds, bytes — not milliseconds or kilobytes), and a _total suffix specifically for counters. http_requests_total follows all three: lowercase with underscores, no embedded unit needed for a plain count, and a _total suffix correctly signalling "this is a counter."
Q36 (PromQL). A dashboard needs a very spiky, second-by-second reacting rate for an ad-hoc debugging graph, and the engineer reaches for irate() instead of rate(). What's the trade-off?
- A. There is no trade-off;
irate()is strictly better in every situation - B.
irate()calculates the rate using only the last two samples in the range, giving fast reaction to spikes but a noisy, jittery graph — it should not be used for alerting rules or slow-moving trend graphs - C.
irate()cannot be used on counters at all - D.
irate()ignores counter resets entirely, unlikerate()
Check the answer
B. irate() (instant rate) uses just the two most recent samples, reacting instantly to a spike but making it useless for smoothed dashboards or alert thresholds, where the noise would trigger false positives. rate() averages across the whole window, trading reaction speed for stability — the right default for alerting rules.
Q37 (Prometheus Fundamentals). Internally, how does Prometheus actually represent a metric's name inside its own label model?
- A. The metric name is stored completely separately from labels, in its own dedicated field with no label representation
- B. The metric name is itself stored as the reserved
__name__label, so a time series really is just "a set of labels," with the name being one of them - C. Metric names are not stored at all; only label hashes are kept
- D. The metric name is derived at query time from the file path it was scraped from
Check the answer
B. Every metric name is, under the hood, the value of a reserved label called __name__ — which is why a selector like http_requests_total{job="x"} is really just label-matching on __name__="http_requests_total" combined with job="x". A time series is uniformly a set of label-value pairs.
Q38 (Observability Concepts). A team migrating from a StatsD-based system to Prometheus is confused because their application used to push every metric update over UDP, and now nothing appears until Prometheus scrapes it. What's the correct explanation?
- A. Their instrumentation code is broken and must be rewritten from scratch
- B. This is expected: Prometheus's model inverts the direction of control — the target exposes current values on an HTTP endpoint, and the server decides when to pull them, rather than the application pushing on its own schedule
- C. Prometheus secretly still uses UDP under the hood
- D. Push-based and pull-based systems are functionally identical and this should never happen
Check the answer
B. This is the biggest mental-model shift moving onto Prometheus from a push-based system like StatsD: instrumented code doesn't send anything anywhere on its own; it exposes current values at /metrics, and it's entirely up to the Prometheus server's scrape schedule when — or whether — those values get read.
Q39 (Alerting & Dashboarding). What does it mean for a page to be "actionable," in the sense the exam tests?
- A. It must include a graph attached to the notification
- B. There is something the on-call engineer can actually do in response — ideally documented in a linked runbook — and if there's genuinely nothing to do, it shouldn't be a page at all, but a ticket or a dashboard instead
- C. It must be sent by SMS rather than by any other channel
- D. It must include the exact PromQL expression that triggered it
Check the answer
B. An actionable page gives the person being woken up a real, documented next step — exactly why a runbook_url annotation matters. If a firing condition genuinely has no useful human response, the correct treatment is a ticket or a dashboard, not a 3am page.
Q40 (PromQL). Which expression correctly returns the five pods with the highest CPU usage, aggregated by pod, over the last five minutes?
- A.
topk(5, container_cpu_usage_seconds_total) - B.
topk(5, sum by (pod) (rate(container_cpu_usage_seconds_total[5m]))) - C.
sum by (pod) (topk(5, rate(container_cpu_usage_seconds_total[5m]))) - D.
max_over_time(container_cpu_usage_seconds_total[5m])
Check the answer
B. Rate the raw counter first, aggregate it down to one value per pod with sum by (pod), and only then rank with topk(5, ...). Option A ranks a raw, unrated counter with no per-pod aggregation; option C reverses the order, ranking before aggregating, which produces a different and generally meaningless answer.
Q41 (Prometheus Fundamentals). In the plain-text exposition format below, what do the # HELP and # TYPE comment lines specifically provide?# HELP http_requests_total Total HTTP requests served.# TYPE http_requests_total counter
- A. They are purely cosmetic and are stripped before Prometheus stores anything
- B.
# HELPsupplies a human-readable description and# TYPEdeclares the metric type — counter, gauge, histogram, summary or untyped — both metadata that tooling and PromQL functions can rely on - C.
# TYPEsets the scrape interval for that specific metric - D.
# HELPis mandatory;# TYPEis deprecated and ignored by modern Prometheus
Check the answer
B. These comment lines are part of the exposition format's actual contract: # HELP gives a human-readable description, and # TYPE declares which metric type this series is — information Prometheus and downstream tooling both use.
Q42 (PromQL, Select TWO). An error-ratio query built as sum(rate(http_requests_total{code=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) returns an empty result, even though both halves individually return data. Which TWO of the following are plausible, structurally correct explanations?
- A. Binary arithmetic operators match series on identical label sets by default, and after
sum()has stripped labels down to nothing on each side, an empty-versus-nonempty mismatch leaves nothing to divide - B. PromQL forbids division between two aggregated vectors under any circumstances
- C. One side may have literally zero series at this moment — no requests currently match
code=~"5.."— and dividing "no data" by a number returns no data, not zero - D. Division always requires an
on()clause or it is a guaranteed syntax error - E.
sum()can never be divided by anothersum()of the same metric
Check the answer
A and C. Both are real, common causes of an "empty division" surprise: label-set mismatches after aggregation, and one side simply having no matching series at that moment — an absent series is not the same as a zero value. B, D and E are all false as blanket statements; division between aggregated vectors is legal PromQL and doesn't require on() unless the label sets genuinely differ.
Q43 (PromQL). sum(rate(http_request_duration_seconds_bucket[5m])) is fed straight into histogram_quantile(0.99, ...) and the result is wrong. What was dropped that shouldn't have been?
- A. The
joblabel - B. The
lelabel —histogram_quantileneeds it preserved to know which cumulative bucket boundary each summed row belongs to - C. The
__name__label - D. Nothing was dropped;
histogram_quantile()doesn't use labels at all
Check the answer
B. sum(rate(...)) with no by (le) clause collapses every bucket boundary into one indistinguishable blob, and histogram_quantile() has no way to tell which row was which boundary. The fix is sum by (le) (rate(..._bucket[5m])) so every cumulative boundary survives the aggregation.
Q44 (PromQL). A histogram's _bucket series use the le (less-than-or-equal) label. What does the bucket labelled le="0.5" actually count?
- A. Exactly the requests whose duration was between 0.1 and 0.5 seconds, and no others
- B. The count of observations less than or equal to 0.5 seconds — cumulative from zero, so it also includes everything already counted in
le="0.1",le="0.25", and every smaller boundary - C. The average duration of all requests, capped at 0.5 seconds
- D. The number of requests that took longer than 0.5 seconds
Check the answer
B. Prometheus histogram buckets are cumulative by design — each le bucket counts every observation at or below that boundary, including everything already counted by smaller buckets. That's exactly why summing across the le label, rather than treating buckets as independent ranges, is what makes them aggregatable in the first place.
Q45 (PromQL). A batch job exposes platform_backup_last_success_timestamp_seconds, a Unix timestamp gauge updated only when a backup succeeds. Which expression correctly answers "how many hours since the last successful backup?"
- A.
rate(platform_backup_last_success_timestamp_seconds[1h]) - B.
(time() - platform_backup_last_success_timestamp_seconds) / 3600 - C.
platform_backup_last_success_timestamp_seconds / 3600 - D.
increase(platform_backup_last_success_timestamp_seconds[1h])
Check the answer
B. time() returns the current Unix timestamp as an instant vector; subtracting the metric's own last-success timestamp gives elapsed seconds since that success, and dividing by 3600 converts it to hours. This time()-minus-a-timestamp shape is the whole "Timestamp Metrics" competency, and it underpins virtually every freshness alert.
Score yourself
☺ Like you're 10: Count your correct answers out of forty-five, turn it into a percentage against the real 75% pass mark, then look at which domain cost you the most points — that second part is the part that actually helps.
The Linux Foundation's Multiple Choice Exam FAQ states that a score of 75% or above is required to pass any LF multiple-choice exam, and the PCA is one. Treat 75% here as a target to clear comfortably, not a calibrated prediction of the real sitting — this paper's wording is ours, not the CNCF's, and it isn't tuned to match the real exam's difficulty.
| Domain | Questions in this paper | Your score | If you're under two-thirds, go here |
|---|---|---|---|
| 🐘 PromQL | Q1, 6, 11, 16, 21, 26, 31, 36, 40, 42, 43, 44, 45 | /13 | PCA — the exam |
| 🦉 Prometheus Fundamentals | Q2, 7, 12, 17, 22, 27, 32, 37, 41 | /9 | Prometheus |
| 🐿️ Observability Concepts | Q3, 8, 13, 18, 23, 28, 33, 38 | /8 | The OpenTelemetry data model |
| 🐢 Alerting & Dashboarding | Q4, 9, 14, 19, 24, 29, 34, 39 | /8 | Grafana |
| 🦫 Instrumentation and Exporters | Q5, 10, 15, 20, 25, 30, 35 | /7 | OpenTelemetry Collector |
| Total | 45 questions | /45 | 75% (34/45) to clear comfortably |
Whatever you scored, sort your misses into two piles before you move on, because on a paper like this one they mean different things. A question you got wrong because you genuinely didn't know the function or the definition is a real content gap — reread the linked page and redo that exact question cold in a couple of days. A question you got wrong despite roughly knowing the material — you second-guessed yourself, or mixed up two similar-looking options under time pressure — is a confidence problem, not a knowledge gap, and the fix is more timed reps, not rereading content you already have. Either way, don't retake this exact paper minutes later; go read first, then come back.
Where each domain is taught
☺ Like you're 10: Every question above traces back to one of a handful of pages. Go back to the page, not to the wider internet.
Nothing in this paper examines anything that isn't covered somewhere on this course. PromQL, the data model, and the alerting-and-instrumentation examples all live in the PCA blueprint itself; the broader observability vocabulary — logs, events, traces and spans — sits one layer up in the deep-dive material, since it deliberately reaches beyond Prometheus alone.
PromQL
Instant vs. range vectors, rate/sum ordering, aggregating over time and dimensions, binary operators, histogram_quantile with le preserved, and the timestamp-metrics pattern.
🦉 · 20%Prometheus Fundamentals
The pull architecture, scrape and evaluation intervals, relabel_configs vs metric_relabel_configs, the data model, cardinality, and the exposition format.
🐿️ · 18%Observability Concepts
Metrics vs. logs vs. events vs. traces, push vs. pull, service discovery, and the SLI/SLO/SLA/error-budget vocabulary.
🐢 · 18%Alerting & Dashboarding
Panels and template variables, recording rules, the for: field, Alertmanager grouping/inhibition/silencing, and alerting on symptoms rather than causes.
🦫 · 16%Instrumentation and Exporters
Choosing a client-library metric type, avoiding cardinality mistakes in your own code, node_exporter and blackbox_exporter, and metric naming conventions.
Beyond the domain pages, the wider revision kit still applies: flashcards for the vocabulary, the self-check quiz for mixed recall, the glossary for anything a question assumed you already knew, and the PCA study plan for how to sequence all of this against your remaining prep time. For deeper, module-specific reps beyond a full sitting, the PCA practice bank splits the same ground into shorter, focused drills, and Set 2 is the scenario-heavy paper that assumes this baseline is already solid.
Remy: Thirty-nine out of forty-five! PromQL, Fundamentals, done, done, next paper!
Ellie: Which domain hid the other six, Remy? Thirty-nine sounds excellent until one domain quietly ate five of them.
Remy: ...Alerting & Dashboarding, mostly. I kept marking every true expression as an instant page, no matter what for: said.
Foxy: Wait, so a true expression doesn't just page someone the second it's true?
Timmy: Not if for: is set. Pending, then firing — only once it's held for the whole duration. That's the whole point: it survives a blip.
Gizmo: Easier fix — set for: 0s everywhere and page on absolutely everything. Maximum awareness! 🔔
Ellie: That's not awareness, Gizmo, that's the fastest way to get your whole team to mute you. Twenty-eight percent of this exam is PromQL — most of the other seventy-two is about not doing exactly that.
1. Name the five PCA domains and their weights, in weight order. 2. Why is sum(rate(x[5m])) correct while rate(sum(x)[5m]) is wrong? 3. What does histogram_quantile() need preserved in its input to work correctly, and what happens if it's dropped? 4. What is Pushgateway actually for, and what is it not for? 5. What's the difference between relabel_configs and metric_relabel_configs, in terms of when each runs? 6. Name one exam detail this page states with confidence and one it deliberately leaves blank — and where would you confirm either before booking?
Check your answers
- PromQL 28%; Prometheus Fundamentals 20%; Observability Concepts 18%; Alerting & Dashboarding 18%; Instrumentation and Exporters 16%.
rate()has to run on a counter range vector so it can handle each series' own resets correctly; summing first destroys the individual series, and their resets along with it. Rate first, then aggregate.- The
lelabel. Without it kept (typically viasum by (le)), every cumulative bucket boundary collapses into one indistinguishable row, andhistogram_quantile()has no way to interpolate a percentile correctly. - Short-lived batch jobs that finish and disappear before Prometheus can scrape them. It is not a general push endpoint — Prometheus itself is a pull system, and Pushgateway is a narrow, deliberate exception.
relabel_configsruns before the scrape and decides what gets scraped at all (viakeep/drop);metric_relabel_configsruns after the scrape, on samples already returned, and is the emergency brake on a metric that turns out to be high-cardinality.- Stated with confidence: the 90-minute duration and the 75% pass mark (from the Linux Foundation's Multiple Choice Exam FAQ). Deliberately left blank: the real question count, which neither official page publishes. Confirm both, and everything else, on the official Linux Foundation PCA page and the CNCF certification page before you register.
That's the full sitting. Reread whichever domain cost you the most, give it a day to settle, then move on to Set 2 — the scenario-heavy paper that assumes this baseline is already solid.