InfluxDB Interview Questions and Answers
Last updated:
Check out 40 of the most common InfluxDB interview questions, then take an AI-powered practice interview
Q1What is InfluxDB and what problem does it solve?
BasicFundamentals
Answer
InfluxDB is an open-source time-series database built by InfluxData, designed specifically for storing and querying timestamped data, sensor readings, application metrics, server telemetry, financial ticks, and IoT signals. It solves problems that general-purpose databases (PostgreSQL, MongoDB) handle poorly at scale: writing millions of points per second, efficient compression of timestamp-ordered data, downsampling old data automatically, and querying by time ranges (`WHERE time > now() - 1h`) cheaply. Traditional B-tree indexes degrade when every write is at the latest timestamp; InfluxDB's storage engines (TSM in 1.x/2.x, Parquet in 3.x) are designed around append-only, time-ordered writes and use specialised encodings, delta-of-delta for timestamps, Gorilla/XOR for floats, run-length for integers, that achieve 10-90× compression on typical telemetry.
The trade-off: InfluxDB is not a general-purpose database, UPDATEs and DELETEs are expensive or impossible, joins are limited, and the data model is purpose-built for measurements over time. In India, InfluxDB is the default time-series engine inside Telegraf/Grafana stacks at telcos, EV networks, smart-meter rollouts, and observability teams that need long retention without the cost of pushing every metric into a data warehouse. A senior interviewer usually follows up by probing the boundary: what breaks if you make InfluxDB your primary store?
Anything needing transactions, foreign keys, or mutable rows. There is no `UPDATE` statement at all, a correction is simply a fresh write to the same measurement, tag set and timestamp, and deletes in the TSM engine are logical tombstones that only reclaim disk at the next compaction, so `df` will not move immediately after a delete. The scaling limit in 1.x and 2.x is series cardinality, not row count, which is why the schema decision that actually matters is which dimensions become tags rather than how many points per second you expect.
Key Points
- Purpose-built for timestamped data (metrics, IoT, telemetry)
- Handles millions of writes/sec via append-only storage
- Built-in retention policies, downsampling, time-range queries
- Not a general-purpose DB, UPDATE/DELETE/joins are limited
Q2Explain the InfluxDB data model: measurement, tags, fields, and timestamp.
BasicData Model
Answer
Every point in InfluxDB has four parts: (1) **Measurement**, like a table name, e.g. `cpu_usage` or `temperature`. (2) **Tags**, indexed key-value pairs used for filtering and grouping, e.g. `host=server01,region=mumbai`. Tags are always strings. (3) **Fields**, the actual values, e.g. `value=42.5,load=0.7`. Fields can be float, int, string, or bool, and are NOT indexed. (4) **Timestamp**, nanosecond precision by default, UTC.
The combination of measurement + tag set uniquely identifies a 'series'. Choosing tags vs fields is the single most consequential decision in InfluxDB schema design: tag values create new series (high-cardinality tags blow up storage), while field values are cheap but cannot be efficiently filtered. Rule of thumb: tag what you `GROUP BY` and filter on; field what you `SELECT` and aggregate.
Two behaviours regularly catch candidates out. First, field types are pinned per field per shard: write `value=1i` and then `value=1.5` into the same measurement inside the same shard and the second write is rejected with `field type conflict: input field "value" on measurement "cpu_usage" is type float, already exists as type integer`. The only clean fixes are renaming the field or letting the next shard start with the new type, which is why type discipline belongs in the producer, not in a cleanup job.
Second, an empty tag value is not stored as an empty string, InfluxDB drops the tag entirely, so `host=` and a missing `host` collapse into the same series while `host=server01` is a different one. In InfluxDB 3.x the same model is surfaced as SQL tables: tags become dictionary-encoded string columns, fields become regular typed columns, and `time` is the partition key, so `SELECT * FROM cpu_usage` shows tags, fields and timestamp side by side with no special syntax.
# Line Protocol
# <measurement>,<tag_key>=<tag_value> <field_key>=<field_value> <timestamp_ns>
cpu_usage,host=server01,region=mumbai value=42.5,load=0.7 1715500800000000000
temperature,sensor=tank-A,plant=pune value=78.3 1715500800000000000
# host, region, sensor, plant are TAGS (indexed)
# value, load are FIELDS (not indexed, cheap)
Q3What is the Line Protocol in InfluxDB?
BasicWrite API
Answer
Line Protocol is InfluxDB's plain-text wire format for writing data. Each line represents one point and follows the syntax `measurement,tag_set field_set timestamp`. It's compact, easy to generate from any language, and accepted by both the HTTP API and the Telegraf agent.
Multiple points are sent as multiple lines in a POST body to `/write` (1.x) or `/api/v2/write` (2.x/3.x). Common gotchas: tags and fields are comma-separated but the boundary between the tag set and field set is a *single space*; string field values must be wrapped in double quotes; integer fields require an `i` suffix (`count=1042i`); booleans accept `t`/`T`/`true`/`True` or `f`/`F`/`false`/`False`; and the timestamp is in nanoseconds by default (precision can be overridden via the `precision` query parameter, `s`, `ms`, `us`, `ns`). Special characters in tag/field keys or string values must be escaped with backslashes, most client libraries handle this for you, but if you generate Line Protocol with string concatenation you will eventually hit it.
Telegraf's `outputs.influxdb_v2` and the official Python/Go/Java SDKs all emit valid Line Protocol; rolling your own is rarely worth the trouble. Two failure modes are worth naming in an interview. An unescaped comma or space inside a tag value produces `unable to parse` and, on the v2 endpoint, rejects the whole batch with a 400, which is why a single malformed sensor label can silently stop an entire edge site from reporting.
On the InfluxDB 3 endpoint `/api/v3/write_lp` you can pass `accept_partial=true` so valid lines land and only the bad ones are reported back. A duplicated tag key on the same line is rejected outright. Finally, sort tag keys lexicographically before serialising: the server sorts them anyway to compute the series key, and pre-sorted input reduces parse cost on large batches, which is the kind of detail that separates someone who has run an ingest pipeline from someone who has only read the docs.
# POST /api/v2/write?org=goodspace&bucket=metrics&precision=ns
# Authorization: Token <api-token>
cpu_usage,host=server01,region=mumbai value=42.5 1715500800000000000
cpu_usage,host=server02,region=mumbai value=51.2 1715500800000000000
request_count,service=api,env=prod count=1042i 1715500800000000000
log_message,service=api level="info" msg="login ok" 1715500800000000000
Q4What are buckets and organizations in InfluxDB 2.x/3.x?
BasicArchitecture
Answer
InfluxDB 2.x introduced two new concepts that replaced the 1.x model of databases + retention policies: (1) **Organization (org)**, the top-level tenant boundary. Users, buckets, tokens, dashboards, and tasks all live inside an org. Useful for multi-tenant SaaS or separating teams across business units. (2) **Bucket**, the container for time-series data.
Roughly equivalent to a 1.x `database + retention policy` combo. Each bucket has a retention period (e.g. 30 days, infinite), after which old data is automatically expired by dropping shards. Tokens grant scoped access (read/write per bucket, all-access for admins).
In InfluxDB 3.x, the same org/bucket model is preserved but the underlying storage is Parquet files on object storage (S3, GCS, Azure Blob) instead of TSM files on local disk, which means buckets can grow effectively without bound, billed at object-storage rates. A bucket in InfluxDB Cloud Serverless can also have separate hot and cold storage tiers managed by the platform. Two details interviewers probe.
The bucket is the unit of retention, so you cannot give two measurements inside one bucket different TTLs, you split them into separate buckets and route writes accordingly at the Telegraf output or client layer. And bucket identity is the immutable bucket ID, not the name: `influx bucket update --name` renames it while tokens, dashboards and DBRP mappings keep pointing at the ID, so a rename does not break authorizations, but deleting and recreating a bucket with the same name silently invalidates every scoped token. InfluxQL clients from 1.x reach 2.x buckets only through a DBRP mapping, so if a legacy Grafana panel suddenly returns no rows after a migration, check `influx v1 dbrp list` before blaming the query.
# create an org, a bucket with 30-day retention, and a write-scoped token
influx org create --name goodspace
influx bucket create \
--name metrics_raw \
--org goodspace \
--retention 720h \
--shard-group-duration 1h
influx auth create \
--org goodspace \
--write-bucket 0a1b2c3d4e5f6071 \
--description 'telegraf-edge-writer'
# legacy InfluxQL clients need a database/retention-policy mapping
influx v1 dbrp create \
--db telemetry \
--rp autogen \
--bucket-id 0a1b2c3d4e5f6071 \
--default
Q5What is a retention policy in InfluxDB?
BasicRetention
Answer
A retention policy controls how long data lives before being automatically deleted. In InfluxDB 1.x, you create them explicitly: `CREATE RETENTION POLICY 'one_week' ON 'telemetry' DURATION 7d REPLICATION 1 DEFAULT`. In 2.x and 3.x, retention is set per bucket (`influx bucket update --id <id> --retention 720h`).
The engine drops whole 'shards' (or time-partitioned Parquet files in 3.x) that fall outside the window, it's a cheap O(1) delete, unlike `DELETE FROM`. Common production pattern: a `raw` bucket with 7-day retention for high-resolution data, a `metrics_5m` bucket with 30-day retention, and a `metrics_1h` bucket with 1-year retention for hourly aggregates produced by a continuous query or task. The cost difference is dramatic: keeping a year of 1-second data versus a year of 1-hour aggregates can be a 3600× difference in storage.
The retention setting is also enforced lazily, data may live a little past its TTL until the next shard drop runs, so don't rely on it as a hard privacy delete (use explicit DELETE or, for GDPR-style requests, structural deletion at the bucket level). The natural follow-up is how you delete a subset. In 2.x that is the `/api/v2/delete` endpoint or `influx delete`, which takes a `--start`, a `--stop` and a `--predicate` that can only reference `_measurement` and tag keys, never a field value, so 'delete every reading above 200 degrees' is not expressible and has to be done by rewriting the series. Those deletes write tombstones, disk is reclaimed only at the next compaction, and a wide predicate over months of shards can pin CPU on the node for a long time.
# 1.x: explicit retention policy
CREATE RETENTION POLICY "one_week" ON "telemetry"
DURATION 7d REPLICATION 1 SHARD DURATION 1h DEFAULT
# 2.x/3.x: retention lives on the bucket
influx bucket update --id 0a1b2c3d4e5f6071 --retention 720h
# targeted delete: tag predicate only, never a field predicate
influx delete \
--bucket metrics_raw \
--org goodspace \
--start 2026-01-01T00:00:00Z \
--stop 2026-02-01T00:00:00Z \
--predicate '_measurement="cpu_usage" AND host="server01"'
Q6What is a continuous query in InfluxDB 1.x?
BasicDownsampling
Answer
A continuous query (CQ) is a scheduled InfluxQL query that runs periodically to downsample high-resolution data into lower-resolution aggregates. Classic use case: keep 5-second sensor readings for 7 days, but downsample to 1-minute averages stored for 1 year. CQs are gone in InfluxDB 2.x (replaced by Flux **tasks**) and 3.x (replaced by SQL-based tasks and external schedulers), but you'll still see them in legacy 1.x deployments at companies that haven't migrated yet, and they're a common interview topic for India-based telco/IoT teams running long-lived 1.x clusters.
The mechanics matter in an interview. A CQ fires at the end of each `GROUP BY time()` interval and only covers the interval that just closed, so late-arriving points are silently missed unless you add `RESAMPLE EVERY 5m FOR 1h`, which recomputes the trailing hour on every run. CQs get no retries, run on a single node, and log failures only to `influxd.log`, so a CQ that quietly stopped firing is usually discovered weeks later when someone notices a flat dashboard.
Two more traps: the `INTO` target inherits the destination retention policy rather than the source, and any tag not named in the `GROUP BY` clause is dropped from the output, which is why a downsampled measurement often collapses several hosts into one indistinguishable series. Use `SHOW CONTINUOUS QUERIES` to audit what is actually installed, since CQs are stored in the meta store and are invisible in the data itself.
CREATE CONTINUOUS QUERY "cq_5m_mean" ON "telemetry"
BEGIN
SELECT mean("value") INTO "downsampled"."autogen"."temperature_5m"
FROM "telemetry"."autogen"."temperature"
GROUP BY time(5m), sensor
END
Q7How do you write data into InfluxDB using the HTTP API?
BasicWrite API
Answer
Send Line Protocol via POST to the write endpoint. In 1.x it's `/write?db=<database>&precision=<unit>`; in 2.x/3.x it's `/api/v2/write?org=<org>&bucket=<bucket>&precision=<unit>` with an `Authorization: Token <token>` header. Batch points, never POST one point per request in production.
Recommended batch size: 5,000–10,000 points per request, depending on point size. The server returns 204 on success; on partial failure (some points reject), 2.x returns 400 with a JSON body listing the bad lines so you can quarantine them. Details that separate a working client from a production one: set `Content-Encoding: gzip` and compress the body, which typically cuts Line Protocol volume by 5-10× on the wire and matters a great deal on cellular edge links.
Use `precision=ms` or `precision=s` when your source has no nanosecond resolution, because shorter timestamps mean smaller payloads. Handle status codes distinctly rather than retrying blindly: `204` is success, `400` means malformed Line Protocol or a field type conflict and must never be retried (quarantine the batch and alert), `401` and `403` mean a missing or wrongly scoped token, `413` means the payload exceeded the server limit so you should split the batch, and `429` or `503` mean rate limited or overloaded and must be retried with exponential backoff honouring the `Retry-After` header. Writes are idempotent on measurement plus tag set plus timestamp, so a retry after a network timeout cannot duplicate points, which is exactly the property that lets you build an at-least-once ingest pipeline safely. In InfluxDB 3 the endpoint is `/api/v3/write_lp?db=<db>&precision=<unit>`.
curl -i -X POST \
'http://localhost:8086/api/v2/write?org=goodspace&bucket=metrics&precision=ns' \
-H 'Authorization: Token YOUR_TOKEN' \
-H 'Content-Type: text/plain; charset=utf-8' \
--data-binary 'cpu_usage,host=server01 value=42.5 1715500800000000000
cpu_usage,host=server02 value=51.2 1715500800000000000'
Q8What is Telegraf and how does it integrate with InfluxDB?
BasicTelegraf
Answer
Telegraf is InfluxData's open-source metrics collection agent, written in Go. It has 300+ input plugins (system metrics, MQTT, MySQL, Kafka, SNMP, Modbus, OPC UA for industrial IoT, Prometheus scrape, AWS CloudWatch, GCP Stackdriver, NGINX, HAProxy) and just as many output plugins (InfluxDB v1/v2/v3, Kafka, Elasticsearch, Datadog, Wavefront, plain files for testing). The most common pipeline: Telegraf scrapes/receives metrics, batches them in memory, optionally transforms them with processor plugins (regex, rename, math), and writes Line Protocol to InfluxDB.
It's the standard ingest agent for InfluxDB workloads in 2026, at telcos like Jio and Airtel, thousands of Telegraf agents run on edge nodes feeding into central InfluxDB clusters. Telegraf is configured via a single TOML file declaring inputs, processors (filtering, tagging), aggregators (basic statistics windows), and outputs. Run it as a systemd service on Linux hosts or as a sidecar/DaemonSet on Kubernetes.
Production behaviour worth knowing: Telegraf buffers in memory, sized by `metric_buffer_limit` (default 10000), and flushes every `flush_interval` (default 10s) or when `metric_batch_size` (default 1000) fills. If the output stays down longer than the buffer holds, you get `Metric buffer overflow; N metrics have been dropped` in the log and that data is gone, because Telegraf does not spill to disk. Any pipeline that genuinely must not lose points needs Kafka or a persistent MQTT broker in front rather than a larger buffer. Other essentials: `interval` sets collection frequency, `collection_jitter` spreads load so a fleet of thousands does not fire on the same second, `[global_tags]` stamps `site` or `region` onto every point without touching each input, and `telegraf --test --config telegraf.conf` prints the exact Line Protocol an input would emit, which is the fastest way to catch a bad tag before it reaches the database and pollutes cardinality.
# /etc/telegraf/telegraf.conf
[[inputs.cpu]]
percpu = true
totalcpu = true
[[inputs.mem]]
[[inputs.mqtt_consumer]]
servers = ["tcp://mqtt.broker.local:1883"]
topics = ["sensors/+/temperature"]
data_format = "json"
[[outputs.influxdb_v2]]
urls = ["http://influxdb:8086"]
token = "$INFLUX_TOKEN"
organization = "goodspace"
bucket = "metrics"
Q9What is Grafana and why is it commonly used with InfluxDB?
BasicVisualization
Answer
Grafana is an open-source dashboarding tool that natively supports InfluxDB as a data source (InfluxQL, Flux, and SQL via FlightSQL for 3.x). The pairing is so common, Telegraf + InfluxDB + Grafana, sometimes called the 'TIG stack', that interviewers expect you to know it. Grafana provides time-series visualisations, gauges, heatmaps, world maps, table panels, alerting with multi-channel routing, templating (`$variable` for sensor/host/region/plant), and dashboard provisioning as code via JSON or the Grafana operator on Kubernetes.
Production setups typically run Grafana behind nginx with OAuth (Google/Keycloak/Okta), and InfluxDB tokens with read-only scope per dashboard team to enforce isolation. Grafana 10+ supports the InfluxDB 3.0 SQL data source natively. For Indian observability teams, Grafana plus InfluxDB is the de facto pairing for any visualisation work that isn't already in Datadog or New Relic.
Two practical points come up in interviews. The data source configuration decides the query editor: Grafana's InfluxDB data source has separate InfluxQL, Flux and SQL modes, and switching an existing dashboard between them rewrites nothing, every panel query has to be ported by hand, which is the real cost of an InfluxDB 2.x to 3.x migration. Second, the time macros matter.
A panel that hardcodes `range(start: -30d)` ignores the dashboard time picker and scans thirty days even when someone is looking at the last five minutes, which is the usual explanation when one innocuous dashboard is hammering the database. Use `v.timeRangeStart` and `v.timeRangeStop` in Flux or `$__timeFilter` in SQL, and set `Max data points` plus `Min interval` on heavy panels so the downsampling window is pushed into the query instead of thinning raw points in the browser.
# /etc/grafana/provisioning/datasources/influxdb.yaml
apiVersion: 1
datasources:
- name: InfluxDB-Metrics
type: influxdb
access: proxy
url: http://influxdb:8086
jsonData:
version: Flux
organization: goodspace
defaultBucket: metrics_raw
httpMode: POST
timeout: 30
secureJsonData:
token: $INFLUX_READ_TOKEN
Q10How do you query data in InfluxDB using InfluxQL?
BasicInfluxQL
Answer
InfluxQL is a SQL-like query language used in InfluxDB 1.x (and still supported via a compatibility endpoint in 2.x and 3.x). The core verbs are `SELECT`, `FROM`, `WHERE`, `GROUP BY time(<duration>)`, `ORDER BY time`, and aggregate functions (`mean`, `sum`, `count`, `max`, `min`, `derivative`, `non_negative_derivative`, `percentile`, `moving_average`). Time-range filters using `now()` are idiomatic and absolutely required, an InfluxQL query without a time bound will try to scan every shard in the retention period and is the #1 cause of OOM kills in production 1.x clusters.
The `fill()` clause controls how empty time buckets are rendered (`null`, `previous`, `0`, `linear`). InfluxQL cannot do joins across measurements, subqueries with arbitrary expressions, or true window functions, for those, you'd use Flux (2.x) or SQL (3.x). InfluxQL also has a slightly quirky string handling: identifiers go in double quotes, string values in single quotes; getting this backwards is a classic interview gotcha.
Behaviours a senior interviewer will probe: `GROUP BY *` groups by every tag, which on a wide measurement returns thousands of series and is the accidental way most people time out a dashboard. `SLIMIT` and `SOFFSET` page over series while `LIMIT` and `OFFSET` page over points inside each series, and confusing the two is why a 'top 10 hosts' panel returns ten points from one host. Aggregates skip nulls rather than treating them as zero, so `sum()` over a sensor that went offline looks perfectly healthy, which is why you pair it with `count()` to detect missing data. And in 2.x and 3.x, InfluxQL is served through a compatibility layer, `/query` backed by a DBRP mapping in 2.x and `/api/v3/query_influxql` in 3.x, so a handful of constructs that worked on a native 1.x server (certain nested subquery expressions, some meta queries) behave differently or are unsupported, which is worth testing before you promise a lift-and-shift migration.
-- last hour, average CPU per host, 1-minute buckets
SELECT mean("value")
FROM "cpu_usage"
WHERE time > now() - 1h
GROUP BY time(1m), "host"
fill(null)
Q11What's the difference between InfluxDB 1.x, 2.x, and 3.x?
BasicVersions
Answer
InfluxDB 1.x (released 2016): the original, TSM (Time-Structured Merge) storage engine, InfluxQL, databases + retention policies + users, no built-in auth in OSS by default, continuous queries for downsampling, the TICK stack pairing (Telegraf, InfluxDB, Chronograf, Kapacitor). Still widely deployed at large enterprises and telcos, especially across legacy Indian telecom and manufacturing systems where upgrade windows are scarce. InfluxDB 2.x (released 2020): unified UI, Flux query language, organizations + buckets + tokens, built-in tasks (replacing CQs), Checks and Notifications for alerting, Telegraf-aware UI.
Same TSM engine under the hood, so cardinality limits carry over. InfluxDB 3.x (preview in 2023, GA in OSS as 'Core' and 'Enterprise' in 2024-2025): complete rewrite on the FDAP stack, Apache Flight (gRPC transport), DataFusion (query engine), Arrow (in-memory format), Parquet (storage). Adds SQL support, unlimited tag cardinality, much better compression, and object-storage backends (S3, GCS, Azure Blob) for effectively unlimited retention.
InfluxQL and Flux are still readable in 3.x for compatibility, but SQL is the recommended language going forward. For new projects starting in 2026, default to 3.x unless you have a hard constraint forcing 2.x. What a senior interviewer actually wants after the feature list is the compatibility matrix, because that is what sizes a migration.
The endpoints differ: 1.x is `/write?db=` and `/query` on port 8086 with auth off unless you set `auth-enabled = true` in `influxdb.conf`; 2.x is `/api/v2/write?org=&bucket=` plus `/api/v2/query` on 8086 with token auth always on, and InfluxQL reachable only through a DBRP mapping; InfluxDB 3 Core and Enterprise listen on 8181 by default and expose `/api/v3/write_lp?db=`, `/api/v3/query_sql` and `/api/v3/query_influxql`, driven by a single `influxdb3` binary rather than the `influxd` server plus `influx` client pair. The detail that catches teams out is that Flux does not exist in InfluxDB 3 Core or Enterprise at all, it survives only on Cloud Serverless and Cloud Dedicated, so a 2.x to 3.x move is a rewrite of every Flux task, alert and Grafana panel rather than a binary swap. The one mercy is that 3.x keeps a v1 and v2 write-compatible endpoint, so Telegraf's `outputs.influxdb_v2` keeps working if you point `bucket` at the new database name.
# 1.x: database in the query string, InfluxQL only, auth often disabled
curl -XPOST 'http://localhost:8086/write?db=telemetry&precision=s' \
--data-binary 'cpu,host=s1 value=42 1715500800'
# 2.x: org + bucket, token auth mandatory, Flux on /api/v2/query
curl -XPOST 'http://localhost:8086/api/v2/write?org=goodspace&bucket=metrics&precision=s' \
-H 'Authorization: Token $INFLUX_TOKEN' \
--data-binary 'cpu,host=s1 value=42 1715500800'
# 3.x Core/Enterprise: port 8181, db, bearer token, SQL
curl -XPOST 'http://localhost:8181/api/v3/write_lp?db=telemetry&precision=second' \
-H 'Authorization: Bearer $INFLUXDB3_AUTH_TOKEN' \
--data-binary 'cpu,host=s1 value=42 1715500800'
curl -G 'http://localhost:8181/api/v3/query_sql' \
-H 'Authorization: Bearer $INFLUXDB3_AUTH_TOKEN' \
--data-urlencode 'db=telemetry' \
--data-urlencode 'q=SELECT count(*) FROM cpu' \
--data-urlencode 'format=pretty'
Q12What is cardinality in InfluxDB and why does it matter?
BasicCardinality
Answer
Cardinality is the total number of unique series in your database. A series = a unique combination of measurement + tag set. Example: a `cpu_usage` measurement with tags `host` (1000 values) and `region` (5 values) has 1000 × 5 = 5,000 series.
In InfluxDB 1.x and 2.x (TSM engine), the in-memory inverted index grows with cardinality, 1 million series can mean 1-2 GB of RAM just for the index, and 10 million series often pushes a single-node cluster to OOM. Adding a high-cardinality tag like `request_id`, `user_id`, or a UUID is the #1 way to crash an InfluxDB cluster, engineers call it a 'cardinality explosion'. The interview question 'what happens if you tag `user_id` on a Jio-scale subscriber metric?' almost always comes up.
Answer: 500M+ series, the index OOMs the node, and the cluster falls over. InfluxDB 3.x removes this hard limit because Parquet doesn't need an in-memory series index, it uses min/max statistics in Parquet row groups for selective scans, but storage cost still grows roughly linearly with cardinality, and queries that touch many series still pay per-file I/O, so it's not free. Measurement details matter in the follow-up. `SHOW SERIES CARDINALITY` returns a HyperLogLog++ estimate, not a count; `SHOW SERIES EXACT CARDINALITY` walks the index and is expensive enough that you should not run it from a dashboard.
To find the culprit rather than the total, use `SHOW TAG VALUES EXACT CARDINALITY WITH KEY = "..."` per suspect tag, or `influx_inspect report-tsi -series-file /var/lib/influxdb/data/_series -top 10` offline against the data directory. 1.x also ships hard guards in `influxdb.conf`, `max-series-per-database` (default 1000000) and `max-values-per-tag` (default 100000), which reject the offending writes with `max-series-per-database limit exceeded` instead of letting the node die; they are blunt but far better than an OOM at 2am, and setting either to 0 disables the guard entirely. Cardinality is also per shard, so a bad tag introduced on Monday stops costing memory only when the shards containing it age out of retention, which is why the emergency lever during an incident is usually shortening retention or dropping the affected measurement rather than fixing the producer.
-- estimate first (cheap), then drill into the suspect tag
SHOW SERIES CARDINALITY ON telemetry
SHOW TAG KEYS ON telemetry FROM "http_requests"
SHOW TAG VALUES EXACT CARDINALITY ON telemetry
WITH KEY = "request_id"
-- emergency: stop the bleeding, then fix the producer
DROP SERIES FROM "http_requests" WHERE "request_id" != ''
# offline audit of the on-disk index, top 10 offenders
influx_inspect report-tsi \
-series-file /var/lib/influxdb/data/_series \
-top 10 \
/var/lib/influxdb/data/telemetry
# 1.x guard rails in influxdb.conf
# [data]
# max-series-per-database = 1000000
# max-values-per-tag = 100000
Q13What happens if you write two points with the same measurement, tag set and timestamp?
BasicWrite API
Answer
There is no primary-key violation and no error. The identity of a point is measurement plus tag set plus field key plus timestamp, so a second write to that identity overwrites the field value: last write wins, silently. Two consequences follow.
First, different field keys at the same timestamp merge rather than replace, so writing `cpu,host=s1 user=10` and then `cpu,host=s1 system=5` with the same nanosecond timestamp gives you one row carrying both fields. Second, and this is the property that matters operationally, writes are idempotent, so an ingest pipeline that retries after a socket timeout or replays a Kafka partition cannot create duplicates. That is what makes at-least-once delivery safe without a dedup layer, and it is the reason `curl` retries and Telegraf's `retry_interval` are not dangerous.
The failure mode is the mirror image: accidental collisions. If you send a 10 Hz sensor with `precision=s`, ten readings per second collapse onto the same timestamp and nine of them vanish with a 204 success response. The same happens when a tag that distinguishes two producers is empty (InfluxDB drops empty tag values entirely) or when a client stamps `time.Now()` truncated to seconds.
Nothing logs an error, so you detect it by comparing points sent against `SELECT count("value")` over the same window. Under the covers, TSM keeps both versions until compaction merges them, and InfluxDB 3 deduplicates overlapping Parquet files at query time using the sort key, so heavy duplicate load costs query performance even though results stay correct.
# same series + same timestamp, different fields => one merged row
cpu,host=s1 user=10.0 1715500800000000000
cpu,host=s1 system=5.0 1715500800000000000
# => cpu,host=s1 user=10.0,system=5.0 @1715500800000000000
# same series + same timestamp + same field => last write wins, no error
cpu,host=s1 user=10.0 1715500800000000000
cpu,host=s1 user=99.0 1715500800000000000
# => user=99.0
# silent data loss: 10 Hz source written with second precision
# POST /api/v2/write?bucket=metrics&precision=s
vibration,sensor=v01 value=0.41 1715500800
vibration,sensor=v01 value=0.44 1715500800
vibration,sensor=v01 value=0.39 1715500800
# => one point survives, server returns 204
# detection: what you sent vs what landed
SELECT count("value") FROM "vibration"
WHERE time > now() - 1h GROUP BY time(1m), "sensor"
Q14How do you start InfluxDB 3 Core with `influxdb3 serve` and create a database, token and first write?
BasicInfluxDB 3.x
Answer
InfluxDB 3 collapses the old `influxd` server and `influx` client into one `influxdb3` binary. You start it with `influxdb3 serve --node-id host01 --object-store file --data-dir ~/.influxdb3`, which listens on port 8181 rather than 8086. Two flags carry real weight. `--node-id` (called `--host-id` in earlier 3.x builds) is mandatory and namespaces this node's prefix inside the object store, so pointing two processes with the same node id at the same bucket is a corruption bug rather than a clustering feature. `--object-store` accepts `memory`, `file`, `s3`, `google` and `azure`; `memory` is perfect for tests and CI because everything disappears on exit, while `s3` additionally needs `--bucket`, `--aws-access-key-id` and `--aws-secret-access-key`.
Auth comes next: `influxdb3 create token --admin` prints the token exactly once and there is no way to recover it, so capture it into `INFLUXDB3_AUTH_TOKEN` immediately. A node started with no token configured accepts unauthenticated traffic, which is how test instances end up exposed. Databases (the 3.x name for buckets) are created implicitly on first write, or explicitly with `influxdb3 create database telemetry`.
From there `influxdb3 write --database telemetry --file data.lp` and `influxdb3 query --database telemetry 'SELECT ...'` wrap the `/api/v3/write_lp` and `/api/v3/query_sql` endpoints. The Docker path is `docker run -p 8181:8181 influxdb:3-core`, remembering to mount a volume, because the default container data directory is ephemeral and a restart takes your Parquet files with it.
# 1) start a single node backed by local files
influxdb3 serve \
--node-id host01 \
--object-store file \
--data-dir ~/.influxdb3
# 2) mint an admin token (printed once, never recoverable)
influxdb3 create token --admin
export INFLUXDB3_AUTH_TOKEN='apiv3_...'
# 3) create a database and write a point
influxdb3 create database telemetry
influxdb3 write --database telemetry \
'cpu_usage,host=server01,region=mumbai value=42.5'
# 4) query it back as SQL
influxdb3 query --database telemetry \
"SELECT host, avg(value) FROM cpu_usage \
WHERE time > now() - INTERVAL '1 hour' GROUP BY host"
# throwaway node for CI: nothing touches disk
influxdb3 serve --node-id ci01 --object-store memory
Q15What is the difference between InfluxDB 3 Core and InfluxDB 3 Enterprise?
BasicVersions
Answer
They are the same engine with different limits and licences. Core is the open-source, dual MIT and Apache-2 licensed build aimed at single-node, edge and recent-data workloads. Its defining constraint is the query window: Core compacts and serves roughly the last 72 hours of data.
Older data is still durably written to object storage, but Core will not answer queries against it, so a Core node is a hot store you downsample or forward from, never your system of record for last quarter's numbers. Core is also single-node, with no built-in replication, failover or read replicas. Enterprise removes the historical-query limit, adds multi-level compaction over the full dataset, supports multi-node topologies where you can dedicate nodes to ingest, compaction and query, and adds finer-grained access control.
It is commercially licensed, with a free licence tier intended for non-production and home use. Both builds share the same Parquet-plus-catalog storage layout, the same `/api/v3/*` endpoints and the same caches, including the Last Value Cache (`influxdb3 create last_cache`) that answers 'latest reading per device' from memory instead of scanning Parquet, so moving from Core to Enterprise is a licence and topology change rather than a data migration. The interview answer is the selection rule: Core on the factory gateway or the single observability box where you only look at the last day, Enterprise or Cloud Dedicated when you need HA, long-range analytical queries, or to keep a heavy dashboard workload from competing with ingest.
Key Points
- Core: open source, single node, queries roughly the last 72 hours
- Enterprise: full historical query, multi-node, finer-grained access control
- Same Parquet storage and /api/v3 endpoints in both
- Core to Enterprise is a licence and topology change, not a data migration
Q16What is Flux and how is it different from InfluxQL?
IntermediateFlux
Answer
Flux is a functional, pipe-forward data scripting language introduced in InfluxDB 2.x. It's much more expressive than InfluxQL, you get joins across measurements, conditional logic, custom functions, working with multiple buckets/orgs, and writing results back to a new bucket. The signature pattern is the pipe-forward operator `|>` which passes data from one function to the next: `from() |> range() |> filter() |> aggregateWindow() |> yield()`.
Flux is what powers InfluxDB tasks (replacing CQs), alerting, and dashboards in 2.x. In InfluxDB 3.x, SQL is the primary language and Flux is supported for backward compatibility but no longer the focus. Note the nuance a senior interviewer will want: InfluxDB Cloud Serverless and Cloud Dedicated still accept Flux for existing workloads, while InfluxDB 3 Core and Enterprise expose SQL and InfluxQL only, so every Flux task and Flux-mode Grafana panel is something you have to rewrite when you move onto a 3 Core node.
The other thing to understand is Flux's data model: a stream is a set of tables partitioned by the group key, so `group()`, `pivot()` and `join()` are operations on that partitioning rather than on rows. That is why `aggregateWindow(..., createEmpty: false)` exists, and why a script with several branches but no `|> yield()` on each returns only one result. Performance-wise, predicate pushdown into the storage engine only happens for `range()` and simple `filter()` calls placed immediately after `from()`; anything after a `map()` or `pivot()` runs in the Flux runtime over materialised data, which is the single most common reason a Flux query is slow.
// last 1 hour, 5-minute mean CPU per host
from(bucket: "metrics")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "cpu_usage" and r._field == "value")
|> aggregateWindow(every: 5m, fn: mean, createEmpty: false)
|> group(columns: ["host"])
|> yield(name: "mean")
Key Points
- Pipe-forward syntax with |> operator
- Supports joins, conditional logic, custom functions
- Powers tasks, alerts, dashboards in InfluxDB 2.x
- Less central in 3.x, SQL is the new default
Q17How do you downsample data using a Flux task?
IntermediateDownsampling
Answer
A task is a saved Flux script that runs on a schedule, replacing the old continuous query mechanism. The pattern: read raw data from a high-frequency bucket, aggregate by time, and write into a downsampled bucket with longer retention. Tasks are managed via the InfluxDB UI, CLI (`influx task create`), or the `/api/v2/tasks` endpoint, and they have first-class run history and retry semantics visible in the UI.
A task that runs every 5 minutes and writes the mean of the last 5 minutes into a `metrics_5m` bucket is the canonical 'continuous downsampling' setup. Don't forget idempotency, if the task fails and retries, your `to()` write must overwrite cleanly (same measurement + tags + timestamp). Add a small `offset` (e.g. 30s) so late-arriving points have a chance to land before the window aggregates, and monitor task run failures with a Grafana alert on the `_tasks` system bucket.
Three failure modes are worth raising unprompted. First, `range(start: -task.every)` is relative to wall clock at execution time, so a delayed or retried run reads a different window than the one it was meant to cover and you get a hole in the rollup; robust pipelines derive an explicit `start` and `stop` from the scheduled time instead of a relative duration. Second, never let a task write back into the bucket it reads from, or it will re-aggregate its own output on the next run and the numbers drift upward forever.
Third, a failing task keeps getting scheduled rather than being disabled, so it fails quietly forever unless something watches it: `influx task run list --task-id <id>` shows run history and `influx task retry-failed` replays them. Also remember that `to()` writes with the tags present at that point in the pipeline, so if `aggregateWindow` dropped a grouping column, several hosts silently merge into one series in the downsampled bucket.
option task = {name: "downsample_cpu_5m", every: 5m, offset: 30s}
from(bucket: "metrics_raw")
|> range(start: -task.every)
|> filter(fn: (r) => r._measurement == "cpu_usage")
|> aggregateWindow(every: 5m, fn: mean, createEmpty: false)
|> set(key: "_measurement", value: "cpu_usage_5m")
|> to(bucket: "metrics_downsampled", org: "goodspace")
Q18How does InfluxDB compare to Prometheus for monitoring?
IntermediateComparison
Answer
Both store time-series data, but they make opposite architectural choices: **Prometheus** uses a pull model (scrapes HTTP endpoints), is designed for short-term (15 days default) infrastructure metrics, and uses PromQL. **InfluxDB** uses a push model (clients write to it), retains data as long as your retention policies allow, supports much higher write throughput, and handles non-numeric fields (strings, bools) natively. Prometheus wins for Kubernetes infrastructure monitoring because pulling from `/metrics` endpoints is service-discovery friendly. InfluxDB wins for IoT, telecom, industrial telemetry, and any workload where data is generated externally (sensors, edge devices) and pushed inward.
Many production stacks run both, Prometheus for infra, InfluxDB for application/business metrics, with Grafana on top of both. Details that show real depth: Prometheus stores only float64 samples keyed by metric name plus labels, so there is no string or boolean value and no tag-versus-field distinction, while InfluxDB stores typed fields including strings on the same point. Prometheus deliberately ships no clustering in the core project, you scale it with federation, Thanos, Mimir or VictoriaMetrics, whereas InfluxDB 3 Enterprise provides its own multi-node story over object storage.
The difference that bites in production is staleness: Prometheus marks a series stale when a scrape stops returning it, which makes `up == 0` alerting natural and immediate, while InfluxDB simply stops receiving points and a silent device looks exactly like a device with nothing to report. Absence-of-data alerting therefore has to be built explicitly, typically a `count()` over a rolling window compared against the expected sample count per device. Interviewers usually close this comparison with 'so how do you alert when a sensor goes quiet?', and that is the answer they are fishing for.
Key Points
- Prometheus: pull, short-term, infra-focused, PromQL
- InfluxDB: push, configurable retention, IoT/telemetry, Flux/SQL/InfluxQL
- Common: run both, with Grafana as the unified UI
Q19What is the FDAP stack and how does InfluxDB 3.x use it?
IntermediateInfluxDB 3.x
Answer
FDAP stands for **Flight, DataFusion, Arrow, Parquet**, the four Apache projects that InfluxDB 3.x is built on. (1) **Arrow** is the in-memory columnar format used for all internal data representation. (2) **Parquet** is the on-disk columnar format, written to local disk or object storage (S3, GCS, Azure Blob). (3) **DataFusion** is the query engine that compiles SQL into vectorised Arrow operations. (4) **Flight** is the gRPC-based transport for sending query results between server and client efficiently. The practical upshot for users: unlimited tag cardinality, native SQL with window functions and joins, object-storage backends for cheap long-term retention, and 10-100× compression compared to TSM. Trade-off: writes are buffered and flushed to Parquet files in batches, so there's higher write latency than TSM at small scales.
Follow-ups to expect: because the planner is DataFusion, you get `EXPLAIN` and `EXPLAIN ANALYZE` for free, which is how you confirm that partition pruning actually happened rather than assuming it. Pruning depends on Parquet row-group min/max statistics, so a query filtering on `time` plus a selective tag reads only the matching row groups, while a query with no tag predicate over a wide range degrades into a near-full object-storage scan whose cost shows up as S3 GET requests rather than CPU. Arrow matters on the client side too: results come back as Arrow record batches over Flight, so a `pyarrow.flight` or `influxdb_client_3` client lands columnar data directly in pandas or Polars with no JSON parsing step, which is an order-of-magnitude difference on large result sets compared with the v2 CSV response format.
# pip install influxdb3-python pandas
from influxdb_client_3 import InfluxDBClient3
client = InfluxDBClient3(
host="localhost:8181",
token="YOUR_TOKEN",
database="telemetry",
)
# results arrive as Arrow record batches over Flight, no JSON parsing
table = client.query(
query="""
SELECT date_bin(INTERVAL '5 minutes', time) AS bucket,
host,
avg(value) AS avg_cpu
FROM cpu_usage
WHERE time > now() - INTERVAL '1 hour'
GROUP BY bucket, host
ORDER BY bucket DESC
""",
language="sql",
)
df = table.to_pandas()
print(df.head())
Q20What was Kapacitor and what replaced it?
IntermediateAlerting
Answer
Kapacitor was the original streaming/batch processing engine in the TICK stack (Telegraf, InfluxDB, Chronograf, Kapacitor) used for alerting and complex stream processing in InfluxDB 1.x. It used a DSL called TICKscript. Kapacitor still exists but it is essentially in maintenance mode, InfluxData's recommended modern path is **Flux tasks** in 2.x and **SQL-based tasks plus external alerting** (Grafana Alerting, Alertmanager, custom worker apps) in 3.x.
Expect the interviewer to ask 'how would you migrate off Kapacitor?' if the company has legacy 1.x clusters; the answer is to port TICKscripts to Flux tasks and emit alerts via HTTP/Slack/PagerDuty. Know the shape of it: Kapacitor ran two task types, `stream` tasks that receive a copy of every write through InfluxDB's subscription mechanism, and `batch` tasks that periodically query InfluxDB, driven with `kapacitor define`, `kapacitor enable` and `kapacitor show`. The subscription model is exactly what bites during a migration.
A dead or unreachable Kapacitor leaves a stale subscription registered in InfluxDB, visible with `SHOW SUBSCRIPTIONS`, and the 1.x server keeps trying to forward every write to it, which surfaces as rising write latency and repeated subscription write errors in `influxd.log`. Running `DROP SUBSCRIPTION` is therefore a mandatory decommissioning step, not an optional cleanup. For the migration answer, map node by node: `batch|query` becomes a scheduled Flux or SQL task, `alert().crit(lambda: ...)` becomes a Grafana alert rule carrying the same threshold, `stateChangesOnly()` maps onto Grafana notification policy grouping and repeat interval, and any `|influxDBOut()` node becomes a `to()` call or an `INSERT INTO` in the replacement task.
// legacy Kapacitor batch task: alert when 5-minute mean CPU crosses 90
batch
|query('SELECT mean("value") FROM "telemetry"."autogen"."cpu_usage"')
.period(5m)
.every(1m)
.groupBy('host')
|alert()
.crit(lambda: "mean" > 90)
.stateChangesOnly()
.slack()
.channel('#ops-alerts')
// kapacitor define cpu_alert -type batch -tick cpu_alert.tick \
// -dbrp telemetry.autogen
// kapacitor enable cpu_alert
// SHOW SUBSCRIPTIONS -- check for stale subscriptions before decommissioning
Q21How do you handle high-cardinality tags in InfluxDB?
IntermediateCardinality
Answer
First, audit what you have: `SHOW SERIES CARDINALITY` and `SHOW TAG VALUES CARDINALITY WITH KEY = "<tag>"` give you a starting point. Then apply one or more remedies: (1) **Move high-cardinality tags to fields**, losing the index but stopping the series explosion. Acceptable if you don't filter/group by that dimension. (2) **Bucket the value**, instead of tagging `user_id` (millions of values), tag a hashed-mod-1000 bucket `user_bucket` (1000 values) and keep `user_id` as a field.
Queries can still filter on the bucket and then post-filter on the field cheaply. (3) **Aggregate at write time**, Telegraf's `aggregator.basicstats` processor reduces per-second points to per-minute means before writing, often cutting series count by 60×. (4) **Upgrade to InfluxDB 3.x**, Parquet's columnar layout removes the in-memory cardinality penalty, although storage and query cost still scale. (5) **Shorter retention**, old high-cardinality data hurts query time even if writes are fine; drop the tail aggressively. (6) **Separate buckets per tenant or per device class**, keeps the index on each bucket bounded. In India, telcos like Jio specifically hit cardinality issues with per-subscriber-MSISDN tags and use schemes (2) and (3) heavily; smart-meter rollouts at discoms typically partition by region into separate buckets for the same reason. The follow-up worth pre-empting: fixing cardinality only helps future writes. Existing series stay in the index until the shards holding them age out of retention, so after a bad deploy the node stays under memory pressure for a full retention period unless you explicitly drop the affected series or shorten retention temporarily.
# 1) audit: find which tag is actually exploding
SHOW SERIES CARDINALITY ON telemetry
SHOW TAG VALUES CARDINALITY ON telemetry WITH KEY = "user_id"
# 2) bucket the offending tag at the agent, keep the raw value as a field
[[processors.starlark]]
source = '''
load("hash.star", "hash")
def apply(metric):
uid = metric.tags.pop("user_id", None)
if uid != None:
metric.fields["user_id"] = uid
metric.tags["user_bucket"] = hash.sha256(uid)[:2]
return metric
'''
# 3) collapse per-second points into per-minute statistics before writing
[[aggregators.basicstats]]
period = "60s"
drop_original = true
stats = ["count", "mean", "max", "min"]
Q22Why should you batch writes to InfluxDB?
IntermediatePerformance
Answer
Each HTTP write request has fixed overhead, TCP, TLS handshake (if not reusing connections), header parsing, authentication, and a write-lock on the WAL. Sending one point per request is 100-1000× slower than batching, and at high data rates it will exhaust ephemeral ports on the client side and overwhelm InfluxDB's request queue. The InfluxDB ingest documentation recommends 5,000-10,000 points per batch for the v2 API.
Telegraf batches automatically via its `metric_batch_size` and `flush_interval` settings (defaults: 1,000 points, 10 seconds, both worth raising for heavy workloads). If you write from your own application, accumulate points in memory and POST every N points or every M seconds, whichever comes first; persist the buffer to disk if memory loss on crash is unacceptable. Don't go too large, batches above 50,000 points start to risk request timeouts, especially over WAN links from edge to cloud, and the all-or-nothing failure mode hurts.
Also enable gzip compression on the request, it typically cuts wire bytes by 5-10× for Line Protocol, which matters on rural/cellular edge links common in Indian IoT deployments. Two more things a senior interviewer listens for. Retries must be bounded and must distinguish retryable from non-retryable failures, because a 400 replayed forever becomes a hot loop that burns the entire ingest budget on data that will never be accepted; the official clients expose this as `WriteOptions(batch_size, flush_interval, jitter_interval, retry_interval, max_retries, max_retry_delay, exponential_base)`.
And add jitter, because a fleet of agents or pods that all flush on a round ten-second boundary produces a sawtooth load profile where the server idles for nine seconds then saturates for one, and that spike is what actually triggers `503`s. The knobs are `collection_jitter` and `flush_jitter` in Telegraf, `jitter_interval` in the clients.
from influxdb_client import InfluxDBClient, WriteOptions
with InfluxDBClient(
url="http://influxdb:8086",
token="YOUR_TOKEN",
org="goodspace",
enable_gzip=True,
) as client:
write_api = client.write_api(
write_options=WriteOptions(
batch_size=5000,
flush_interval=10_000, # ms
jitter_interval=2_000, # spread a fleet of writers
retry_interval=5_000,
max_retries=5,
max_retry_delay=30_000,
exponential_base=2,
)
)
for line in stream_of_line_protocol():
write_api.write(bucket="metrics_raw", record=line)
Q23How do you back up and restore an InfluxDB database?
IntermediateOperations
Answer
In 2.x and 3.x: use `influx backup` (CLI) which writes a portable backup directory you can restore with `influx restore`. Pass `--bucket` to back up a single bucket. The backup contains the org/bucket metadata plus the TSM (or Parquet, in 3.x) files.
Schedule it via cron or a Kubernetes CronJob, store the output in object storage with lifecycle policies (S3 + Glacier). Test restores quarterly, a backup you never restore is a hope, not a recovery plan. In 1.x, the equivalent commands are `influxd backup -portable` and `influxd restore -portable`.
For high-availability setups (InfluxDB Enterprise or 3.x Cluster), replication is also configured between nodes; but replication is not a backup, you still need offline copies for ransomware/operator-error scenarios. What interviewers actually probe is the restore path and the version boundary. `influx restore` into a running server restores into new bucket IDs unless you pass `--new-bucket` or `--full`, and a `--full` restore replaces the whole server including tokens and users, which instantly invalidates the credentials your Telegraf agents are holding, so token rotation belongs in the runbook rather than being discovered at 3am. Backups are also not point-in-time consistent across a long-running job: a bucket under active write lands with a ragged tail, and the standard mitigation is to accept a few minutes of overlap and lean on write idempotency when you replay Kafka or the ingest buffer over the top.
In 3.x on object storage the picture changes shape entirely, because the Parquet files plus the catalog are the backup. Versioned S3 with a lifecycle policy and cross-region replication gives cheaper, more granular recovery than a periodic dump, but the catalog and the data must be snapshotted together, or you restore files the catalog has never heard of and the data is invisible to queries.
# 2.x: full backup, then restore one bucket under a new name
influx backup /var/backups/influx/$(date +%F) \
--host http://localhost:8086 \
--token $INFLUX_ADMIN_TOKEN
influx restore /var/backups/influx/2026-08-01 \
--bucket metrics_raw \
--new-bucket metrics_raw_restored \
--token $INFLUX_ADMIN_TOKEN
# 1.x equivalents
influxd backup -portable -database telemetry /var/backups/influx1/
influxd restore -portable -db telemetry -newdb telemetry_restored \
/var/backups/influx1/
# ship offsite, encrypted, and let a lifecycle policy age it out
aws s3 sync /var/backups/influx/ s3://gs-influx-backups/ --sse aws:kms
Q24What is the role of shards in InfluxDB?
IntermediateStorage
Answer
A shard is the physical storage unit in the TSM engine (1.x, 2.x). Each shard holds a contiguous time range, for example, one shard per day for hot data, one per week for older data. When a retention policy expires data, InfluxDB drops the entire shard, which is why retention is O(1) and not O(rows).
Shard groups are defined by the retention policy's shard duration, which is automatically chosen based on retention length (1h shards for <2-day retention, 1d for <6-month, 7d for longer) but can be overridden. Tuning: short shard durations (1h) for high-volume real-time workloads minimise the amount of in-memory state at any one time; long durations (1 week, 1 month) for analytical bucket-style data where queries span days reduce file-handle and metadata overhead. Too many small shards is also bad, each shard has its own TSI index, and 10,000+ shards on a node hurts startup time.
In InfluxDB 3.x, shards as such are gone, data lives in time-partitioned Parquet files, which the engine prunes by min/max timestamp from Parquet footer metadata. The operational follow-up is what to do when the layout is already wrong. You cannot retroactively change the duration of existing shard groups: `ALTER RETENTION POLICY ...
SHARD DURATION 1d` applies only to shard groups created after the change, so fixing a bad choice means writing forward with the new duration and letting the old shards expire, or exporting with `influx_inspect export` and reimporting. The symptoms of too many shards are distinctive and worth being able to name: startup that takes many minutes while the node opens every TSM file and loads indexes, file-descriptor exhaustion (raise `LimitNOFILE` in the systemd unit), and memory that climbs on restart rather than under query load. `SHOW SHARDS` and `influx_inspect report-disk` are the two commands to reach for.
Q25How would you store IoT sensor data from a factory floor in InfluxDB?
IntermediateSchema Design
Answer
Typical Indian manufacturing IoT setup at companies like Tata Steel or Mahindra: PLCs and sensors push data into an MQTT broker or OPC UA gateway, Telegraf consumes it via the appropriate input plugin, and writes to InfluxDB. Schema: one measurement per sensor *type* (`temperature`, `pressure`, `vibration`), not per sensor. Tags: `plant`, `line`, `machine`, `sensor_id`.
Field: `value` (float). Avoid tagging anything that changes frequently (operator name, batch number, those go in a relational system or as fields). Use a 7-day raw bucket and a 1-year hourly-aggregate bucket via a downsampling task.
Per-machine cardinality is usually manageable (a factory floor has hundreds to thousands of sensors, not millions). For multi-factory, use one bucket per factory or one org per factory if isolation matters. The details that separate a real deployment from a diagram: timestamps must come from the device or the gateway, never from Telegraf's arrival time, otherwise a plant that loses its uplink replays an entire backlog stamped within the same minute and every average for that window is wrong.
In the MQTT input that means `json_time_key` and `json_time_format`. Buffer at the edge rather than trusting Telegraf's in-memory buffer, which drops on overflow, so a site with flaky connectivity should write into a local broker or a local InfluxDB 3 Core node and replicate upward. Expect unit chaos across vendors, one PLC reporting Celsius and another Fahrenheit into the same measurement name, and normalise it with a `processors.converter` or `processors.starlark` step at ingest instead of in every dashboard. Finally, insist that `machine` and `sensor_id` stay stable across firmware upgrades, because a vendor that renames sensors on update silently doubles your series count overnight.
# Line Protocol from Telegraf MQTT input
temperature,plant=pune,line=A,machine=press-12,sensor_id=t01 value=78.3 1715500800000000000
vibration,plant=pune,line=A,machine=press-12,sensor_id=v01 value=0.42 1715500800000000000
pressure,plant=chennai,line=B,machine=hydra-3,sensor_id=p07 value=12.1 1715500800000000000
Q26How do you query data using SQL in InfluxDB 3.x?
IntermediateInfluxDB 3.x
Answer
InfluxDB 3.x exposes a SQL endpoint backed by Apache DataFusion. Connect via the FlightSQL protocol from clients like `pyarrow.flight`, Grafana's SQL data source, or any JDBC/ODBC client that supports FlightSQL. Tables map to measurements; columns map to tags + fields + `time`.
Queries support window functions, CTEs, joins across measurements, and standard SQL aggregates. This is a huge ergonomics improvement over InfluxQL/Flux for engineers coming from PostgreSQL or BigQuery backgrounds, and is the main reason most India-based observability teams are evaluating 3.x in 2026. Specifics worth naming: time bucketing is `date_bin(INTERVAL '5 minutes', time, TIMESTAMP '1970-01-01T00:00:00Z')`, not `GROUP BY time(5m)`, and the optional third argument is the origin that makes buckets align to the hour instead of to the query start.
Tag columns are nullable, so a point written without a tag yields `NULL` rather than an empty string, and `WHERE region != 'mumbai'` silently drops every row where `region` is null, which is a classic cause of missing data in a freshly migrated dashboard. The HTTP endpoints are `/api/v3/query_sql` and `/api/v3/query_influxql`, taking `db`, `q` and a `format` of `json`, `jsonl`, `csv`, `parquet` or `pretty`, and the `influxdb3 query` CLI wraps both. Predicate pushdown is the entire performance story: always bound `time` so the planner can prune partitions, use `EXPLAIN ANALYZE` to confirm only a handful of Parquet files were scanned, and avoid `SELECT *` on wide tables because reading every column off object storage defeats the point of a columnar engine.
-- 5-minute average CPU per host, last hour, only Mumbai region
SELECT
date_bin('5 minutes', time) AS bucket,
host,
AVG(value) AS avg_cpu
FROM cpu_usage
WHERE time > now() - INTERVAL '1 hour'
AND region = 'mumbai'
GROUP BY bucket, host
ORDER BY bucket DESC;
Q27How do you set up alerting on InfluxDB metrics?
IntermediateAlerting
Answer
Three common approaches in 2026: (1) **Grafana Alerting**, most popular. Define alert rules in Grafana that query InfluxDB on a schedule and route notifications via Slack, PagerDuty, OpsGenie, email. Works across all InfluxDB versions and lets you unify alerts from InfluxDB, Prometheus, and Loki under one rules UI. (2) **InfluxDB 2.x Checks & Notifications**, built into the InfluxDB UI; useful if you're staying entirely in the InfluxDB ecosystem.
Powered by Flux tasks under the hood, so deduplication and state tracking are straightforward. (3) **Kapacitor (legacy)**, still used in 1.x environments; TICKscripts trigger HTTP/Slack/PagerDuty alerts and can also act as a stream processor. For new builds, prefer Grafana Alerting, it has a far richer routing/silencing/grouping model (similar to Alertmanager), supports multi-condition rules across data sources, and decouples your alert config from your storage backend. Whichever you pick, write alert rules as code (Terraform, the Grafana provider, or YAML in Git) so you can review and roll back changes, clicking alerts together in a UI is a recipe for incident-time confusion.
Two things make alerting on time-series different from alerting on logs, and interviewers listen for both. Missing data is not a healthy value, so every rule needs an explicit no-data behaviour (in Grafana that is the `No data and error handling` setting), and leaving it as `OK` is exactly how a dead sensor becomes invisible for a week. Second, the evaluation window must be wider than your ingest lag: a rule evaluating the last 1 minute against a pipeline that flushes every 60 seconds will flap between firing and resolving on batch timing alone, so set the query range to at least twice the flush interval and use a `For` duration so the condition must hold before anyone gets paged.
// InfluxDB 2.x task: page when a sensor stops reporting (deadman)
import "http"
import "json"
option task = {name: "alert_sensor_deadman", every: 5m, offset: 30s}
silent = from(bucket: "metrics_raw")
|> range(start: -10m)
|> filter(fn: (r) => r._measurement == "temperature")
|> group(columns: ["sensor_id"])
|> count()
|> filter(fn: (r) => r._value < 5) // expect at least 5 points per 10m
silent
|> map(fn: (r) => {
body = json.encode(v: {text: "sensor " + r.sensor_id + " silent 10m"})
code = http.post(
url: "https://hooks.slack.com/services/REDACTED",
headers: {"Content-Type": "application/json"},
data: body,
)
return {r with notified: code}
})
Q28How do you secure an InfluxDB deployment?
IntermediateSecurity
Answer
Layered defenses: (1) **TLS** on all ports, never run port 8086 cleartext over the internet. Use a reverse proxy (nginx, Caddy, Envoy) with a real cert. (2) **Token-based auth** with least-privilege scopes, read-only tokens for Grafana, write-only tokens for Telegraf, no all-access tokens in code. Rotate via the `/api/v2/authorizations` endpoint. (3) **Network isolation**, InfluxDB should sit on a private subnet, accessible only from app servers and ingest agents.
In GCP, this means a VPC with firewall rules; in AWS, a VPC + security group. (4) **Audit logging**, InfluxDB Enterprise and Cloud log all administrative actions; in OSS, front it with nginx + access logs. (5) **Backups encrypted at rest**, S3 with SSE-KMS. The most common real-world compromise is leaked write tokens in client-side mobile apps, never put a write token in a mobile binary; proxy through your backend. Three more items a security-minded interviewer expects you to raise.
Tokens in 2.x are bearer credentials with no expiry by default, so scope each to one bucket and one verb, keep them in a secret manager, and audit with `influx auth list --json`. InfluxDB 3 Core and Enterprise use `influxdb3 create token --admin` with an `Authorization: Bearer <token>` header, and a node started without any token configured is completely open, which is precisely how test instances end up indexed on the public internet. Next, the 1.x compatibility endpoints `/query` and `/write` still accept credentials as `u` and `p` URL query parameters, which means they get written in cleartext into nginx and load-balancer access logs; force header auth and strip those parameters at the proxy. Finally, Flux's `http.post` and `sql.from` let anyone who can create a task make outbound network calls and read external databases from inside the server, which is server-side request forgery by design, so restrict task creation to a small operator group and keep query logging on so you can see what actually ran.
# least-privilege tokens, one per consumer
influx auth create --org goodspace \
--write-bucket 0a1b2c3d4e5f6071 --description 'telegraf-writer'
influx auth create --org goodspace \
--read-bucket 0a1b2c3d4e5f6071 --description 'grafana-reader'
# audit what exists, and revoke on suspicion rather than at rotation time
influx auth list --json | jq '.[] | {id, description, permissions}'
influx auth delete --id 0c9f2b7e1a4d3005
# InfluxDB 3 Core/Enterprise: bearer tokens, port 8181
influxdb3 create token --admin
curl -H 'Authorization: Bearer YOUR_TOKEN' \
--data-urlencode 'db=telemetry' \
--data-urlencode 'q=SELECT 1' \
--get 'http://localhost:8181/api/v3/query_sql'
Q29How do you test code against InfluxDB in CI using `influxdb3 serve --object-store memory` and `telegraf --test`?
IntermediateTesting
Answer
Mocking the client is the wrong instinct, because every bug worth catching lives in the parts a mock replaces: Line Protocol escaping, field types, timestamp precision and predicate semantics. Run a real server instead. `docker run --rm -p 8181:8181 influxdb:3-core influxdb3 serve --node-id ci01 --object-store memory` starts in a second and keeps nothing on disk, and Testcontainers has InfluxDB modules for Java, Python and Go if you want lifecycle management in the test itself. Four rules make those tests stable.
First, never let a test call `now()`: inject a clock and write fixed nanosecond timestamps, then query an absolute range, otherwise the suite fails at a midnight boundary or when CI is slow. Second, isolate per test with its own database or bucket, because last-write-wins means leftover points from an earlier test quietly change an average rather than raising an error. Third, flush before asserting: a batching write API returning does not mean the data is queryable, so use `WriteOptions(write_type=SYNCHRONOUS)` in tests or call `write_api.flush()` before the read.
Fourth, test the Telegraf config as a unit of its own, since most production schema mistakes originate there: `telegraf --test --config telegraf.conf --input-filter mqtt_consumer` prints exactly the Line Protocol that would be written, without writing it. The high-value test that most teams skip is a schema contract test: assert that the tag keys emitted for each measurement match an allow-list, so a new `request_id` tag fails CI instead of exploding cardinality in production a week later.
# conftest.py
import pytest, uuid
from influxdb_client import InfluxDBClient, Point, WriteOptions
from influxdb_client.client.write_api import SYNCHRONOUS
FIXED_NS = 1715500800000000000 # never now()
@pytest.fixture
def bucket(client):
name = f"test_{uuid.uuid4().hex[:8]}"
b = client.buckets_api().create_bucket(bucket_name=name, org="goodspace")
yield name
client.buckets_api().delete_bucket(b)
def test_cpu_point_roundtrip(client, bucket):
client.write_api(write_options=SYNCHRONOUS).write(
bucket=bucket,
record=Point("cpu_usage").tag("host", "s1").field("value", 42.5).time(FIXED_NS),
)
rows = client.query_api().query(f'''
from(bucket: "{bucket}")
|> range(start: 2024-05-12T00:00:00Z, stop: 2024-05-13T00:00:00Z)
|> filter(fn: (r) => r._measurement == "cpu_usage")
''')
assert rows[0].records[0].get_value() == 42.5
# schema contract: fail CI when someone adds a new tag
ALLOWED = {"cpu_usage": {"host", "region"}}
# telegraf --test --config telegraf.conf --input-filter mqtt_consumer
Q30A write returns HTTP 204 but the data never shows up in Grafana. How do you debug it?
IntermediateDebugging
Answer
Work outside in, and get Grafana out of the picture first by running the same query directly with `influx query` or `influxdb3 query` over an absolute time range. If the raw query returns rows, the bug is in the panel: a hardcoded `range(start: -30d)`, a dashboard timezone that is not UTC, a variable that resolved to nothing, or a missing DBRP mapping so an InfluxQL panel against 2.x silently sees no database. If the raw query is empty too, the point is either somewhere else in time or was never accepted.
Precision mismatch is the most common cause by far and it always returns 204: send millisecond epochs to an endpoint defaulting to `ns` and the points land in 1970, send seconds as nanoseconds and they land tens of thousands of years in the future. Query with `range(start: 0)` and inspect `_time` to find where they actually went. Next check retention: a backfill with timestamps older than the bucket retention is accepted and then evicted at the next shard drop, so it appears to work and then disappears.
Then check for partial rejection, because a field type conflict rejects only the offending points and returns 400 with the failing line while the rest of the batch lands, which looks like sparse data rather than an outage. On the agent side, grep the Telegraf log for `Metric buffer overflow; N metrics have been dropped`, which means the output was down longer than `metric_buffer_limit` and that data is simply gone.
# 1) is the write actually accepted? -i shows the status and the error body
curl -i -XPOST 'http://localhost:8086/api/v2/write?org=goodspace&bucket=metrics' \
-H 'Authorization: Token '"$INFLUX_TOKEN" \
--data-binary 'cpu_usage,host=s1 value=1i 1715500800000'
# HTTP/1.1 400 Bad Request
# {"code":"invalid","message":"field type conflict: input field \"value\" on
# measurement \"cpu_usage\" is type integer, already exists as type float"}
# 2) where did the points actually land in time?
influx query 'from(bucket: "metrics")
|> range(start: 0)
|> filter(fn: (r) => r._measurement == "cpu_usage")
|> keep(columns: ["_time", "host", "_value"])
|> sort(columns: ["_time"])
|> limit(n: 5)'
# 3) what is the agent emitting, and is it dropping?
telegraf --test --config /etc/telegraf/telegraf.conf
journalctl -u telegraf --since '1 hour ago' | grep -E 'buffer overflow|E!'
Q31How do you monitor InfluxDB itself using `/health`, `/metrics` and `/debug/vars`, and what do you alert on?
IntermediateOperations
Answer
Each version exposes its own introspection surface. 1.x publishes expvar counters at `/debug/vars`, scraped by Telegraf's `inputs.influxdb` plugin, plus `/ping` for liveness. 2.x serves Prometheus-format metrics at `/metrics` and health at `/health`, and keeps task run history in the `_tasks` system bucket and check state in `_monitoring`. InfluxDB 3 serves `/health` and `/metrics` on port 8181 and additionally exposes `system` tables you can query with SQL, including recent query history, which is the fastest way to find the dashboard that is hammering the node. The metrics that matter are not the host ones.
Alert on write error rate split by HTTP status, because a rising 400 rate means a producer started emitting the wrong field type while a rising 503 rate means you are saturated, and the remedies are opposite. Alert on series cardinality growth rate rather than absolute cardinality, since the absolute number is always alarming and the derivative is what predicts an OOM. Alert on task or continuous query failures, on free disk for both the data directory and the WAL directory separately, on query queue depth against `query-concurrency`, and in 3.x on compaction lag measured as the count of small Parquet files in the recent partitions.
Above all, alert on points written per minute per source, because ingest quietly stopping is the most common real incident and it is invisible in CPU and memory graphs. One structural rule: never store InfluxDB's own metrics only in the instance being monitored, or the dashboard dies with the database.
# scrape InfluxDB 2.x/3.x metrics with Telegraf into a SEPARATE instance
[[inputs.prometheus]]
urls = ["http://influxdb:8086/metrics"]
interval = "30s"
[inputs.prometheus.tags]
monitored_host = "influx-prod-01"
[[inputs.http_response]]
urls = ["http://influxdb:8086/health"]
response_string_match = "pass"
[[outputs.influxdb_v2]]
urls = ["http://influx-meta:8086"] # never the node being watched
bucket = "influx_selfmon"
# 1.x: expvar counters instead of /metrics
# [[inputs.influxdb]]
# urls = ["http://influxdb:8086/debug/vars"]
# the alert that catches the most real incidents: ingest went quiet
# from(bucket: "metrics_raw")
# |> range(start: -10m)
# |> filter(fn: (r) => r._measurement == "temperature")
# |> group(columns: ["plant"])
# |> count()
# |> filter(fn: (r) => r._value < 100)
# 3.x: which queries are burning the node right now
influxdb3 query --database telemetry \
"SELECT * FROM system.queries ORDER BY start_time DESC LIMIT 20"
Q32What drives InfluxDB cost (cardinality, retention, object-storage GETs) and how do you reduce it?
IntermediateCost
Answer
Four dimensions drive spend, and they are the same whether you self-host or buy managed: compressed bytes stored, cardinality, query I/O, and network egress. Cardinality is the one people underprice, because in 1.x and 2.x it converts directly into RAM for the in-memory index, which means it sets your instance size rather than your disk bill. The levers, in order of payoff: first, collect less at the source.
Changing Telegraf's `interval` from `10s` to `60s` beats any downsampling task, because a point you never wrote costs nothing to write, store, compact or query, and most dashboards render one-minute buckets anyway. Second, tier retention: a raw bucket at 7 days, one-minute rollups at 30 days and one-hour rollups at a year is the standard shape, and the ratio between one-second and one-hour resolution is 3600 to 1 on storage. Third, remove high-cardinality tags.
Fourth, gzip writes if you pay for bandwidth, which is normal on cellular edge links. On InfluxDB 3 over object storage the shape changes: per-GB storage is cheap enough to stop being the conversation, and the surprise line item is per-request GET charges plus cross-AZ traffic, so a dashboard that scans thousands of small Parquet files costs real money every refresh. That makes healthy compaction and a partition template that lets queries prune whole directories a cost control, not just a latency optimisation. Managed InfluxDB Cloud bills on ingest, query and storage depending on plan, so exactly the same changes show up on the invoice.
# 1) cheapest win: collect at the resolution you actually render
[agent]
interval = "60s" # was 10s
collection_jitter = "5s"
flush_interval = "30s"
# 2) tier retention instead of keeping raw data forever
influx bucket create --name metrics_raw --retention 168h # 7d
influx bucket create --name metrics_1m --retention 720h # 30d
influx bucket create --name metrics_1h --retention 8760h # 1y
# 3) find what is actually consuming disk before optimising blind
influx_inspect report-disk -detailed /var/lib/influxdb/data
# 4) 3.x: confirm a query prunes partitions instead of scanning objects
influxdb3 query --database telemetry \
"EXPLAIN ANALYZE SELECT avg(value) FROM cpu_usage \
WHERE time > now() - INTERVAL '1 hour' AND region = 'mumbai'"
Q33How would you architect an InfluxDB deployment for a national-scale IoT platform (millions of devices)?
AdvancedArchitecture
Answer
For Jio/Airtel-scale IoT ingest (10M+ devices, billions of points per day): (1) **Ingest tier**, a fleet of stateless ingest workers behind a load balancer, terminating MQTT/HTTP/Kafka and writing batched Line Protocol to InfluxDB. Don't let devices hit InfluxDB directly. (2) **Storage tier**, InfluxDB 3.x clustered (Enterprise or self-hosted Core with sharding), backed by S3-compatible object storage for Parquet files. 3.x is essential at this scale because the TSM cardinality limit (1.x/2.x) breaks down. (3) **Query tier**, separate read-only InfluxDB processes pointed at the same Parquet store, scaled horizontally for dashboards and ad-hoc analytics. (4) **Downsampling**, Flux/SQL tasks running every minute to produce 1-min, 5-min, 1-hour rollups in separate buckets with progressively longer retention. (5) **Schema discipline**, strict tag-set policy in code review (no high-cardinality tags), automated cardinality alerts. (6) **Disaster recovery**, daily backups to a second region, RPO < 24h. Telco India deployments typically also keep a parallel Kafka tier so they can replay ingest into a fresh InfluxDB if the storage tier is lost.
Do the arithmetic out loud, because interviewers want capacity reasoning rather than a box diagram. Ten million devices each reporting one metric every 60 seconds is roughly 167,000 points per second sustained, which a modest number of well-batched ingest workers handles comfortably, but it is also about 14.4 billion points a day, so retention is a cost decision before it is a technical one. On cardinality, one tag value per device is 10 million series before you multiply by metric type, which is exactly why Parquet-based 3.x is not optional at this scale. Then plan for the thundering herd: devices that reconnect after a regional outage all backfill simultaneously, so the ingest tier needs a rate limiter and Kafka needs enough retention to absorb that replay rather than letting the storage tier absorb it and fall over a second time.
Key Points
- Stateless ingest tier with batching, behind LB
- InfluxDB 3.x with object storage at this scale
- Separate query nodes from write nodes
- Tiered buckets (raw 7d, 1m for 30d, 1h for 1y)
- Kafka in front for replay-ability
Q34How does InfluxDB 3.x handle unlimited cardinality and what are the trade-offs?
AdvancedInfluxDB 3.x
Answer
InfluxDB 1.x/2.x (TSM) maintained an in-memory inverted index from tag-set hashes to series IDs. RAM grew with cardinality, so 10M+ series often required tens of GB of RAM and OOM-killed nodes. InfluxDB 3.x removes the in-memory series index entirely.
Writes go into an in-memory WAL, are sorted and compacted into Parquet files partitioned by time (and optionally by tag), and the Parquet column statistics (min/max per row group) act as a 'lazy' index that DataFusion uses for predicate pushdown. Queries that filter on highly selective tags read only the matching row groups from object storage. Trade-offs: (1) query latency for single-series lookups is higher than TSM (you pay an S3 read), (2) memory usage on writes is bounded but Parquet compaction is CPU-heavy, (3) very small workloads see no benefit and may be slower.
Net: 3.x is a clear win above ~5M series; below that, 2.x is often simpler. Two further trade-offs are worth volunteering unprompted. Compaction is the hidden operational cost: freshly written data lands as many small Parquet files, and until they are merged into larger ones a query over that window opens far more objects than it should, so recent-data latency degrades whenever compaction falls behind.
In InfluxDB 3 that boundary is also a product boundary, with Core aimed at single-node, edge and recent-data use while Enterprise carries the compaction and historical-query story for large datasets. Second, partitioning strategy replaces index design as the thing you actually tune. The default partitioning is by day, and on a high-cardinality table you usually also want a coarse tag in the partition template so a query filtering on `region` prunes whole directories instead of relying on row-group statistics inside every file. Getting that wrong does not show up as high CPU, it shows up as a query that reads thousands of objects and an object-storage request bill nobody budgeted for.
Q35How would you migrate from InfluxDB 1.x to 2.x or 3.x in a zero-downtime production system?
AdvancedMigration
Answer
Plan in phases: (1) **Parallel writes**, modify ingest (Telegraf or app code) to write to BOTH 1.x and the new cluster simultaneously, behind feature flags. Validate row counts and aggregate values match. (2) **Backfill historical data**, use `influx_inspect export` from 1.x to dump Line Protocol, then `influx write` into the new bucket. Backfill in time-range chunks (1 week at a time) to bound failure blast radius. (3) **Port queries**, InfluxQL queries mostly work in 2.x via a compatibility endpoint; in 3.x you usually want to rewrite to SQL.
Port Grafana dashboards by changing the data source and updating the query language. (4) **Port continuous queries to Flux tasks (2.x) or scheduled SQL/external scheduler (3.x)**, validate each downsampling output matches the legacy CQ output for a week. (5) **Switch reads**, flip Grafana / app reads to the new cluster, watching error rates. (6) **Decommission old writes**, last step, only after weeks of stable parallel operation. Common pitfall: timestamp precision differences (default ns in v2 vs whatever the v1 client used) can cause silent duplicate/missing points. Two more risks to name.
Field type conflicts surface only at write time, so a field stored as an integer in 1.x but emitted as a float by the new client is rejected on the new cluster while the old one keeps happily accepting it, which is why the parallel-write phase must alert on write error rates rather than just comparing row counts. And validate with checksums, not eyeballs: compare `count()` and `sum()` per measurement per day between old and new across the whole backfill range, and treat any day that differs as a re-import rather than trying to chase individual points. Keep the export slices small enough that a failed chunk is a ten-minute retry, not a weekend.
# 1) export one bounded week of history as Line Protocol
influx_inspect export \
-datadir /var/lib/influxdb/data \
-waldir /var/lib/influxdb/wal \
-database telemetry \
-start 2026-01-01T00:00:00Z \
-end 2026-01-08T00:00:00Z \
-compress \
-out /tmp/telemetry-w1.lp.gz
# 2) load that slice into the new bucket
influx write \
--bucket metrics_raw \
--org goodspace \
--file /tmp/telemetry-w1.lp.gz \
--compression gzip \
--precision ns
# 3) verify the slice before starting the next one
influx query 'from(bucket: "metrics_raw")
|> range(start: 2026-01-01T00:00:00Z, stop: 2026-01-08T00:00:00Z)
|> filter(fn: (r) => r._measurement == "cpu_usage")
|> count()'
Q36How do you diagnose and fix slow Flux/SQL queries in InfluxDB?
AdvancedPerformance
Answer
Step-by-step diagnostic: (1) **Profile the query**, in InfluxDB 2.x, use `option profiler.enabledProfilers = ["query", "operator"]` to see per-operator runtime. In 3.x, prepend `EXPLAIN ANALYZE` to a SQL query to see DataFusion's plan + row counts at each stage. (2) **Check the time range**, `range(start: -30d)` on a high-cardinality bucket scans far more data than needed. Push filters to before aggregates. (3) **Tag filters first**, `filter(fn: (r) => r.host == 'server01')` on a tag should appear *before* operations that fan out (joins, unbounded aggregates). (4) **Avoid `pivot()` and `join()` on huge series sets**, these are expensive.
Pre-aggregate in a downsampling task. (5) **Cardinality**, `SHOW SERIES CARDINALITY` on the bucket. If it's growing, find the offending tag with `SHOW TAG VALUES CARDINALITY`. (6) **Read I/O**, in 3.x, watch S3 GET counts per query (CloudWatch / GCP Logs). If a query reads thousands of Parquet files, the time range is too wide or partitioning is wrong.
Typical fix order: narrow time range → filter on tags before aggregates → push the aggregation into a continuous task → upgrade storage / partition layout. Two systemic causes sit outside the query itself. If a dashboard is slow because thirty panels each run their own aggregate over raw data, no amount of query tuning fixes it; the answer is a materialised rollup the panels read instead, and the tell is that the database is idle at rest and only melts when someone opens that one dashboard. And check saturation before blaming the query: InfluxDB 2.x caps concurrent queries with `query-concurrency` and `query-queue-size`, and once the queue is full new queries are rejected outright rather than running slowly, so a report of intermittent dashboard errors is usually contention, not a bad query.
// 2.x: enable the profilers and read per-operator timings
option profiler.enabledProfilers = ["query", "operator"]
from(bucket: "metrics_raw")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "cpu_usage" and r.host == "server01")
|> aggregateWindow(every: 1m, fn: mean, createEmpty: false)
-- 3.x: confirm partition pruning and how many Parquet files were opened
EXPLAIN ANALYZE
SELECT date_bin(INTERVAL '1 minute', time) AS bucket,
avg(value) AS avg_cpu
FROM cpu_usage
WHERE time > now() - INTERVAL '1 hour'
AND host = 'server01'
GROUP BY bucket;
Q37Beyond Prometheus, what other time-series databases compete with InfluxDB and when would you choose each?
AdvancedComparison
Answer
The 2026 time-series landscape, with selection criteria: (1) **TimescaleDB** (Postgres extension), pick when you need full SQL, joins with relational tables, and existing Postgres ops expertise. Good for financial tick data and analytical workloads. (2) **ClickHouse**, pick for analytical workloads with very wide rows and ad-hoc SQL. Outperforms InfluxDB on aggregate queries over billions of rows but lacks built-in retention/downsampling primitives. (3) **VictoriaMetrics**, pick for Prometheus-compatible scraping at huge scale; lower resource usage than Prometheus for the same workload. (4) **QuestDB**, pick for low-latency financial and trading workloads; uses SQL with time-series extensions. (5) **TDengine**, Chinese-origin TSDB popular in industrial IoT. (6) **OpenTSDB**, older, HBase-backed; mostly legacy. **When to pick InfluxDB specifically**: easy to operate single-node, great ecosystem (Telegraf inputs cover everything, Grafana integration is first-class), good fit for IoT/telemetry with mixed numeric+string fields, and SQL via InfluxDB 3.x covers most analytical needs.
In India, InfluxDB dominates IoT and telecom telemetry, while ClickHouse dominates ad-tech and product analytics, both are common stacks, sometimes side-by-side. Two framing points land well with senior interviewers. These are rarely either/or in practice: the common 2026 pattern is a hot store with short retention driving operational dashboards plus a columnar analytical store for long-range questions, and InfluxDB 3 partly collapses that split because it writes Parquet you can point other engines at.
And give the operational criterion, not just the benchmark. TimescaleDB inherits Postgres backup, replication, connection pooling and monitoring that your team already runs. ClickHouse asks you to learn a genuinely different operational model, including background merges and `ReplacingMergeTree` deduplication semantics that surprise people who expect a normal UPDATE. InfluxDB gives you Telegraf's plugin catalogue, which is frequently the deciding factor when the data source is a Modbus PLC, an SNMP switch or an OPC UA gateway rather than an application you control and can instrument yourself.
Q38Walk through the TSM storage engine: WAL, cache, TSM files, compaction and TSI.
AdvancedStorage
Answer
A write in 1.x and 2.x lands in three places in order. It is appended to the write-ahead log under the `wal/` directory and fsynced according to `wal-fsync-delay`, then inserted into an in-memory cache keyed by series, and only then acknowledged, so durability comes from the WAL and query visibility comes from the cache. The cache is snapshotted to an immutable TSM file when it crosses `cache-snapshot-memory-size` (default 25 MB) or after `cache-snapshot-write-cold-duration` (default 10 minutes) without writes, and `cache-max-memory-size` (default 1 GB) is the hard ceiling above which writes are rejected outright.
A TSM file is a series-keyed index plus compressed blocks: delta-of-delta and simple8b for timestamps, Gorilla XOR for floats, zigzag plus RLE for integers, bit-packing for booleans, Snappy for strings, which is where the 10-90x compression comes from. Compaction then merges small files upward through levels, with `compact-full-write-cold-duration` (default 4 hours) triggering a full compaction of cold shards, and this is also the only point at which tombstones from a `DELETE` actually free disk. Separately, TSI is the on-disk inverted index (`index-version = "tsi1"`) that replaced the original in-memory index so that cardinality no longer has to fit in RAM. Three consequences show up in production: restart time is proportional to un-snapshotted WAL size, so a node killed with a full cache can take minutes to replay; compaction competes with ingest for CPU and IOPS, appearing as periodic write-latency spikes; and thousands of shards mean thousands of open TSM files, which is why file-descriptor exhaustion is a classic 1.x outage.
# influxdb.conf: the knobs that decide memory, restart time and IO
[data]
dir = "/var/lib/influxdb/data"
wal-dir = "/var/lib/influxdb/wal" # put on a separate device
index-version = "tsi1" # on-disk index, not in-memory
wal-fsync-delay = "0s" # raise on spinning disks
cache-max-memory-size = "1g" # writes rejected above this
cache-snapshot-memory-size = "25m" # snapshot cache -> TSM
cache-snapshot-write-cold-duration = "10m"
compact-full-write-cold-duration = "4h"
max-concurrent-compactions = 0 # 0 = half of GOMAXPROCS
# inspect what is actually on disk
influx_inspect report-disk -detailed /var/lib/influxdb/data
influx_inspect dumptsm -index /var/lib/influxdb/data/telemetry/autogen/12/000000012-000000002.tsm
influx_inspect verify -dir /var/lib/influxdb
# shard sprawl is a file-descriptor problem before it is a query problem
SHOW SHARDS
# /etc/systemd/system/influxdb.service.d/override.conf
# [Service]
# LimitNOFILE=65536
Q39Trace a write through InfluxDB 3 from `/api/v3/write_lp` to queryable Parquet. What is lost if the node crashes?
AdvancedInfluxDB 3.x
Answer
The request hits `/api/v3/write_lp`, is parsed, and is validated against the catalog. New tables or new columns cause a catalog update that is itself persisted, which is why a producer that invents a column per request is expensive in 3.x even though there is no series index. The points are then appended to a write-ahead log segment and added to an in-memory queryable buffer, and the response returns.
Two things follow from that ordering. Data is queryable the instant the write returns, before any Parquet file exists, so 'my data is not in object storage yet' is never an explanation for a missing recent point. And durability is bounded by the WAL flush, governed by `--wal-flush-interval` (default one second), so an unclean kill can lose at most that window of acknowledged writes; running with `--object-store memory` loses everything, which is fine for CI and fatal in production.
Later, the buffer is snapshotted, sorted by the sort key of tags then time, written out as Parquet objects, and the catalog is updated to point at them, after which the covered WAL segments are dropped. On restart the node replays surviving WAL segments back into the buffer. A query therefore unions three sources: the in-memory buffer, recently persisted Parquet that has not been compacted, and compacted Parquet, deduplicating on the sort key as it goes. That union is why duplicate-heavy ingest slows queries while still returning correct results, and why recent-window latency degrades whenever compaction falls behind and leaves hundreds of small objects in the newest partitions.
# durability and file-size behaviour are start-up flags, not runtime config
influxdb3 serve \
--node-id host01 \
--object-store s3 \
--bucket gs-influx3-prod \
--data-dir /var/lib/influxdb3 \
--wal-flush-interval 1s \
--gen1-duration 10m
# the write is queryable immediately, before any Parquet exists
influxdb3 write --database telemetry 'cpu_usage,host=s1 value=42.5'
influxdb3 query --database telemetry \
"SELECT * FROM cpu_usage ORDER BY time DESC LIMIT 1"
# confirm how many objects a recent-window query actually opens
influxdb3 query --database telemetry \
"EXPLAIN ANALYZE SELECT avg(value) FROM cpu_usage \
WHERE time > now() - INTERVAL '15 minutes'"
# a ParquetExec over hundreds of tiny files = compaction is behind
Key Points
- WAL append plus in-memory buffer, then acknowledge: queryable before persistence
- Durability window is bounded by --wal-flush-interval
- Queries union buffer, uncompacted Parquet and compacted Parquet, deduplicating on the sort key
- Compaction lag shows up as many small objects and slow recent-window queries
Q40What is the InfluxDB 3 Processing Engine and when would you use a Python plugin instead of an external service?
AdvancedInfluxDB 3.x
Answer
The Processing Engine is an embedded Python runtime inside InfluxDB 3 Core and Enterprise that runs your code in the database process, filling the gap left when Flux tasks and Kapacitor disappeared. You enable it by starting the server with `--plugin-dir`, drop a Python file in that directory, and attach it with `influxdb3 create trigger`. Three trigger kinds cover most needs.
A WAL-flush trigger (`--trigger-spec "all_tables"` or `"table:cpu_usage"`) calls `process_writes(influxdb3_local, table_batches, args)` on every flushed write batch, which is how you build derived series, enrichment or deadman detection with sub-second latency. A scheduled trigger (`--trigger-spec "every:1m"` or a cron spec) calls `process_scheduled_call(...)` and is the natural replacement for a downsampling task. A request trigger exposes `process_request(...)` at `/api/v3/engine/<path>` so an external system can invoke logic on demand.
Inside a plugin, `influxdb3_local` gives you a query interface, a writer that emits Line Protocol back into a database, and a logger, and `--trigger-arguments` passes per-trigger configuration so one plugin file can serve several triggers. The judgement question interviewers are really asking is when not to use it. Because plugins execute in the database process, a slow or dependency-heavy plugin adds latency to the write path and a crash loop is a database problem rather than an application problem. Use it for small, deterministic, low-latency transforms on edge nodes where standing up a second service is not worth it; keep anything CPU-heavy, network-blocking, or requiring normal CI, versioning and rollback discipline in an external consumer reading from Kafka.
# /var/lib/influxdb3/plugins/deadman.py
def process_scheduled_call(influxdb3_local, call_time, args):
threshold = int(args.get("min_points", 5))
rows = influxdb3_local.query(
"""
SELECT sensor_id, count(value) AS n
FROM temperature
WHERE time > now() - INTERVAL '10 minutes'
GROUP BY sensor_id
"""
)
for r in rows:
if r["n"] < threshold:
influxdb3_local.warn(f"sensor {r['sensor_id']} silent: {r['n']} points")
influxdb3_local.write(
LineBuilder("sensor_health")
.tag("sensor_id", str(r["sensor_id"]))
.int64_field("points_10m", int(r["n"]))
)
# enable the engine and attach the trigger
# influxdb3 serve --node-id host01 --object-store file \
# --data-dir /var/lib/influxdb3 --plugin-dir /var/lib/influxdb3/plugins
influxdb3 create trigger \
--database telemetry \
--plugin-filename deadman.py \
--trigger-spec 'every:5m' \
--trigger-arguments min_points=5 \
sensor_deadman
Frequently Asked Questions
Is InfluxDB better than Prometheus in 2026?
Neither is universally better, they target different problems. Prometheus is the standard for Kubernetes infrastructure monitoring because of its pull model and service-discovery friendliness. InfluxDB is the standard for IoT, telecom telemetry, industrial sensors, and long-retention metric storage because of its push model, configurable retention, and richer data types. Many teams run both.
How much does an InfluxDB developer earn in India?
₹8-24 LPA in 2026 for engineers with strong InfluxDB experience as part of a broader observability or IoT stack. The upper end is typically at telcos (Jio, Airtel), industrial IoT companies, and observability product teams. Pure 'InfluxDB DBA' roles are rare; most positions combine it with Telegraf, Grafana, Kafka, and one of Kubernetes / cloud platforms.
Should I learn Flux or SQL for InfluxDB in 2026?
If you're targeting InfluxDB 3.x (which is where new deployments are going), prioritise SQL, it's the primary query language, has wider tooling support, and the skill is transferable to ClickHouse, BigQuery, and Postgres. Learn Flux only if you're working with an existing 2.x deployment that has Flux tasks/dashboards you need to maintain. InfluxQL remains useful for legacy 1.x systems still common in Indian telecom and manufacturing.
What's the biggest mistake people make when modeling data in InfluxDB?
Tagging unbounded values, typically `user_id`, `request_id`, `device_serial_number`. Each new tag value creates a new series, and in 1.x/2.x the in-memory index grows linearly with series count, eventually OOM-killing the node. The fix is to put those values in fields (or upgrade to 3.x, which handles high cardinality natively but still costs storage). Always run `SHOW SERIES CARDINALITY` before a load test.
How does InfluxDB fit into the IoT growth story in India?
India's IoT market is exploding around 2026, Jio's smart-meter rollouts, Airtel's industrial IoT services, EV charging networks (Tata Power, Ola Electric), smart-city projects, and connected manufacturing under 'Make in India'. InfluxDB sits at the data layer in most of these stacks, paired with Telegraf or Kafka for ingest and Grafana for visualization. Hiring for engineers who understand cardinality, downsampling, and edge-to-cloud Telegraf pipelines is steadily rising across these segments.
Does InfluxDB 3 Core really only let you query the last 72 hours?
Yes, and it is the single most important thing to know before choosing Core. Core writes all your data durably to object storage, but its compaction and query path cover roughly the most recent 72 hours, so older data is retained and not queryable from that node. That makes Core a strong hot store for edge gateways and single-server monitoring, provided you downsample or forward anything you need long-range. Removing the limit means InfluxDB 3 Enterprise, Cloud Dedicated or Cloud Serverless, which is a licence and topology change rather than a data migration since the Parquet layout is the same.
Do I have to rewrite my Flux tasks to move from InfluxDB 2.x to 3.x?
If you are moving to InfluxDB 3 Core or Enterprise, yes. Flux is not present in those builds at all, so every Flux task, every Flux-mode Grafana panel and every Check or Notification has to be rewritten as SQL or InfluxQL against `/api/v3/query_sql` and `/api/v3/query_influxql`, with scheduling moved to the Processing Engine or an external scheduler. Flux still runs on Cloud Serverless and Cloud Dedicated for existing workloads. Writes are the easy half: 3.x keeps a v2-compatible write endpoint, so Telegraf's `outputs.influxdb_v2` keeps working once you point `bucket` at the new database name.
What is the fastest way to run InfluxDB locally for development and CI?
For InfluxDB 3, `influxdb3 serve --node-id ci01 --object-store memory` starts in about a second and leaves nothing on disk, which is ideal for a test suite; swap `--object-store memory` for `file --data-dir ~/.influxdb3` when you want the data to survive a restart. For 2.x, `docker run -p 8086:8086 influxdb:2` plus `influx setup` gets you an org, bucket and token in one step. Whichever you use, give each test its own database or bucket and write fixed timestamps rather than `now()`, because last-write-wins semantics mean leftover points change results silently instead of failing loudly.
Introduction
InfluxDB has become the default time-series database for IoT, telemetry, monitoring, and observability workloads in 2026. With the release of InfluxDB 3.0 (Core/Enterprise) rebuilt on the FDAP stack, Flight, DataFusion, Arrow, and Parquet, the platform now handles unlimited tag cardinality, native SQL queries, and columnar storage at a scale that the original 1.x TSM engine never could. InfluxData also shifted the open-source posture, with Core OSS aimed at single-node and edge use, while Enterprise targets clustered, high-availability deployments.
If you're interviewing for an InfluxDB role in India today, at telcos like Jio and Airtel, IoT-heavy manufacturing companies (Tata, Mahindra, L&T), EV makers, smart-meter projects, fintech metric storage at Razorpay or PhonePe, or observability product teams, expect deep questions on the time-series data model (measurement, tags, fields, timestamps), retention policies, Flux vs InfluxQL vs SQL, cardinality management, downsampling strategies, and the architectural differences between InfluxDB 1.x/2.x/3.x as well as competitors like Prometheus, ClickHouse, and TimescaleDB.
This page covers 40 InfluxDB interview questions asked in 2026, grouped by difficulty. Each answer includes the underlying concept, the production failure mode behind it, and a code example where it adds clarity. Use the basic section to refresh fundamentals, intermediate for the operational patterns interviewers probe (batching, downsampling, monitoring, testing, cost), and advanced for storage-engine internals and system-design conversations that come up in senior interviews.
Ready to practice InfluxDB interviews?
Don't just read, practice these InfluxDB questions live with an AI interviewer that asks follow-ups and scores your answers.