← Back
Home › Systems › IT operations, analytics and integration

bi-dashboard

BI dashboards on a warehouse

Superset, Looker

Open the bi-dashboard pagebi-dashboard Hdr histogramdata-structures: Log-linear bucketed histograms with bounded relative error for latency percentilesDeterministic simulationtestingdistributed: Run the whole system in one thread under a seeded scheduler with simulated network, disk and clock, so every failure replays from its seed.›Primary-backup replicationdistributed: One node orders all writes and ships them to standbys; the acknowledgement rule (none, one, all) sets what a crash loses, and an external arbiter decides who takes over.›Process supervisionhardware-os: A parent process starts services, reaps their exits and restarts them under a delay and burst-limit policy, then stops them with SIGTERM before SIGKILL.›Fair queuingnetworking: Deficit round robin / weighted fair queuing to share capacity among tenants or flowsAuthorization models (RBAC,ABAC, ReBAC)security: How to decide who may do what to which object; roles for coarse rules, relationships for sharing, and checks on every object.›Coverage-guided fuzzingsecurity: Mutate inputs, run an instrumented target, and keep any input that reaches a new code edge; feedback turns blind guessing into incremental search.›Mutual TLSsecurity: TLS where the client also proves a certificate key, so every connection carries a verified, rotatable machine identity.›Lttb downsamplingstatistics: Largest-Triangle-Three-Buckets: reduce a series to N points while keeping its visual shapeIncremental view maintenancestorage: Update materialized views from deltas instead of recomputingPoint-in-time recoverystorage: Periodic base backups plus a continuously archived change log let you rebuild the state as of any instant, then branch from there.›Rollup aggregationstorage: Fold raw events into one mergeable partial aggregate per time bucket and dimension key, then merge fine buckets into coarser ones, so long ranges read few rows and stay exact.›Semantic layerstorage: Metric and dimension definitions compiled to SQL with join paths and access rulesConnection poolingsystems: Reuse and multiplex backend connections with bounded pools, checkout queues and health evictionCron schedulingsystems: Cron expression parsing and next-fire-time computation, with catch-up and time-zone rulesGraceful drainingsystems: On a termination signal, stop taking new work, finish in-flight work until a deadline, tell clients to reconnect elsewhere, then exit; clients resume from a token.›LRU and CLOCKsystems: LRU evicts the least recently used entry via hash map plus linked list; CLOCK approximates it with a reference bit, so hits take no lock.›Request coalescingsystems: Collapse concurrent identical requests into one backend fetch (singleflight)Cooperative schedulingconcurrency: Green threads/coroutines yielding at await points on a user-space schedulerFault injectiondistributed: Inject latency, errors, kills and partitions via proxies, netem or hooksRecord replaydistributed: Record every nondeterministic input (time, randomness, I/O, model and tool outputs, per-tick player input) and re-execute deterministically for debugging, replays and state rebuildLeasesdistributed: A lock that expires on its own: bounded-time ownership that survives crashes and partitions, given bounded clock drift and fencing tokens on writes.›Health checkingsystems: Decide per backend whether to route to it using probes and real-traffic errors, with consecutive-count hysteresis, capped ejection and a panic fallback.›PRNGs (PCG, xoshiro)numerics: Small, fast, statistically strong non-cryptographic generators: PCG32 and xoshiro256**, with seeding, parallel streams and unbiased ranges.›Code coverage instrumentationcompilers: Insert counters into compiled code to record which blocks, edges or lines ran; a spanning tree of the control-flow graph cuts the counters needed.›Delta debuggingcompilers: Ddmin minimization of failing inputs or change setsFast hash functionsdata-structures: Non-cryptographic hashes built from 64×64→128-bit multiplies and xor-shifts; pick by key size, trust level and whether the hash is persisted.›Sanitizerssecurity: ASan/UBSan/TSan shadow memory and instrumentation to catch memory bugsWrite-ahead logstorage: Append each change to a checksummed sequential log and fsync it before touching data pages; the basis of crash durability in nearly every database.›Change data capturestorage: Decode the database's own commit log into row-change events in commit order, with a resume position, so any consumer can mirror the data exactly.›+ 7 moreTransparent interceptionnetworking: Redirect traffic to a local proxy (iptables TPROXY/REDIRECT, eBPF) without app changesSyscall interceptionsecurity: Intercept syscalls via ptrace, seccomp user notify or a user-space kernelFencing tokensdistributed: A number that grows with every lock grant and is checked by the protected resource, so a paused ex-holder's late write is rejected.›Control-flow graphcompilers: Split a linear instruction list into basic blocks and connect them by jumps; the graph every optimizer, SSA builder and dataflow pass walks.›Minimum spanning treegraphs: Cheapest set of edges connecting all vertices; Kruskal sorts edges and joins components with union-find, Prim grows one tree, Boruvka merges in parallel rounds.›Failure bisectionsearch-sort: Binary search over commits, batches or inputs to isolate a failureCRC32C checksumshardware-os: The Castagnoli CRC-32 with dedicated instructions on x86 (SSE4.2) and ARMv8. It is the standard fast integrity check for storage blocks, logs and network frames.›fsync, O_DSYNC and O_DIRECThardware-os: What fsync, fdatasync, O_DSYNC, O_DIRECT and F_FULLFSYNC really guarantee on Linux and macOS, and the exact call sequences for crash-safe files.›Consumer offsetsdistributed: Each consumer group stores one integer per partition, the next position to read, so a restarted consumer resumes where it left off with at-least-once delivery.›Incremental sync cursorsdistributed: The client keeps one opaque token; each pull returns only the changes after it plus the next token, so sync cost scales with what changed, not with the dataset.›Message sequence numbersdistributed: A per-stream counter on every message lets the receiver detect loss, duplicates and reordering, ack cheaply and resume after reconnect with "send from N".›+ 1 moreEbpfhardware-os: Verified in-kernel programs on hooks (kprobes, XDP, tc) with mapsPtrace process controlhardware-os: Ptrace: attach, read and write registers and memory, single-step, intercept signalsSeccomp bpfsecurity: Syscall filtering with seccomp BPF programsBFS and DFSgraphs: The two basic graph traversals; BFS gives hop distances and levels, DFS gives discovery/finish order for cycles, components and topological order.›d-ary heapdata-structures: Array heap with d children per node (d = 4 typical): half the binary heap's depth, siblings in one cache line, faster priority queues.›Union-findgraphs: Disjoint-set forest with union by size and path compression; merges sets and answers same-set queries in effectively constant time.›SIMD programminghardware-os: Process 4-16 lanes per instruction with AVX2, AVX-512 or NEON via Rust std::arch, with runtime dispatch and a portable fallback.›Segmented logdistributed: Split an append-only log into files named by their first offset, write only the newest, and find any record by binary search plus a sparse index.›Cursor paginationnetworking: Keyset/opaque-cursor pagination for stable incremental reads from APIs and tables+ 1 moreSparse matrices (CSR)numerics: Compressed sparse row stores only nonzeros as row pointers, column indices and values; SpMV streams them once, so it is memory-bandwidth bound.›

