For the complete documentation index, see llms.txt. This page is also available as Markdown.

Controller

Most of the properties in Pinot are set in Zookeeper via Helix. However, you can also set properties in controller.conf file. You can specify the path to configuration file at the startup time as follows:

bin/pinot-admin.sh StartController -configFileName /path/to/controller.conf

Controller.conf can have the following properties.

Primary configuration

Property
Default
Description

controller.vip.host

same as controller.host

The VIP hostname used to set the download URL for segments

controller.vip.port

same as controller.port

controller.vip.protocol

controller.host

localhost

The ip of the host on which controller is running

controller.port

9000

The port on which controller should run

controller.access.protocol

controller.data.dir

${java.io.tmpdir}/PinotController

Directory to host segment data

controller.local.temp.dir

controller.zk.str

localhost:2181

zookeeper host:port string to connect

controller.update_segment_state_model

false

controller.helix.cluster.name

Pinot Cluster Name, required.

cluster.tenant.isolation.enable

true

Enable Tenant Isolation, default is single tenant cluster. If enabled, each server or broker added into the cluster will be tagged with DefaultTenant.

enforce.pool.based.assignment

false

When true, the controller validates table configs to require both pool-based instance assignment and replica-group-based assignment in instanceAssignmentConfigMap. Dimension tables and tables that reuse pre-existing instancePartitionsMap assignments are excluded from this check.

controller.enable.split.commit

false

(Deprecated) Enable split commit protocol for real-time segment commit.

controller.query.console.useHttps

false

use https instead of http for cluster

controller.upload.onlineToOfflineTimeout

2 minutes

controller.mode

dual

Should be one of helix_only, pinot_only or dual

controller.resource.rebalance.strategy

org.apache.helix.controller. rebalancer.strategy.AutoRebalanceStrategy

controller.resource.rebalance.delay_ms

5 minutes

How long the helix waits to rebalance partitions after a controller is lost. Longer time values allow for more time for a controller to recover. Shorter time values prevent cluster operations like segment sealing from being blocked.

controller.realtime.segment.commit.timeoutSeconds

120 seconds

request timeout for segment commit

controller.executor.numThreads

not set (-1)

Size of the controller async executor used for background controller work such as multiget helpers. If unset or set to 0/negative, Pinot uses a cached thread pool. If set to a positive value, Pinot uses a fixed-size thread pool.

controller.executor.rebalance.numThreads

not set (-1)

Size of the dedicated controller executor used for table and tenant rebalance work. If unset or set to 0/negative, Pinot uses a cached thread pool. If set to a positive value, Pinot uses a fixed-size thread pool.

controller.deleted.segments.retentionInDays

7 days

duration for which to retain deleted segments

controller.ingestFromURI.allowLocalFileSystem

false

When true, the /ingestFromURI controller API may read controller-local files through file:///... URIs or LocalPinotFS. Leave this false unless you explicitly trust controller-local ingestion inputs.

controller.lineage.exclusive.delete.enabled

true

When true, Pinot keeps segments that are still locked by a live lineage entry on the lineage-managed cleanup path instead of deleting them through the generic segment delete flow. Set to false to restore the legacy delete behavior.

controller.admin.access.control.factory.class

org.apache.pinot.controller. api.access.AllowAllAccessFactory

controller.segment.upload.timeoutInMillis

10 minutes

timeout for upload of segments.

controller.startup.continueWithoutDeepStore

false

When true, the controller continues startup even if Pinot fails to validate or create controller.data.dir through PinotFS during boot. When false, the controller fails fast on that startup check.

controller.startup.exitOnTableConfigCheckFailure

true

When true, the controller exits during startup if any table is missing its TableConfig. When false, the controller stays up and reports the missing-table-config count via tableWithoutTableConfigCount.

controller.startup.exitOnSchemaCheckFailure

true

When true, the controller exits during startup if any table is missing its Schema. When false, the controller stays up and reports the missing-schema count via tableWithoutSchemaCount.

controller.realtime.segment.metadata.commit.numLocks

64

controller.enable.storage.quota.check

true

controller.storage.factory.class.file

org.apache.pinot.spi. filesystem.LocalPinotFS

table.minReplicas

1

controller.access.protocols

