TL;DR: Histogram, because summaries compute quantiles per instance and quantiles cannot be averaged. A histogram ships bucket counts, which are additive, so you can compute a p99 across a whole fleet at query time. A summary provides an approximate per-instance quantile; it remains useful for that instance but cannot produce a fleet quantile by averaging.
How to approach it
Answer the question directly, then explain the aggregation property, because that is the whole reason and it is what interviewers are checking for.
A strong answer
The four types:
Counter only increases, or resets to zero on restart. Request totals, errors, bytes processed. You almost never graph the raw value; you graph rate() over it, and the function is reset-aware so a process restart does not produce a negative spike.
Gauge goes up and down. Queue depth, memory in use, active connections, temperature. rate() is meaningless on a gauge; you use the value itself, or delta().
Histogram counts observations into cumulative buckets, and ships the bucket counts plus a sum and a total count. Latency, response sizes.
Summary calculates quantiles inside the client and ships the computed values.
Now the distinction that matters. A summary’s p99 is an estimate with the client’s configured quantile error, and there is no mathematically valid way to combine the p99 of ten instances into a fleet p99. Averaging them is wrong, and the error is not small: if one instance is degraded, its p99 is diluted by nine healthy ones and disappears. Since almost every service runs more than one replica, and fleet p99 and per-instance p99 answer different questions, summaries are the wrong tool for anything you will aggregate.
A histogram ships counts per bucket, and counts add. Sum the buckets across every instance and compute the quantile at query time with histogram_quantile(), and the result is a genuine fleet-wide figure. The cost is that the answer is approximate, bounded by bucket width, and that you must choose the buckets in advance. Choose them around your SLO: if the target is 300ms, you want boundaries clustered there rather than the defaults, because a quantile falling in a wide bucket is interpolated and the error is the bucket's width.
Cardinality is the other reason to be careful. A histogram creates one series per bucket per label combination, so ten finite bucket boundaries produce eleven bucket series including +Inf, plus _sum and _count: thirteen series per labelset (optional extra exported series excluded). Native histograms, which store a sparse exponential representation instead of fixed buckets, reduce per-bucket series overhead, but resolution, bucket limits and interoperability still need configuration, and they are the direction the ecosystem is moving.
The rule I would state: counter for things that happen, gauge for things that are, histogram for things that take time or have size, and summary when a per-instance estimate is useful and you do not need to merge those quantiles.
What interviewers probe next
"Why not just average the latency?" An average hides the tail, which is the part users experience. It also cannot distinguish a uniformly mediocre service from a fast one with a slow slice.
"What does rate() do over a 5-minute window?" Per-second average increase over that window, extrapolated to the window edges. At least two samples are required; a window of roughly four scrape intervals is a practical default that tolerates scrape alignment and a missed scrape.
"How would you alert on latency from a histogram?" On the ratio of requests inside the good bucket to total, which is an SLI, rather than on the quantile itself. It is cheaper and it is what an error budget consumes.
Common mistakes
Using a summary and then averaging quantiles across instances, which is silently wrong rather than visibly wrong.
Leaving default histogram buckets, so no boundary sits near your actual SLO and every quantile is a wide interpolation.
Putting rate() on a gauge, which produces a number that looks plausible and means nothing.
References