How it is built

Architecture overview

A BI dashboard tool does not store the data it shows. It stores a small model of the data (which tables, which columns, which named measures), a set of saved questions and charts built on that model, and layouts that arrange the charts. When someone opens a dashboard, the tool turns every chart into one query, sends it to a separate warehouse or database, and draws the rows that come back. Three things make this feel interactive on warehouses that take seconds per query: a semantic layer that makes the query a pure function of a chart definition plus filters, a result cache keyed on exactly that query, and a background worker tier that runs slow queries, refreshes caches and sends reports. The product is therefore a thin web application in front of someone else's database; the engineering is in generating safe SQL, not running the same SQL twice, and not letting one user's heavy chart starve everyone.

Open BI projects follow this shape. Superset documents a Flask backend with React frontend, a metadata database, a Redis-style cache that doubles as a message broker, Celery workers and a Celery beat scheduler (Superset architecture). Redash's compose file lists the same roles: server, scheduler, worker, Redis, PostgreSQL (compose.yaml). Metabase and Grafana are described below from their own docs.

Parts:

 browser ──HTTPS──► web tier ──► authz ──► chart spec + filters
   ▲                  │                          │
   │                  │                   semantic layer
   │                  │                   (dataset, measures)
   │                  │                          ▼
   │                  │                   SQL compiler ──► cache key
   │ rows/series      │                          │ miss          │ hit
   └──── shaping ◄────┤                          ▼               │
                      │                  queue ► worker ► pool ► warehouse
                      │                          │   ▲            (rollups,
          metadata DB ◄┘                      result cache ◄───────  views)
    (dashboards, users)                           ▲
                                      scheduler: warm-up, reports, alerts