http

Ingress protocols to access controller (http or https or http,https)

controller.access.protocols.http.port

Port to access controller via http

controller.broker.protocols.https.port

Port to access controller via https

controller.broker.protocol

http

protocol for forwarding query requests (http or https)

controller.broker.port.override

override for broker port when forwarding query requests (use in multi-ingress scenarios)

controller.tls.keystore.path

Path to controller TLS keystore

controller.tls.keystore.password

keystore password

controller.tls.truststore.path

Path to controller TLS truststore

controller.tls.truststore.password

truststore password

controller.tls.client.auth

false

toggle for requiring TLS client auth

pinot.controller.http.server.thread.pool.corePoolSize

2 * cores

Config for the thread-pool used by pinot-controller's http-server.

pinot.controller.http.server.thread.pool.maxPoolSize

2 * cores

Config for the thread-pool used by pinot-controller's http-server.

pinot.controller.http.server.max.http.header.size

unset (Grizzly default)

Maximum total HTTP header size in bytes accepted by the controller's Grizzly HTTP/HTTPS listeners. Set this when upstream proxies, auth gateways, or clients send larger headers than the Grizzly default allows.

pinot.controller.http.server.max.request.headers

unset (Grizzly default)

Maximum number of HTTP headers accepted by the controller's Grizzly HTTP/HTTPS listeners.

pinot.controller.segment.fetcher.http.client.maxConnTotal

Config for the http-client used by HttpSegmentFetcher for downloading segments

pinot.controller.segment.fetcher.http.client.maxConnPerRoute

Config for the http-client used by HttpSegmentFetcher for downloading segments

If you temporarily disable either startup check to keep the controller running while you repair legacy tables, watch the controller gauges tableWithoutTableConfigCount and tableWithoutSchemaCount to confirm the invalid-table count returns to zero.

Pinot does not support enabling Helix batch message mode through controller.conf. Controllers now disable batch message mode on controller-managed IdealStates when those resources are created or updated, so any legacy controller.enable.batch.message.mode setting has no effect.

Periodic task configuration

The following controller periodic tasks can be tuned independently.

When a task documents both frequencyPeriod and cronExpression, Pinot uses the Quartz cronExpression if it is set and falls back to the fixed-delay frequencyPeriod otherwise. Invalid cron expressions fail controller startup during periodic-task scheduler initialization. Tasks without a cronExpression entry remain fixed-delay only.

Cron expression examples

Controller periodic-task cron schedules use Quartz syntax, with seconds as the first field: second minute hour day-of-month month day-of-week [year]. Use ? in either the day-of-month or day-of-week field when that field does not constrain the schedule. Pinot evaluates the schedule in the controller JVM's time zone, so keep controller time zones consistent when using wall-clock schedules.

Schedule
Quartz cron expression

Every 5 minutes

0 0/5 * * * ?

Every hour

0 0 * * * ?

Every day at 02:30

0 30 2 * * ?

Every Sunday at 03:00

0 0 3 ? * SUN

Weekdays at 01:15

0 15 1 ? * MON-FRI

Add the cron expression to controller.conf under the task-specific key:

Do not include quote characters in a Java properties controller.conf value. If the same config is rendered through YAML or another format where spaces are significant, quote the whole cron string in that outer format only. To return a task to fixed-delay scheduling, remove or clear its *.cronExpression value and set the corresponding *.frequencyPeriod.

BrokerResourceValidationManager

This task rebuilds the BrokerResource if the instance set has changed.

Config
Default Value

controller.broker.resource.validation.frequencyPeriod

1h

controller.broker.resource.validation.cronExpression

unset

controller.broker.resource.validation.initialDelayInSeconds

between 2m-5m

ResponseStoreCleaner

This task removes expired cursor response-store entries from brokers. Cursor expiration itself is controlled by the broker setting pinot.broker.cursor.response.store.expiration.

Config
Default Value

controller.cluster.response.store.cleaner.frequencyPeriod

1h

controller.cluster.response.store.cleaner.initialDelay

between 2m-5m

StaleInstancesCleanupTask

This task periodically cleans up stale Pinot broker/server/minion instances. It is disabled by default.

Config
Default Value

controller.stale.instances.cleanup.task.frequencyPeriod