How the parts fit together

Semantic layer

The semantic layer (semantic-layer, no page yet) is what separates a BI tool from a SQL editor. Redash is the SQL-editor end: the query is the artifact, the tool stores text and results. Superset sits in the middle: its dataset API exposes datasets with their own columns and metrics, so a chart refers to a named metric rather than an expression (Superset datasets API). Metabase syncs the database schema into its own metadata and assigns each column a semantic type, and an admin can edit that metadata (Syncing and scanning). Looker is the model-first end: its semantic modelling language is a product feature (Looker; proprietary).

Why bother: a measure such as "revenue" is defined once, so every chart agrees, and the compiler can add joins and filters mechanically. The contract is that a chart spec (dataset, dimensions, measures, filters, time grain, limit) plus the viewer's identity fully determines the SQL. That determinism is what makes caching correct. Resolving the names in a spec against the model is name resolution in its plain form: scoping, ambiguity, type checks. The compiler's output is relational algebra (select, project, join, group) before it becomes dialect SQL; relational-algebra (no page yet) is the missing block.

Query compiler and executor

The compiler renders SQL in the warehouse's dialect, and the executor runs it. The tool is a client, so it needs connection pooling (connection-pooling, no page yet): warehouses limit concurrent connections, and opening one costs a TLS handshake and a login. It also needs request coalescing (request-coalescing, no page yet): when twenty viewers open the same morning dashboard at 09:00, twenty identical queries should become one running query and twenty waiters. Without it a cache only helps after the first answer lands, and the cold start is the worst moment.

The heavy lifting (scan, filter, group) belongs to the warehouse, which is why column layouts and vectorized operators matter for BI even though the tool itself contains neither: Columnar storage and Vectorized execution explain why a grouped aggregate over one column of a wide table is cheap.

Result cache

Superset's cache section is the most explicit of the four. It names separate caches for dashboard filter state, explore form data, metadata, chart data, SQL Lab results and thumbnails, with Redis recommended and Memcached, S3-compatible storage and a filesystem as other backends (Superset caching). Chart-data timeouts resolve in order chart, dataset, database, global default, and -1 disables caching. A value-size cap skips oversized results. Metabase offers duration, schedule and adaptive policies at question, dashboard and database level; "adaptive" multiplies a query's average execution time by a factor, so expensive queries live longer in the cache (Metabase caching). Grafana's query cache is documented as an Enterprise and Cloud feature with in-memory, Redis and Memcached backends; its key combines data source, query and time range, and time-series ranges are rounded to the panel interval to raise hit rates (Grafana data sources).

The mechanics under these features are eviction (LRU and CLOCK) and invalidation (Cache invalidation). BI caches mostly use time-to-live invalidation because the tool cannot see warehouse writes. The exact alternative is to invalidate on data change, which needs a signal from the warehouse; that is where Change data capture enters. Note the one design choice Superset documents explicitly: a configured backend that becomes unavailable causes failures rather than silent degradation.

Pre-aggregation

When the warehouse is slow, move the work earlier. A rollup (Rollup aggregation) stores sum(amount) per day and region instead of per order, computed with hash-aggregation (no page yet) and organised by Time partitioning so recent days can be rebuilt without touching old ones. A materialised view kept fresh incrementally (incremental-view-maintenance, no page yet) goes further: apply only the delta of changed rows, which the source emits as a change stream (Change data capture). The compiler's job then includes rollup matching: if a chart asks for monthly revenue by region and a daily-by-region rollup exists, rewrite the query to read it.

Scheduler and workers

Slow queries must not hold a web request open. Superset's documentation shows the standard split: Celery workers execute asynchronous SQL Lab queries, report snapshots and emails; beat is the single scheduler that triggers periodic tasks, and running two beats duplicates reports (Superset async queries). Results are stored in a separate results backend and serialised with MessagePack and PyArrow by default. Cache warm-up is itself a scheduled task with strategies such as top-N dashboards, and it needs a persistent cache backend and a schedule at least as frequent as the cache timeout (Superset caching). Redash's compose file has the same separation of scheduler and worker processes.

The primitives: cron-scheduling (no page yet) for "every weekday at 07:00 in the viewer's timezone"; a Durable job queue so a restarted worker does not lose accepted queries; and fair-queuing (no page yet) so one analyst's thousand-query script does not delay the CEO's dashboard. Superset's example configuration rate-limits the SQL Lab task per worker, which is a crude form of the same idea.

Chart data shaping

A line chart over a year of one-second data is 31 million points; a screen has about two thousand pixel columns. Grafana's docs show the standard answer: "max data points" defaults to the panel width, extra points are aggregated server-side if the data source supports it, and the $__interval variable lets queries group by a bucket that grows when the user zooms out (Grafana query options). The page also notes that resizing a panel can change computed values, which is a real pitfall: set a fixed value for stable numbers. When the source cannot aggregate, a shape-preserving downsampler such as lttb-downsampling (no page yet) picks points that keep peaks visible, and an hdr-histogram (no page yet) summarises latency distributions without storing raw samples. Tables use List virtualization so only visible rows enter the DOM.

Access control

Dashboards expose data, so every query runs for someone. The model is typically roles for objects (dashboard, dataset, database) plus filters on rows; see Authorization models for role-, attribute- and relationship-based variants, and Row-level security for enforcing the row filter in the data layer so a mistyped chart cannot bypass it. The cache must include the identity or the row-filter in its key; otherwise user B receives user A's cached rows. Superset's chart cache timeout hierarchy documented above says nothing about identity, so verify this per product. The tool-to-warehouse link is credential-based in most deployments; where the warehouse supports it, Mutual TLS authenticates the tool itself.

Metadata store

Everything the user authored lives in the metadata database: Superset recommends PostgreSQL or MySQL, standalone for production, and says workers and web servers must share it (architecture). It is small and precious, so it gets the full durability stack: Write-ahead log, Primary-backup replication (with Leases and Health checking for failover), Point-in-time recovery built on ARIES recovery and base backups in Object storage. Losing the cache is an inconvenience; losing dashboards is not.

Operations and verification

Web and worker processes run under Process supervision and drain in-flight requests on deploy (Graceful draining). The SQL compiler is the part worth fuzzing: it builds SQL from user-controlled strings (column names, filters, custom expressions), so Coverage-guided fuzzing with a dialect parser as oracle finds injection and quoting bugs. Deterministic simulation testing fits the scheduler and cache invalidation logic, which are order-sensitive and hard to reproduce.

Data and control flow