-1s

controller.stale.instances.cleanup.task.cronExpression

unset

controller.stale.instances.cleanup.task.initialDelaySeconds

between 2m-5m

controller.stale.instances.cleanup.task.minOfflineTimeBeforeDeletionPeriod

1h

OfflineSegmentIntervalChecker

This legacy interval controls how often OfflineSegmentValidationManager runs expensive segment-level validation, including missing-segment and offline-push-delay metrics. It does not have its own cron expression; use controller.offline.segment.validation.cronExpression to cron-schedule the offline validation task.

Config
Default Value

controller.offline.segment.interval.checker.frequencyPeriod

24h

controller.statuschecker.waitForPushTimePeriod

10m

controller.offlineSegmentIntervalChecker.initialDelayInSeconds

between 2m-5m

OfflineSegmentValidationManager

This task validates offline tables and updates offline segment validation metrics. Segment-level validation is throttled by controller.segment.level.validation.intervalPeriod; if controller.offline.segment.interval.checker.frequencyPeriod is also configured, Pinot uses the lower of the two intervals for segment-level validation.

Config
Default Value

controller.offline.segment.validation.frequencyPeriod

1h

controller.offline.segment.validation.cronExpression

unset

controller.segment.level.validation.intervalPeriod

24h

PinotTaskManager

This task schedules and manages Pinot minion tasks. It periodically generates tasks for each table based on the task configurations defined in the table config. Common minion tasks include MergeRollupTask, RealtimeToOfflineSegmentsTask, SegmentGenerationAndPushTask, and ConvertToRawIndexTask.

Config
Default Value

controller.task.frequencyPeriod

1h

controller.task.manager.initialDelayInSeconds

between 2m-5m

controller.task.scheduler.enabled

false

controller.task.enableDistributedLocking

false

controller.task.concurrentSchedulingEnabled

false

controller.task.scheduler.enabled enables cron-based task schedules from table configs.

controller.task.enableDistributedLocking enables the ZooKeeper-backed lock that PinotTaskManager uses to coordinate task generation for the same table across controllers.

controller.task.concurrentSchedulingEnabled changes the cluster default for task scheduling from the legacy controller-wide serialized path to a concurrent path. When enabled, task generation for different tables can run in parallel, while same-table coordination relies on distributed locking. Enable controller.task.enableDistributedLocking before enabling concurrent scheduling.

RealtimeSegmentValidationManager

This task validates the ideal state and segment zk metadata of real-time tables by doing the following:

  • fixing any partitions which have stopped consuming

  • starting consumption from new partitions

  • uploading segments to deep store if segment download url is missing

This task ensures that the consumption of the real-time tables gets fixed and keeps going when met with erroneous conditions.

Config
Default Value

controller.realtime.segment.validation.frequencyPeriod

1h

controller.realtime.segment.validation.cronExpression

unset

controller.realtime.segment.validation.initialDelayInSeconds

between 2m-5m

controller.realtime.segment.deepStoreUploadRetryEnabled

false

controller.realtime.segment.deepStoreUploadRetry.timeoutMs

-1

controller.realtime.segment.deepStoreUploadRetry.parallelism

1

controller.segment.error.autoReset

false

controller.realtime.segment.partialOfflineReplicaRepairEnabled

false

controller.segment.disaster.recovery.mode

DEFAULT

controller.segment.error.autoReset controls whether the controller's periodic offline and realtime segment validation tasks automatically reset segments in ERROR state so they can retry normal recovery. Pinot leaves this disabled by default.

When controller.realtime.segment.partialOfflineReplicaRepairEnabled is enabled, the controller's periodic validation task automatically resets OFFLINE replicas back to CONSUMING for IN_PROGRESS segments that have a mix of CONSUMING and OFFLINE replicas. This handles cases where a replica's startup fails (for example, due to Kafka consumer initialization errors) while other replicas continue normally. Enable only after verifying that OFFLINE replicas are caused by transient failures rather than persistent errors.

controller.segment.disaster.recovery.mode sets the cluster-wide default disaster-recovery policy used by the controller's realtime segment validation task for pauseless ingestion. Supported values are DEFAULT and ALWAYS, matching the table-level disasterRecoveryMode setting in streamIngestionConfig. You can set this in controller.conf, or update the same key through cluster configs so the controller picks up the new mode without restart.