One dashboard view (cold cache).

  1. The browser requests the dashboard; the web tier loads layout and chart specs from the metadata store (small reads, milliseconds).
  2. Authorization checks the viewer against the dashboard and each dataset.
  3. Each chart spec plus filters and viewer-derived row filters is compiled to SQL; the SQL text (or the spec) hashed with the identity forms the cache key.
  4. A cache miss registers the key with request coalescing; the first caller submits the query to a worker queue, the rest wait on it.
  5. A worker takes a pooled warehouse connection, runs the query, applies the row cap and stores the result under the key with a timeout. Time here is the warehouse's, order of seconds on a large scan.
  6. The web tier shapes the rows (bucketing, limits) and returns them; the browser draws. Charts render independently, so the slowest chart does not block the others.

Warm view. Steps 1-3 as above; the key hits; shaping and return. This is the path caching exists for. Cache warm-up (step 5 run ahead of time by beat) moves the cold view out of business hours for the most-visited dashboards.

Scheduled report. Beat fires at the cron time; a worker renders the dashboard or runs its queries as the report owner, stores a snapshot, and sends email or chat. The worker needs the same code and configuration as the web server (Superset states this explicitly).

Scaling

  1. Warehouse cost and latency limit first. Levers in order: cache with sensible TTLs; coalesce identical queries; push work into rollups; then buy warehouse capacity.
  2. Concurrency on the warehouse. Limit the pool per datasource and queue the rest; apply per-user or per-dashboard fairness.
  3. Cache memory. Cap value size, use an eviction policy suited to scans (frequency-aware policies resist one-off large results), and consider tiering to object storage for big results.
  4. Worker throughput. Add workers; keep one scheduler; give long and short queries separate queues so short ones are not stuck behind long ones.
  5. Web tier. Stateless apart from the metadata store and cache; add instances behind a load balancer.
  6. Metadata store. Rarely first, but a replica handles read-heavy dashboard loads.
  7. Browser. Cap points and rows; virtualise tables.

Failure modes

FailureSymptomCauseFix
Stale numbersDashboard disagrees with the sourceTTL longer than data freshness, or warm-up laggingShorten TTL on volatile data; invalidate from change events; show "as of" time
Cache stampedeWarehouse spikes at 09:00, timeoutsMany identical misses at onceRequest coalescing, pre-warming, jittered expiry
Cross-user data leakA user sees another's rowsCache key lacks identity or row filterInclude identity/filter in key; enforce row policies in the data layer
Duplicate reportsReport emailed twiceTwo scheduler instancesRun exactly one beat, or guard with a lease
Cache outage cascadesAll charts errorBackend configured but down (Superset documents failure, not degradation)Health-checked cache, fail-open policy chosen consciously
Resize changes numbersSame panel shows different totalsMax data points tied to pixel width (Grafana docs)Fix interval or max data points per panel
Wide scan from one chartWarehouse bill and queue delayMissing time filter, unbounded limitDefault time range, row cap, query timeout, per-user queue
Worker mismatchTasks fail after upgradeWeb and workers on different config or versionDeploy together, drain old workers
Lost dashboardsAuthored content missingMetadata DB without PITRWAL archiving, base backups, restore drills

Real implementations

namewhat it isrepolicencenotes
Apache SupersetDashboards, SQL Lab, dataset-level metricsapache/supersetApache-2.0 (LICENSE)Flask, React, Celery, Redis; documented caches and async tier
MetabaseQuestion builder, models, dashboardsmetabase/metabaseAGPL, with a commercial licence for the enterprise directory (LICENSE)Sync, scan and fingerprint of schema; caching policies
GrafanaDashboards for time-series and many data sourcesgrafana/grafanaAGPL-3.0 (LICENSE)Queries pushed to data-source plugins; query cache is Enterprise/Cloud
RedashSQL-first query, visualisation, alertsgetredash/redashBSD-style (LICENSE)Server, scheduler, worker, Redis, PostgreSQL
LookerModel-first BIcloud.google.com/lookerproprietary

Sources

Similar systems

Share the most building blocks with this one.