RealtimeOffsetAutoResetManager

This task runs offset-auto-reset backfill work for real-time tables when realtime segment offset auto reset is enabled in the table ingestion config.

Config
Default Value

controller.realtime.offsetAutoReset.backfill.enabled

false

controller.realtime.offsetAutoReset.backfill.frequencyPeriod

1h

controller.realtime.offsetAutoReset.backfill.cronExpression

unset

controller.realtime.offsetAutoReset.backfill.initialDelayInSeconds

between 2m-5m

RealtimeConsumerMonitor

This task fetches consuming-segment information for real-time tables and emits per-partition records-lag and availability-lag controller gauges. It is disabled by default.

Config
Default Value

controller.realtimeConsumerMonitor.frequencyPeriod

-1s

controller.realtimeConsumerMonitor.cronExpression

unset

controller.realtimeConsumerMonitor.initialDelayInSeconds

between 2m-5m

RetentionManager

This task manages retention of segments for all tables. During the run, it looks at the retentionTimeUnit and retentionTimeValue inside the segmentsConfig of every table, and deletes segments which are older than the retention. The deleted segments are moved to a DeletedSegments folder colocated with the dataDir on segment store, and permanently deleted from that folder in a configurable number of days.

Config
Default Value
Description

controller.retention.frequencyPeriod

6h

Frequency at which the retention manager runs

controller.retention.cronExpression

unset

Quartz cron schedule for the retention manager. When set, Pinot ignores controller.retention.frequencyPeriod.

controller.retentionManager.initialDelayInSeconds

between 2m-5m

Randomized initial delay before first retention manager run

controller.retentionManager.enableCreationTimeFallback

false

If true, use segment creation time as fallback when end time is invalid/missing, enabling cleanup of such segments; dynamic config, no restart needed

controller.deleted.segments.retentionInDays

7d

Duration for which to retain deleted segments

controller.enable.hybrid.table.retention.strategy

false

If true, use hybrid retention strategy for hybrid tables

If controller.enable.hybrid.table.retention.strategy is set to true, the retention manager will use the hybrid retention strategy. In this strategy, the retention manager calculates a time boundary by looking at the maximum end time of offline segments and the segment ingestion frequency specified for the OFFLINE table. Segments older than the time boundary are deleted from the REALTIME table. The time boundary calculation is as mentioned in the Time Boundary section. This type of strategy is useful to prevent data loss when there are failures in moving the data from REALTIME table to OFFLINE table.

When the offline part of the hybrid table is unused or not-required, it's recommended to delete the OFFLINE table. Otherwise, the REALTIME table will keep growing and the retention manager will not be able to delete the segments.

SegmentRelocator

This task is applicable only if you have tierConfig or tagOverrideConfig. It runs rebalance in the background to

  1. relocate COMPLETED segments to tag overrides

  2. relocate ONLINE segments to tiers if tier configs are set

At most one replica is allowed to be unavailable during rebalance unless you override the periodic rebalance defaults below.

Config
Default Value
Description

controller.segment.relocator.frequencyPeriod

1h

How often the segment relocator scans tables and triggers relocation work.

controller.segment.relocator.cronExpression

unset

Quartz cron schedule for the segment relocator. When set, Pinot ignores controller.segment.relocator.frequencyPeriod.

controller.segmentRelocator.initialDelayInSeconds

between 2m-5m

Randomized startup delay before the first segment relocator run.

controller.segment.relocator.bestEfforts

true

Whether the periodic rebalance should continue in best-effort mode if the no-downtime contract cannot be fully achieved.

controller.segment.relocator.minAvailableReplicas

-1

Minimum replicas to keep available during no-downtime rebalance. Negative values mean the maximum number of replicas that may be unavailable.

controller.segment.relocator.reassignInstances

false

Whether the periodic rebalance should recompute instance assignment before rebalancing segments.

controller.segment.relocator.bootstrap

false

Whether the periodic rebalance should bootstrap newly added servers during relocation.

controller.segment.relocator.downtime

false

Whether the periodic rebalance is allowed to use downtime mode instead of enforcing no-downtime movement.

SegmentStatusChecker

This task manages segment status metrics such as realtimeTableCount, offlineTableCount, disableTableCount, numberOfReplicas, percentOfReplicas, percentOfSegments, idealStateZnodeSize, idealStateZnodeByteSize, segmentCount, segmentsInErrorState, tableCompressedSize.

It also emits the per-table TABLE_TENANT_INFO gauge for tenant attribution. Pinot registers one gauge per (tenantType, tenant) pair and sets each value to 1: server tenant, broker tenant, and each tier server tenant derived from the table's tier configs. With the bundled controller JMX exporter config, Prometheus exposes these gauges with table, tableType, tenantType, and tenant labels so you can join tenant ownership onto other table-scoped metrics.

Config
Default Value

controller.statuschecker.frequencyPeriod

5m

controller.statuschecker.cronExpression

unset

controller.statusChecker.initialDelayInSeconds

between 2m-5m

RebalanceChecker

Currently, table rebalance triggered by user runs at best effort. It could fail if the controller running it got restarted; or some servers were not stable, making the rebalance timed out while waiting for external view to converge with ideal state, etc. This task checks for failed rebalance and retry them automatically, up to certain times as configured.

Config
Default Value

controller.rebalance.checker.frequencyPeriod

5m

controller.rebalance.checker.cronExpression

unset

controller.rebalanceChecker.initialDelayInSeconds

between 2m-5m

TenantRebalanceChecker

This task checks tenant rebalance jobs that may be stuck after a controller crash or restart and resumes unfinished table-rebalance work.

Config
Default Value

controller.tenant.rebalance.checker.frequencyPeriod

5m

controller.tenant.rebalance.checker.cronExpression

unset

controller.tenant.rebalance.checker.initialDelayInSeconds

between 2m-5m

TaskMetricsEmitter

This task periodically emits controller metrics about minion tasks, including task counts by state. It also publishes the per-table, per-task-type gauges MAX_SUBTASK_WAIT_TIME_MS and MAX_SUBTASK_RUNNING_TIME_MS. Pinot rewrites both gauges every emit cycle and sets them to 0 when no matching subtasks are in WAITING or RUNNING, so alerts based on these gauges self-resolve after the queue drains.

Config
Default Value

controller.minion.task.metrics.emitter.frequencyPeriod

5m

controller.minion.task.metrics.emitter.cronExpression

unset

ResourceUtilizationChecker

The periodic task ResourceUtilizationChecker runs periodically and fetches disk-usage information from Pinot server instances via GET /instance/diskUtilization.

Config
Default Value
Description

controller.enable.resource.utilization.check

false

Master switch for enforcing resource-utilization checks during real-time ingestion validation and minion task generation.

controller.enable.all.resource.utilization.checkers

true

Registers all resource-utilization checkers for backward compatibility.

controller.enable.disk.utilization.checker

false

Registers the disk-utilization checker when controller.enable.all.resource.utilization.checkers is false.

controller.resource.utilization.checker.frequency

300

Value is in seconds. Setting the value to -1 disables the periodic checker task.

controller.resource.utilization.checker.initial.delay

300 (or 0 when collect.usage.at.startup is true)

Initial delay for the resource-utilization checker in seconds. Automatically set to 0 when controller.resource.utilization.checker.collect.usage.at.startup is enabled.

controller.resource.utilization.checker.collect.usage.at.startup

false

When set to true, the controller waits for the resource utilization checker (disk usage cache) to be populated before marking itself as healthy. This prevents segment push requests from being accepted when disk usage is already high (e.g., 90%) immediately after a restart. When enabled, controller.resource.utilization.checker.initial.delay is automatically set to 0 so the checker runs immediately. If the checker times out, the controller still becomes healthy (fail-open).

controller.disk.utilization.threshold

0.95

Disk-usage threshold expressed as a fraction between 0 and 1.

controller.disk.utilization.check.timeoutMs

30000

Timeout in milliseconds for collecting disk-usage responses from servers.

controller.disk.utilization.path

/home/pinot/data

Compatibility config sent by the controller when requesting disk usage. The current server endpoint ignores this value and always measures the server instanceDataDir.

Last updated

Was this helpful?