Minn Fong
04/23/2026, 10:09 PMCapaticy limit exceeded: No available stream load pipe .
starrocks_be_tablet_cumulative_max_compaction_score has been 0 ever since cluster been brought up.
For reference. here are my cluster stats:
• 1 leader FE node (currently disabled the other 2 follower/observer)
• 4 BE nodes (r6in.4xlarge machines)
• 4 EBS per BE node. Each EBS has 750GiB, 500 MiB/s throughput and 5000 iops (unlikely issue)
How can I troubleshoot this?Rocky
04/23/2026, 10:09 PMstarrocks_be_tablet_update_max_compaction_score. This tracks the compaction status of Primary Key tables. If this value is high (e.g., > 100), it indicates that compaction is falling behind.
2. "Capacity limit exceeded: No available stream load pipe"
This error occurs in the FE when the internal pool of "pipes" used to track Stream Load tasks is exhausted.
* The Cause: StarRocks FE has a default limit on concurrent stream load tasks (often 1000). Since your transaction publish latency is very high (~35s), each Stream Load connection stays "active" in the FE's memory for a long time. If you are sending frequent small loads, you will quickly hit this concurrency limit because old tasks aren't finishing fast enough to free up "pipes" for new ones.
* Relevant FE Config: max_running_txn_num_per_db (default 1000) and stream_load_task_keep_max_num (default 1000).
3. High Transaction Publish Latency (35s)
For PK tables, the "Publish" phase involves applying rowsets to the Primary Key index and generating delete vectors. A 35s latency is extremely high and usually means:
* Too many small versions: You are loading data too frequently in small batches.
* Compaction is not keeping up: The BE cannot merge these small versions fast enough.
* Worker saturation: The threads responsible for applying updates are busy.
──────────
Troubleshooting & Tuning Steps
Step 1: Verify Compaction Status
Run the following SQL commands to see if compaction tasks are actually running or stuck:
sql
-- Check if any compaction tasks are currently running or failing
SHOW PROC '/compactions';
-- Check the version count and compaction score for your partitions
-- Look for "MaxCS" (Compaction Score) and "VisibleVersion"
SHOW PARTITIONS FROM <your_table_name>;
Step 2: Increase Compaction Concurrency (BE side)
Since you have powerful r6in.4xlarge nodes (16 vCPUs) and multiple EBS volumes, you should increase the resources dedicated to PK compaction in your `be.conf`:
properties
# Increase threads for PK compaction (default is 1)
# Since you have 4 disks, setting this to 2 or 4 can help significantly.
update_compaction_num_threads_per_disk = 2
# Decrease the interval between compaction triggers (default 120s)
update_compaction_per_tablet_min_interval_seconds = 60
_Note: You can apply these dynamically via curl -XPOST <http://be_host:be_http_port/api/update_config?update_compaction_num_threads_per_disk=2._>
Step 3: Optimize Ingestion Strategy
* Batching: This is the most critical fix. Instead of many small Stream Loads, aggregate your data and send larger batches (e.g., every 10-30 seconds or every 100MB+). This reduces the number of "versions" created and drastically lowers the overhead on the PK index.
* Persistent Index: Since you are on EBS (even with 5000 IOPS), ensure enable_persistent_index is set to true in your table properties (it is the default in recent versions). This prevents high memory usage during upserts.
Step 4: Increase FE Limits (Optional)
If you must maintain high concurrency, you can increase the FE's capacity to handle more concurrent transactions:
```sql
-- On Leader FE
ADMIN SET FRONTEND CONFIG ("max_running_txn_num_per_db" = "2000");Rocky
04/23/2026, 10:09 PMstarrocks_be_tablet_update_max_compaction_score metric. If it's high, increase update_compaction_num_threads_per_disk and, most importantly, increase your loading batch size to reduce the transaction pressure.
References
• administration/management/FE_configuration.mdMinn Fong
04/23/2026, 10:23 PMRocky
04/23/2026, 10:25 PMstarrocks_be_tablet_cumulative_max_compaction_score is only for Duplicate/Aggregate/Unique tables. For Primary Key (PK) tables, you must monitor starrocks_be_tablet_update_max_compaction_score.
* Capacity Limit / No Pipe: This error occurs because your transaction publish latency is 35 seconds. Every Stream Load (even with merge/group commit) occupies a "pipe" (an internal FE tracking object). Because transactions are taking 35s to finish, these pipes are not being released fast enough, and the FE's internal pool (stream_load_task_keep_max_num, default 1000) is filling up.
* Merge Commit (Group Commit) at 50MB: Group commit is designed to help with tiny frequent loads (e.g., 1KB to 1MB). At 50MB, you are already sending a substantial amount of data. If you send 50MB every 2 seconds, you are creating 30 versions per minute. For PK tables, each version requires a CPU-intensive "apply" phase to update the index and delete vectors.
2. Should you increase payload to 500 MB?
Yes, absolutely. This is the single most effective change you can make.
* By increasing from 50MB to 500MB, you reduce the number of versions created by 10x.
* This drastically reduces the "Compaction Score" because there are fewer rowsets to merge.
* It lowers the overhead on the Primary Key index apply phase, which will bring that 35s latency down to 1–2 seconds.
3. Tuning Steps to Clear the Backlog
Since your nodes have 16 vCPUs and 4 EBS volumes, you are currently under-utilizing your hardware for compaction. Apply these settings to help the cluster "catch up" from the 2,000 score:
A. Increase Compaction Concurrency (BE Config)
Add or update these in be.conf (can be applied dynamically via curl):
properties
# Increase threads for PK compaction (default is 1).
# With 4 disks and 16 cores, set this to 2 or 4.
update_compaction_num_threads_per_disk = 2
# Increase the threads that "apply" the rowsets (the cause of your 35s latency)
# 0 means it equals the number of CPU cores. Ensure it's not restricted.
transaction_apply_worker_count = 0
B. Increase FE Transaction Limits
To stop the "Capacity limit exceeded" error while you are clearing the backlog, increase these in `fe.conf`:
properties
# Increase the pool of tracked stream load tasks
stream_load_task_keep_max_num = 2000
# Increase concurrent transactions per database
max_running_txn_num_per_db = 2000
C. Verify Progress
Use this SQL to see if the tablets are actually compacting:
sql
-- Check the MaxCS (Compaction Score) column. It should start dropping from 2000.
SHOW PARTITIONS FROM <your_table_name>;
-- Check the status of current compaction tasks
SHOW PROC '/compactions';
Summary Recommendation
1. Switch to 500MB batches. At this size, you might not even need "merge commit" (group commit); a standard Stream Load will be more stable.
2. Increase update_compaction_num_threads_per_disk to 2.
3. Monitor starrocks_be_tablet_update_max_compaction_score instead of the cumulative score. If it stays above 100, you are still loading too frequently.
References
• administration/management/FE_configuration.md
• faq/loading/Loading_faq.md
• loading/loading_introduction/loading_considerations.md
• loading/Stream_Load_transaction_interface.mdMinn Fong
04/23/2026, 11:08 PMRocky
04/23/2026, 11:09 PM2000ms interval is likely too aggressive for this volume.
1. Interval is too short: 2 seconds is still very frequent for a PK table under high load.
2. Backpressure: Because your publish latency is 35s, the Merge Commit "coordinator" in the FE is likely holding onto thousands of "pipes" waiting for previous 2-second windows to finish publishing. This is causing your Capacity limit exceeded error.
──────────
Recommended Strategy to Stabilize
1. Scale up the "Apply" and "Compaction" Workers
Since your r6in.4xlarge nodes have 16 vCPUs and high-performance EBS, you can afford to let StarRocks work harder on the background tasks:
properties
# be.conf
# Increase threads for applying rowsets to the PK index
# Default is usually number of cores; ensure it's not being limited.
transaction_apply_worker_count = 16
# Allow more concurrent PK compactions
update_compaction_num_threads_per_disk = 4
# Increase the buffer before flushing to disk during a load
# This helps keep the number of files per version low
write_buffer_size = 536870912 # 512MB
2. Adjust Loading Configuration
If you continue using Merge Commit, increase the interval to give the system breathing room:
* Merge Commit Interval: Set to 10000 (10 seconds).
* Client-side Batching: If possible, buffer at the application level to 1GB+ before calling the Stream Load API. This is more reliable than relying on the FE to merge hundreds of 50MB chunks.
3. Clear the Backlog (Critical)
Your cluster is currently "stuck" at the 2,000 score limit. Even if you change your code now, the BEs are struggling to compact the thousands of versions already there.
1. Stop ingestion entirely for 5-10 minutes.
2. Monitor the score: SHOW PARTITIONS FROM <table_name>; (Look at MaxCS).
3. Once the score drops below 100, resume ingestion with the 1GB+ batch size.
Summary
* 50MB is "tiny" for a 50k events/s stream on a PK table.
* Target 1GB–3GB per batch.
* Monitor starrocks_be_tablet_update_max_compaction_score, not the cumulative score.
* Increase transaction_apply_worker_count to 16 to utilize your vCPUs for faster rowset processing.
References
• faq/loading/Loading_faq.md
• best_practices/primarykey_table.md
• loading/Flink-connector-starrocks.md
• table_design/table_types/primary_key_table.mdMinn Fong
04/23/2026, 11:14 PMRocky
04/23/2026, 11:14 PMmerge_commit_async: true is exactly what you need to "offload" the work from your event producer.
* Synchronous (Default): The Stream Load client waits for the data to be received, written to disk, and published (the apply phase). With your current 35s latency, your client would hang for 35s.
* Asynchronous: The server returns a success response as soon as it has safely received the data and written it to the Write-Ahead Log (WAL) or temporary storage. The client can then immediately grab the next batch of events.
* Risk: In async mode, the client receives a "Success" before the data is actually visible in queries. If the transaction fails during the "Apply" phase later (e.g., due to a disk error or schema issue), the client won't know from the immediate response.
3. The 10-Second Interval
A 10-second merge_commit_interval_ms (10000) is very safe for your volume.
* At 50k events/s (~625 MB/s), a 10s window will result in a ~6GB transaction.
* StarRocks can easily handle 6GB transactions (the default limit is 10GB).
* This will keep your version count extremely low, which is the key to bringing that 2,000 compaction score down.
Final Checklist for Initial Testing
Setting | Recommended Value | Why?
Batch Size | 1GB - 2GB | Significant reduction in PK index overhead.
merge_commit_async | true | Unblocks your event producer immediately.
merge_commit_interval_ms | 10000 | Reduces transaction frequency to ~6 per minute.
transaction_apply_worker_count | 16 | (BE) Matches your r6in.4xlarge CPU count to speed up the apply phase.
update_compaction_num_threads_per_disk | 2 or 4 | (BE) Effectively utilizes your 4 EBS volumes to clear the 2k score backlog.
⚠️ One Critical Step Before Testing
Because your cluster is currently at a 2,000 compaction score, it is likely in a "safety-throttle" mode where it may reject even the new 1GB loads.
1. Stop all ingestion for 10 minutes.
2. Watch the score drop via SHOW PARTITIONS FROM your_table; (look for MaxCS).
3. Once MaxCS is below 500, start your new 1GB + Merge Commit Async pipeline.
If you start the new pipeline while the score is still 2,000, the background compaction might not have enough resources to "catch up" while still processing new 625 MB/s of new data. Give it a clean slate to start.
References
• faq/loading/Stream_load_faq.md
• administration/management/monitoring/metrics.md
• loading/StreamLoad.md
• faq/loading/Routine_load_faq.md
• loading/Stream_Load_transaction_interface.mdMinn Fong
04/24/2026, 12:38 PMPartitionId,PartitionName,VisibleVersion,VisibleVersionTime,VisibleVersionHash,State,PartitionKey,Range,DistributionKey,Buckets,ReplicationNum,StorageMedium,CooldownTime,LastConsistencyCheckTime,DataSize,StorageSize,IsInMemory,RowCount,DataVersion,VersionEpoch,VersionTxnType,TabletBalanced
@Rocky There's no MaxCS score in SHOW partitions from your_table queryRocky
04/24/2026, 12:39 PMSHOW PARTITIONS command does not include the MaxCS column. To view the compaction scores for your table, you should use one of the following two methods:
Method 1: Using the SHOW PROC command (Most Common)
This is the internal StarRocks process view. Replace <db_name> and <table_name> with your actual names:
sql
-- This will show AvgCS, P50CS, and MaxCS columns at the far right
SHOW PROC '/DBS/<db_name>/<table_name>/partitions';
Method 2: Querying information_schema (Easiest to read)
If you are on version 3.1.9+ or 3.2.4+, StarRocks provides a system table that is much easier to filter:
sql
SELECT
TABLE_NAME,
PARTITION_NAME,
VISIBLE_VERSION,
MAX_CS
FROM information_schema.partitions_meta
WHERE TABLE_NAME = 'your_table_name'
ORDER BY MAX_CS DESC;
Why you are looking for MaxCS
* The 2,000 Threshold: In Primary Key tables, when the MaxCS (which reflects the number of un-compacted rowsets/versions) hits 2,000, the table effectively enters a "read-only" state for new writes to prevent the system from falling over.
* Apply Latency: If you see MaxCS climbing while your VisibleVersionTime is lagging, it means the BEs are struggling to "Apply" the data to the Primary Key index.
Verification of your proposed testing plan
Your plan to move to 1GB batches with a 10-second merge interval and async enabled is exactly the right move.
1. Stop ingestion for a few minutes.
2. Run the SHOW PROC command above and wait for MaxCS to drop (ideally below 100).
3. Start your new 1GB async pipeline.
With 1GB batches at 50k events/s, you will only create ~3-4 versions per minute instead of the hundreds you were creating before. This will keep the MaxCS very low and eliminate the 35s publish latency.
References
• administration/management/monitoring/metrics.md
• loading/StreamLoad.md
• loading/Stream_Load_transaction_interface.md
• table_design/table_types/primary_key_table.md
• administration/management/FE_configuration.md
• faq/loading/Loading_faq.md
latency.
References
• knowledge/admin_and_operation/shared_data_compaction.mdMinn Fong
04/24/2026, 1:29 PMRocky
04/24/2026, 1:29 PMstreaming_load_max_mb (Default 10GB): This is the hard limit for the entire HTTP body of a single Stream Load. Since you are targeting 1GB batches, the default is already plenty. You do not need to change this.
* streaming_load_max_batch_size_mb (Default 100MB): This is specific to the JSON parser. If you are sending 1GB of JSON, the parser will fail at 100MB.
* Recommendation: Either set this to 1024 in be.conf or (simpler) add "ignore_json_size:true" to your Stream Load HTTP headers.
2. The Real Flush Control: write_buffer_size
Your assumption about "flushing every 8000 rows" actually refers to the write_buffer_size.
* write_buffer_size (Default 100MB): This BE parameter determines when StarRocks flushes an in-memory segment to disk.
* The Problem: At 50k rows/s (~625 MB/s), a 100MB buffer results in 6.25 flushes per second cluster-wide. If these rows are spread across 3 BEs, each BE is still flushing every ~0.5 seconds.
* The Impact: Every flush creates a new "segment file." A single 1GB batch could easily create 10+ small files per tablet. This is what drives your Compaction Score (MaxCS) to 2,000.
* Recommendation: Set write_buffer_size = 1073741824 (1GB) or at least 536870912 (512MB). This ensures a 1GB load creates only 1 or 2 files per tablet, drastically reducing the background compaction work.
3. Tuning for Wide Tables (300+ Columns)
Wide tables have significant metadata and RPC overhead because StarRocks must track each column's segments.
* max_tablet_write_chunk_bytes (v3.2.12+):
* Default: 512MB.
* Tuning: For 300 columns, increase this to 1073741824 (1GB). This allows the BE to buffer more data for wide columns before sending it between nodes, reducing RPC overhead during the load.
* `load_process_max_memory_limit_percent`:
* Since you are increasing buffers to 1GB, ensure your loading memory pool is large enough. On r6in.4xlarge (128GB), the default 30% (~38GB) is fine, but if you have many concurrent loads, keep an eye on this.
4. Is the Plan Appropriate?
Yes, with these adjustments:
1. 1GB Stream Load: Correct. This reduces transaction frequency.
2. Merge Commit (Async): Correct. This offloads the wait time from your producer.
3. 10-Second Interval: Good. This ensures that even if you have several smaller producers, they get bundled into one healthy 5-6GB transaction.
4. BE Configuration: Use the values below to handle the wide-table/high-volume pressure.
Summary of Recommended Configs (be.conf)
properties
# Increase JSON parser limit (if using JSON)
streaming_load_max_batch_size_mb = 1024
# Reduce flushes/small files (Critical for your MaxCS 2000 issue)
write_buffer_size = 1073741824
# Optimize wide-table RPC (v3.2.12+)
max_tablet_write_chunk_bytes = 1073741824
# Parallelize the PK index "Apply" phase for your 16-core nodes
transaction_apply_worker_count = 16
update_compaction_num_threads_per_disk = 4
One final warning: When you switch to 1GB batches with async: true, your producer will feel very fast, but the BEs will be working hard behind the scenes. Do not resume ingestion until you have stopped and let the current Compaction Score (MaxCS) drop below 500, otherwise, the new 1GB segments will just pile up on top of a "stuck" system.
References
• administration/management/BE_configuration.md
• loading/loading_introduction/loading_considerations.mdRocky
04/24/2026, 1:29 PMMinn Fong
04/24/2026, 1:37 PMRocky
04/24/2026, 1:37 PMmax_tablet_write_chunk_bytes (The "Mailbox" Buffer)
* Where: In the Load Channel (Memory).
* What it triggers: A Network Transfer (RPC).
* Purpose: When you perform a Stream Load, the node receiving the data (the Coordinator) must sort and route rows to the specific BE nodes that own the target tablets.
* Why it matters for you: Because you have 300+ columns, even a few rows can take up a lot of memory.
* If this limit is low (default 512MB), the BE will frequently package up small "chunks" of data and send them over the network to the destination BEs.
* By increasing this to 1GB, you allow the BE to gather more data for your wide rows before sending it, making the network communication much more efficient (fewer, larger packets).
2. write_buffer_size (The "Desk" Buffer)
* Where: In the MemTable (Memory).
* What it triggers: A Disk Flush (I/O).
* Purpose: Once the data arrives at the destination BE, it sits in a MemTable. When this buffer hits the limit, StarRocks freezes the MemTable and "flushes" it to disk as a permanent segment file.
* Why it matters for you: This is the most critical setting for your Compaction Score (MaxCS).
* If this is small (100MB), and you are pushing 625MB/s, you will trigger 6+ flushes per second.
* Each flush creates a new file. High file counts = high compaction work.
* By increasing this to 1GB, you ensure that StarRocks only writes to disk when it has a substantial amount of data, resulting in fewer, larger, and healthier files.
Comparison Summary
Feature | max_tablet_write_chunk_bytes | write_buffer_size
Stage | Data Routing / Transport | Data Persistence
Action | Send data over network to another BE | Write data to local disk
Default | 512 MB | 100 MB
Primary Benefit | Reduces CPU/Network overhead of RPCs | Reduces "Small File Problem" & Compaction Score
Risk if too high | High Memory usage; potential RPC timeouts | High Memory usage; longer recovery time if BE crashes
Do you need both?
Yes.
* If you only increase write_buffer_size, your disk files will be healthy, but your CPU/Network might be overwhelmed by thousands of tiny RPC calls because of the wide columns.
* If you only increase max_tablet_write_chunk_bytes, your network will be efficient, but you'll still be creating thousands of tiny files on disk, leading back to that 2,000 MaxCS score.
For your specific use case (300 columns, 50k rows/s), setting both to 1GB is the "sweet spot" to keep the system stable and the compaction under heavy load.
References
• administration/management/BE_configuration.md
• administration/management/FE_configuration.md
• loading/loading_introduction/loading_considerations.mdMinn Fong
04/24/2026, 2:05 PMRocky
04/24/2026, 2:05 PMCOMMIT by a few milliseconds to allow background compaction to catch up.
* At 2,000: Ingestion stops entirely.
Since you are already at 75-100 with only 20% traffic, you will likely cross the 100 threshold when you scale up. This is not necessarily a failure. It just means the BEs will start working harder to keep the file count stable.
2. Tuning for the "Apply" Phase
With 300 columns and a Primary Key table, the most expensive part of your load isn't the disk write—it's the Apply Phase (calculating which old rows need to be marked as "deleted" because a new version arrived).
Since your CPU usage is so low (<10%), you should increase the concurrency of this phase now:
* transaction_apply_worker_count (BE config):
* Default: 0 (equal to CPU cores).
* Tuning: Since you have 16 cores and low utilization, you can leave it at 0, but if you see "Publish Latency" increase as you scale, ensure this isn't being bottlenecked by other background tasks.
* update_compaction_num_threads_per_disk (BE config):
* Default: 1.
* Tuning: Increase this to 2 or 4. This allows each disk to perform multiple compaction tasks simultaneously. Since your Disk IO is only 15%, your disks can easily handle the extra seeking.
3. Shared-Data vs. Shared-Nothing
* If you are on Shared-Nothing (Local Disk): Increase update_compaction_num_threads_per_disk.
* If you are on Shared-Data (S3/Object Storage): Increase compact_threads (Default 4) to 8 or 16. Shared-data compaction is more CPU-bound than IO-bound.
4. Memory Headroom
You mentioned using <5GB out of 128GB. This is great. For Primary Key tables, the Persistent Index (if enabled) or the In-Memory Index will grow as your row count grows.
* Check your index memory via: http://<be_ip>:<be_http_port>/mem_tracker?type=update.
* As long as this stays well below your update_memory_limit_percent (Default 60% of total mem), you have no scaling concerns here.
5. Final Scaling Checklist
Before you flip the switch to 5/5 nodes:
1. Monitor `PublishTime`: Use SHOW PROC '/transactions/<db_name>/running';. If the PublishTime starts exceeding 5-10 seconds, it means the "Apply" phase is queuing.
2. Increase Compaction Concurrency: Bump update_compaction_num_threads_per_disk to 2 or 4.
3. Check for Slowdown Messages: If your MaxCS hits 150-200, check the ErrMsg in the command above. If you see Partition's compaction score is larger than 100.0, delay commit, it's a sign you may need to increase the merge_commit_interval_ms back to 10000ms to give the BEs more "breathing room" between transactions.
Verdict: You do not need more nodes yet. Your cluster is "sleeping" at 10% CPU. You have plenty of power; you just need to allow the software to use more of that power (via thread counts) for background compaction as the volume increases.
References
• best_practices/primarykey_table.md
• table_design/table_types/primary_key_table.md
• best_practices/query_tuning/schema_tuning.md
• knowledge/usage/best-practice.mdMinn Fong
04/24/2026, 2:12 PMRocky
04/24/2026, 2:12 PMcumulative_compaction_num_threads_per_disk
* Applies to: Duplicate, Aggregate, and Unique (non-PK) models.
* Function: Merges small "delta" files into larger ones shortly after they are written.
* Your Case: This is likely doing nothing for your current table. You can leave it at 2.
* base_compaction_num_threads_per_disk
* Applies to: Duplicate, Aggregate, and Unique (non-PK) models.
* Function: Performs the massive, final merge of data into the "base" rowset.
* Your Case: Also doing nothing for your current table.
* update_compaction_num_threads_per_disk
* Applies to: Primary Key models only.
* Function: This is the engine that merges the log-structured rowsets of a Primary Key table. It handles both the merging of data and the cleanup of the "delete vector" metadata.
* Your Case: This is the most important parameter for your MaxCS (Compaction Score).
──────────
2. What will "drastically" help your Compaction Score?
Since your BE CPU is only at 10% and Disk IO is at 15%, your bottleneck isn't hardware capacity; it's concurrency limits. To drop that MaxCS from 100 towards 10-20, you should tune the following:
A. Increase update_compaction_num_threads_per_disk
Since you have 16 cores and 128GB of RAM, you can safely increase this.
* Current: 4
* Recommended: Set this to 6 or 8 (assuming 1 disk).
_ Note: If you have multiple disks (e.g., 4 SSDs), StarRocks will spin up threads _ disks total threads, so be mindful of the math.
B. The Global Cap: compact_threads
The num_threads_per_disk settings are requests, but compact_threads is the hard ceiling for the entire BE.
* Default: 4 (on older versions) or 25% of CPUs (on newer versions).
* Action: Check this value. If it's at the default of 4, your update_compaction_num_threads_per_disk = 4 is already maxing it out.
* Recommendation: Set compact_threads = 16 (matching your core count) to allow the BE to use its full power when the ingestion spikes.
C. Enable Size-Tiered Compaction (The "Game Changer")
For high-throughput PK tables, the default compaction strategy can sometimes be too aggressive or "chatty."
* Config: enable_pk_size_tiered_compaction_strategy = true (in be.conf).
* Effect: This changes the algorithm to be more like RocksDB's leveled/tiered compaction. It is much more efficient at keeping the file count low for high-frequency Stream Loads.
Summary of Suggested Tuning for your 16-core BEs:
properties
# be.conf
# Allow more total compaction tasks to run at once
compact_threads = 16
# Specifically speed up PK table compaction
update_compaction_num_threads_per_disk = 8
# Use the modern, more efficient compaction strategy for PK
enable_pk_size_tiered_compaction_strategy = true
# Since your rows are wide (300 columns), allow slightly larger merges
# to happen in a single task
max_cumulative_compaction_num_singleton_deltas = 100
How to verify:
After applying these and scaling up your traffic:
1. Run SHOW PROC '/compactions'; to see the current tasks.
2. If you see many tasks in the queue but only a few running, your compact_threads is too low.
3. If you see MaxCS staying high but CPU is still low, increase update_compaction_num_threads_per_disk.
References
• administration/management/BE_configuration.md
• knowledge/admin_and_operation/shared_data_compaction.md
• administration/management/compaction.mdMinn Fong
04/24/2026, 2:17 PMRocky
04/24/2026, 2:18 PMupdate_compaction_num_threads_per_disk = 4 is actually requesting 16 concurrent compaction tasks (4 threads × 4 disks).
Here is the revised tuning plan based on your specific hardware (16 cores, 128GB RAM, 4 EBS volumes):
1. The Multiplier Effect
If you set update_compaction_num_threads_per_disk too high with 4 disks, you will hit the global compact_threads ceiling or overwhelm your 16 CPU cores.
* Recommendation: Set update_compaction_num_threads_per_disk = 2.
* Why: 2 threads × 4 disks = 8 concurrent tasks. This leaves 8 cores free for queries and ingestion (the "Apply" phase). Since your CPU is only at 10%, this is a safe "power up."
2. The Global Ceiling (compact_threads)
Even if you allow 2 threads per disk, they won't run if the global limit is lower.
* Recommendation: Set compact_threads = 16.
* Why: This ensures that even if one disk is "busier" than others, the BE has the permission to use all its physical cores for compaction if needed.
3. Primary Key Specifics (The "Pro" Configs)
Since you are using a PK table and have significant memory/IO headroom, apply these to optimize the 300-column merges:
properties
# be.conf
# 1. Total allowed compaction tasks (match your CPU cores)
compact_threads = 16
# 2. PK-specific concurrency (2 threads * 4 disks = 8 tasks)
update_compaction_num_threads_per_disk = 2
# 3. Enable the modern PK compaction strategy (Crucial for high throughput)
# This reduces the "write amplification" significantly for wide tables.
enable_pk_size_tiered_compaction_strategy = true
# 4. Limit I/O spikes per disk to keep latency stable
# This prevents a single EBS volume from getting "hot" and slowing down others.
pindex_major_compaction_limit_per_disk = 2
# 5. Increase the efficiency of each task
# Since you have 300 columns, we want to merge more files per 'job' to save on overhead.
max_cumulative_compaction_num_singleton_deltas = 50
4. Why EBS changes things
Your EBS volumes (500 MiB/s each) give you a total node throughput of 2,000 MiB/s.
* Your current Disk IO util is <15%. This means you are only using ~300 MiB/s total.
* By increasing concurrency (more threads), you are effectively "stripping" the compaction work across all 4 volumes.
* Because EBS is network-attached, high concurrency is actually better than low concurrency—it helps fill the "pipe" to AWS storage more effectively.
Summary Checklist for Scaling to 50k/s:
1. Check `compact_threads`: If it was at the default (4), this was your real bottleneck. Set it to 16.
2. Toggle `enable_pk_size_tiered_compaction_strategy`: This is the single most effective way to stabilize MaxCS on PK tables.
3. Monitor `starrocks_be_disks_state`: Ensure data is balanced across all 4 EBS volumes. If one volume is much fuller/busier than others, your MaxCS will be driven by that one "slow" disk.
Verdict: With 4 disks and 16 cores, you are in a great position. You don't need more nodes; you just need to allow the BE to parallelize the compaction across those 4 independent EBS channels.
References
• administration/management/BE_configuration.md
• deployment/plan_cluster.md
• faq/operation_maintenance_faq.mdMinn Fong
04/24/2026, 2:22 PMRocky
04/24/2026, 2:22 PMtransaction_apply_worker_count also equals your core count (16).
* If you set compact_threads = 16, and the BE starts 16 compaction tasks, the Apply workers will starve.
* The Result: Your Compaction Score might drop, but your Transaction Publish Latency will skyrocket, and your stream load will eventually time out or slow down significantly.
2. Resource Groups Don't Limit Compaction
StarRocks Resource Groups / Workload Groups are designed to isolate Query resources (CPU/Memory/Concurrency).
* Internal BE background tasks—like Compaction and the *Apply Phase*—run in global thread pools outside of the Resource Group's cpu_core_limit.
* Even if you put queries in a restricted group, 16 compaction threads will still contend with the OS and the Apply workers for the same physical CPU cycles.
3. A Better "Aggressive" Configuration
Instead of 100% of cores, aim for 50-60% of cores for compaction. This allows you to handle the ingestion surge without killing the node's ability to commit transactions.
Suggested Tuning for 16-core BEs with 4 Disks:
properties
# be.conf
# Total ceiling: 10 threads is a heavy load but leaves room for Apply + OS
compact_threads = 10
# 3 threads * 4 disks = 12 requested, capped at 10 by the global limit above
update_compaction_num_threads_per_disk = 3
# THIS IS THE MOST IMPORTANT:
# Switch to the modern PK compaction strategy. It is significantly more
# efficient at keeping the score low with fewer CPU cycles.
enable_pk_size_tiered_compaction_strategy = true
# For 300 columns, increase the rowset limit to reduce "Write Amplification"
lake_pk_compaction_max_input_rowsets = 500
4. Should you add 2 more nodes?
Yes, but for a different reason.
Adding 2 nodes (total 6 BEs) is a great move for 50k events/s with 300 columns.
* Tablet Distribution: StarRocks will redistribute your tablets across 6 nodes instead of 4.
* Less Work per Disk: Each EBS volume will now handle fewer tablets, meaning the compaction work is spread thinner.
* Query Isolation: Since you are using 300 columns, your queries are likely "Heavy Scans." Spreading the data over more nodes increases the total aggregate IOPS and memory cache available for those wide-table queries.
Summary Recommendation
1. Don't go to 16 threads. Set compact_threads to 10 and update_compaction_num_threads_per_disk to 3.
2. Enable enable_pk_size_tiered_compaction_strategy = true immediately. This is the professional way to handle high-throughput PK tables and will likely drop your score more than adding threads will.
3. Scale to 6 nodes. This provides the physical "surface area" (more disks/cores) to maintain low latency as you ramp up from 10k to 50k events/s.
References
• administration/management/compaction.md
• best_practices/primarykey_table.md
• administration/management/BE_configuration.md
References
• table_design/table_types/primary_key_table.md
• best_practices/primarykey_table.mdMinn Fong
04/24/2026, 2:34 PMsql
SELECT
TABLE_NAME,
PARTITION_NAME,
VISIBLE_VERSION,
MAX_CS
FROM information_schema.partitions_meta
WHERE TABLE_NAME = 'requests'
ORDER BY MAX_CS DESC;
MAX_CS is 0 across all partitions. Same applies when viewing in the console. Why is this the case?
starrocks_be_tablet_update_max_compaction_score grafana metrics clearly shows compaction score varying across all nodes but MAX_CS remains 0Rocky
04/24/2026, 2:35 PMMAX_CS is showing as 0 in information_schema.partitions_meta while your Grafana metrics show high values is due to a distinction between the two different compaction engines in StarRocks.
1. The Two "Compaction Scores"
StarRocks tracks two different types of compaction scores depending on the table model:
* Standard Compaction Score (CS): This applies to Duplicate, Aggregate, and Unique (non-PK) tables. It measures the number of rowsets in the LSM-tree. The MAX_CS column in partitions_meta and the AVG_CS fields are specifically tied to this engine.
* Update Compaction Score: This applies exclusively to Primary Key (PK) tables. Because PK tables use a different storage architecture (to handle real-time deletes and partial updates), they have their own compaction metric.
2. Why it shows 0 in your query
For a Primary Key table:
* The LSM Compaction Score (shown in partitions_meta) is often 0 because the table isn't using the standard cumulative/base compaction logic.
* The Update Compaction Score is the one that is actually increasing as you load data.
* The FE (Front End) currently populates the partitions_meta view primarily with the LSM-based scores. In many versions, the PK-specific "Update Compaction Score" is not yet mapped to the MAX_CS alias in that specific system view.
3. How to view the correct PK Compaction Score via SQL
Since partitions_meta is returning the wrong metric for your table type, you should query the BE metrics directly through the information_schema. This table contains the same data your Grafana dashboard is pulling:
sql
SELECT
BE_ID,
VALUE as max_pk_compaction_score
FROM information_schema.be_metrics
WHERE NAME = 'tablet_update_max_compaction_score';
4. Why does this matter for your tuning?
In your previous question, you mentioned adjusting update_compaction_num_threads_per_disk. This was the correct move because that specific thread pool is what reduces the tablet_update_max_compaction_score.
If you were to look at cumulative_compaction_num_threads_per_disk, it would be working on the "standard" score (which is already 0 for you).
Summary Checklist:
* Grafana: Trust starrocks_be_tablet_update_max_compaction_score.
* SQL: Use information_schema.be_metrics for Primary Key tables.
* partitions_meta: Use this primarily for Duplicate/Aggregate tables or to check partition versions/sizes, but ignore its MAX_CS for PK tables.
References
• knowledge/admin_and_operation/shared_data_compaction.mdMinn Fong
04/24/2026, 2:59 PM4.0.7-b75f536
This is my current version. Any difference? A colleague suggested to wait for 4.1.1Rocky
04/24/2026, 2:59 PMMaxCS issues by allowing the BE to finish a heavy merge much faster, preventing the queue from backing up.
* Parallel MemTable Finalization: This speeds up the "Apply" phase of your 50k/s stream loads, reducing the chance of write stalls.
* Automatic Tablet Splitting: If you have data skew (one partition getting hit harder than others), 4.1 can automatically split those hot tablets without you having to manually re-shard or re-create the table.
2. Why your colleague suggested waiting for 4.1.1
There is a specific, known issue in the v4.1.0 container image (Docker/K8s environments):
* The Issue: An unstable load order in the BE process can cause backends to fail to start or crash randomly upon boot in containerized environments.
* The Fix: This is officially fixed in v4.1.1.
Decision Matrix:
If you are... | Recommendation
Running on K8s / Docker | Wait for 4.1.1. The startup bug in 4.1.0 makes it too risky for production.
Running on Bare Metal / EC2 | Upgrade to 4.1.0 now. The container bug doesn't affect you, and you'll get the parallel compaction benefits immediately.
Experiencing "Critical" MaxCS stalls | Upgrade now (non-container) or check for 4.1.1 release. If 4.1.1 is out by the time you read this, it is always the safer choice.
3. If you decide to wait: A "Stop-gap" for 4.0.7
If you wait for 4.1.1, ensure you have enabled this specific 4.0 feature to survive the 50k/s load:
properties
# ensure this is on in your current 4.0.7 be.conf
enable_pk_size_tiered_compaction_strategy = true
This strategy (introduced in late 3.x/early 4.0) is much better at handling wide tables than the old strategy, though it still lacks the multi-threaded tablet compaction found in 4.1.
Final Verdict:
Wait for 4.1.1 if you use containers. If you are running directly on EC2 instances (bare metal style), the move to 4.1 is highly beneficial for your 300-column table because it finally breaks the "one-thread-per-tablet" compaction bottleneck.
References
• https://docs.starrocks.io/docs/release_notes/release-4.1/
• https://docs.starrocks.io/docs/administration/management/compaction/
compaction)Minn Fong
04/24/2026, 3:06 PMRocky
04/24/2026, 3:06 PMupdate_compaction_num_threads_per_disk is still your primary lever. 4.1 doesn't change the underlying "one thread per tablet" rule for local storage yet.
* Ingestion: The new Publish thread pool in 4.1 is the main win for you, as it decouples the "Apply" logic from other background tasks more effectively.
Recommendation for your setup:
* If you stay on Shared-Nothing: You don't need 4.1 specifically for compaction speed, but the 4.1.1 release (once available) is worth it for the ingestion stability (Publish thread pool) and general bug fixes.
* The real "Compaction" fix: For Shared-Nothing, the most effective way to lower your Compaction Score is still:
1. Enable enable_pk_size_tiered_compaction_strategy = true (This is available in your current 4.0.7).
2. Increase the number of Buckets: Since compaction is 1-thread-per-tablet, having more (smaller) tablets allows you to utilize more of your 16 cores (via compact_threads) even if a single tablet is still slow.
3. Scale BE nodes: As you planned, adding 2 more nodes spreads the tablet load, effectively giving you more "threads" across the cluster to handle the compaction queue.
Summary: Your colleague is right to suggest waiting for 4.1.1 for stability, but don't expect 4.1 to magically solve the "one-thread-per-tablet" compaction bottleneck on local disks—that specific breakthrough is currently a "Lake-only" feature.
References
• https://docs.starrocks.io/docs/release_notes/release-4.1/
• administration/management/compaction.md
• table_design/table_types/primary_key_table.md
only" feature for now.
References
• administration/management/resource_management/Replica.md
• using_starrocks/caching/query_cache.md
• release_notes/release-4.0.mdMinn Fong
04/24/2026, 3:08 PMRocky
04/24/2026, 3:08 PMprimary_key_limit_size (default 128 bytes), it might retry indefinitely, causing a "busy-wait" loop that consumes CPU and prevents the BE from focusing on background compaction. 4.0.9 correctly identifies these as non-retryable and pauses the job, freeing up resources.
3. Critical Bug Fixes for PK Tables
* UpdateTabletSchemaTask Collision: 4.0.9 fixes a bug where concurrent ALTER TABLE operations could cause schema update tasks to be skipped. In a 300-column table where you might be adding/dropping columns, this fix is vital for metadata consistency.
* Primary Key Size Limit Handling: Improved handling of edge cases where the Primary Key index might grow unexpectedly, ensuring the BE doesn't crash or stall during the "Apply" phase.
Should you upgrade to 4.0.9 while waiting for 4.1.1?
Yes. 4.0.9 is a "safety" release. It won't make a single compaction task run 2x faster, but it will make the cluster much more resilient to the "stalls" you are seeing at 50k events/s.
If you stay on the 4.0 branch, make sure these two settings are in your BE config:
1. enable_pk_size_tiered_compaction_strategy = true (This is the most efficient strategy for 4.0).
2. update_compaction_num_threads_per_disk = 4 (or higher, since you have 16 cores and 300 columns).
Summary: 4.0.9 is about predictability and diagnostics. It will help you see why the compaction score is high or why tasks are suspended, whereas 4.0.7 might leave you guessing. If you are struggling with the 50k/s load today, 4.0.9 is a worthy interim step before the 4.1.1 upgrade.
References
• release_notes/release-4.0.md
• administration/management/compaction.md
References
• release_notes/release-4.0.mdMinn Fong
04/24/2026, 3:27 PMRocky
04/24/2026, 3:27 PMdesired_concurrent_number for Routine Load.
2. Parallelize the Apply Phase: In your be.conf, check transaction_apply_worker_count. If it’s low, increase it to 8 or 12. This allows the BE to use more cores when finishing those 1.5GB flushes.
3. Compaction Concurrency: Since your score is 45, you have "room" to make compaction more aggressive.
* Set update_compaction_num_threads_per_disk = 4.
* This will use more CPU to "clean up" those 45 versions faster, bringing the score down even further and potentially allowing for even higher throughput (100k+ events/s).
Summary Checklist:
* Current State: Healthy, but "lazy."
* Recommendation: Keep the 1.5GB flush. Increase your Routine Load batch size/time to match.
* Next Step: If you have 50k events/s today and low CPU, you can likely push to 100k+ events/s on the same hardware just by increasing the load concurrency.
One Warning: Monitor your BE memory. Large flushes + 300 columns + high concurrency can lead to memory spikes. Keep an eye on mem_tracker?type=update to ensure you aren't approaching the 80% process limit.
References
• knowledge/admin_and_operation/shared_data_compaction.mdMinn Fong
04/24/2026, 3:29 PMRocky
04/24/2026, 3:30 PM_version column or _is_delete logic to ensure out-of-order loads don't corrupt the final state.
3. Tuning the BE for Wide-Table Stream Loads
Since you have 300 columns, the "MemTable" (where data lives before it hits 1.5GB) and the "Apply" phase are the bottlenecks. Adjust these in `be.conf`:
* transaction_apply_worker_count: Increase this to 8 or 12.
* This controls how many threads are available to update the PK index and write delete vectors once a load finishes. For 300 columns, this phase can be CPU-intensive; giving it more threads will help clear the "Apply" queue faster.
* flush_thread_num_per_store: Increase to 4.
* This allows the BE to use more threads to actually write those 1.5GB MemTables to disk.
* load_process_max_memory_limit_percent: Ensure this is at least 30% or 40%.
* With 1.5GB flushes and multiple parallel loads, you need to ensure the BE doesn't trigger "emergency flushes" because it hit the global load memory limit.
4. Optimize the "Apply" Phase
In Primary Key tables, the "Apply" (publishing the version) is often the hidden cost.
* Check your be.conf for primary_key_batch_get_index_threads. If it's not set, it defaults to a low value. Increasing this can speed up the "lookup" part of the ingestion for wide tables.
5. Check "Partial Update" Potential
Are you sending all 300 columns in every Stream Load?
* If you are only changing a few columns, use Partial Updates (set the HTTP header partial_update: true).
* In StarRocks 3.x/4.x, partial updates for PK tables are extremely efficient. This would reduce your IO and CPU even further by only writing the changed columns to new segments.
Summary: Is it "Sub-optimal"?
It is only sub-optimal if you want to process more data. If your requirement is 50k events/s and the system is healthy at 10% CPU, you have successfully built a very cost-efficient cluster.
If you want to push for 100k-150k events/s:
1. Increase Client Batch Size (aim for 1GB per PUT).
2. Increase Parallel Workers (2-4).
3. Increase Apply Workers (transaction_apply_worker_count = 12).
Final Warning: Keep an eye on the mem_tracker?type=update via the BE web port (8040). If the PK index memory grows too large for your 16-core nodes, you'll see "memory limit exceeded" errors. If that happens, it's time to add the 2 nodes you mentioned earlier.
ReferencesMinn Fong
04/24/2026, 3:33 PMRocky
04/24/2026, 3:34 PMtransaction_apply_worker_count = 0 (which defaults to your 16 cores). For a 300-column PK table, the "Apply" phase is the most CPU-intensive part because StarRocks must:
1. Check the PK index for 1.5GB worth of rows.
2. Generate delete vectors for old versions.
3. Update the index.
Optimization: Increase transaction_apply_worker_count to 24 or 32 (1.5x or 2x your core count).
* Why: Even though you have 16 cores, "Apply" tasks often involve I/O waits (reading the PK index or metadata). Having more workers allows the BE to process more "Apply" tasks in parallel while others wait for disk I/O, better utilizing those 16 cores.
2. Leverage Your 4 EBS Volumes
You have update_compaction_num_threads_per_disk = 4 and 4 disks. This means you have 16 potential threads dedicated to PK compaction.
* Check: Ensure your storage_root_path in be.conf explicitly lists all four mount points (e.g., storage_root_path = /mnt/ebs1;/mnt/ebs2;/mnt/ebs3;/mnt/ebs4).
* Optimization: If your EBS volumes are io2 or gp3 with high throughput, you can increase update_compaction_num_threads_per_disk to 6 or 8.
* Result: This will consume more of that idle CPU to bring your compaction score from 45 down to <10, which will make queries faster.
3. Memory & Flush Tuning
With 4 concurrent 1.5GB Stream Loads, you are holding at least 6GB of raw data in memory at any given time just for the active MemTables.
* Optimization: Check load_process_max_memory_limit_percent (default 30%). If your BE has 64GB of RAM, 30% is ~19GB. You are safe. If your BE has only 32GB, 30% is ~9GB, which is getting close to the limit.
* Action: If you have the RAM, increase this to 50% to prevent "emergency flushes" that ignore your 1.5GB threshold.
4. Increase Ingestion Concurrency
Since your CPU is in the single digits, the cluster is "bored."
* Optimization: Increase your worker goroutines from 4 to 8 or 12.
* Why: You are currently bottle-necked by your client-side ingestion rate. By doubling the concurrent PUT requests, you will start to see the CPU utilization climb into the 30-50% range, which is much more optimal for your hardware.
5. Partial Updates (The "Pro" Move)
If your 300 columns are not all changing in every load:
* Optimization: Use the HTTP Header partial_update: true.
* Impact: This reduces the I/O load significantly during both the "Apply" phase and Compaction, as StarRocks only writes the delta for the columns that actually changed. This is the single biggest performance boost for wide PK tables.
6. Fine-tune Compaction Strategy
Since you are on 4.0.x, ensure you are using the Size-Tiered strategy for PK tables:
* enable_pk_size_tiered_compaction_strategy = true
* This strategy is much better at handling the "large rowset" pattern you've created with 1.5GB flushes compared to the older priority-based strategy.
Summary Checklist for your `be.conf`:
1. transaction_apply_worker_count = 24 (Increase to saturate CPU during commits).
2. update_compaction_num_threads_per_disk = 6 (To bring the score 45 down faster).
3. load_process_max_memory_limit_percent = 50 (Ensure large flushes aren't interrupted).
4. Client-side: Increase goroutines to 8 to feed the cluster more data.Rocky
04/24/2026, 3:34 PMMinn Fong
04/24/2026, 3:38 PMRocky
04/24/2026, 3:39 PMcompact_threads and Per-Disk Threads
You have 4 disks and update_compaction_num_threads_per_disk = 4. This creates a potential for 16 concurrent PK compaction tasks.
* The Global Cap: compact_threads is the global limit for all compaction types (Base, Cumulative, and PK).
* The Constraint: If you keep compact_threads at a low value (like the default 4), StarRocks will never actually run more than 4 compaction tasks, even though your per-disk setting allows for 16.
* Recommendation: To utilize your disk parallelism, compact_threads must be at least equal to your total disk threads ($4 \times 4 = 16$).
2. Is 14 threads on a 16-core machine safe?
Since your current CPU utilization is in the single digits, you have plenty of room. However, compaction is "bursty." When a large merge starts, it will try to consume as much CPU as the thread allows.
* The Risk: If you set compact_threads = 14, and 14 large merge tasks trigger at once, your CPU will jump to 90%+ instantly. This could cause your 150ms publish latency to spike to several seconds because the "Apply" phase (which also needs CPU) will be fighting for the remaining 2 cores.
* The Better Approach: Start with compact_threads = 8 (50% of cores). Since your compaction score is 45, the goal is to see if it starts trending down. If it stays at 45 and CPU is still low, move to 10 or 12.
* Why not 14? You need to leave overhead for:
1. The Apply Phase: Even if it’s only 150ms, it needs high-priority CPU cycles.
2. The BE Heartbeat/RPC: If the BE becomes totally CPU-saturated, it might miss heartbeats from the FE, causing the node to be marked as "Down."
3. Why is your Compaction Score 45 despite low CPU?
If your score is stuck at 45 and CPU is low, it means the system isn't "trying" hard enough to compact, likely due to internal throttling or interval settings.
Try adjusting these to lower that score of 45:
* update_compaction_per_tablet_min_interval_seconds: Default is often 120s. Reduce this to 30s. This tells StarRocks it's okay to trigger a new compaction task on the same tablet more frequently.
* enable_pk_size_tiered_compaction_strategy = true: (If not already on). For your 1.5GB batches, the "Size-Tiered" strategy is far more effective at bringing down the version count than the legacy strategy.
4. Summary & Action Plan
1. Increase compact_threads to 10 or 12 (not 14 yet). This gives you a massive boost over the default while keeping a safety buffer.
2. Set transaction_apply_worker_count = 16 (explicitly). Even though it defaults to core count, explicitly setting it ensures that during the 150ms publish window, the BE can aggressively use all cores to finish the job.
3. Lower update_compaction_per_tablet_min_interval_seconds to 30 to allow more frequent "cleanup" of those 45 versions.
4. Monitor the "Apply" Queue: Keep an eye on be_http_port/mem_tracker. If you see update memory growing or publish latency increasing, back off the compact_threads.
Verdict: Your 150ms publish latency means the "Apply" phase is healthy. Your current bottleneck is simply that the compaction scheduler is being too "polite." Increasing the thread count to 10-12 and shortening the interval will move that score from 45 down toward 10.
References
• administration/management/BE_configuration.mdRocky
04/24/2026, 3:39 PMMinn Fong
04/24/2026, 4:14 PMRocky
04/24/2026, 4:15 PMinformation_schema.be_configs. This is often much more convenient than running curl commands against each individual node.
However, there are a few important caveats to keep in mind:
1. It only works for "Mutable" parameters
Not all configurations can be changed at runtime. You can verify if a parameter is changeable by checking the MUTABLE column in that same table:
sql
SELECT * FROM information_schema.be_configs WHERE NAME = 'compact_threads';
If MUTABLE is TRUE, the change will take effect immediately without a restart.
For your specific parameters:
* compact_threads: Yes, it is mutable (since v3.1.7+).
* transaction_apply_worker_count: Yes, it is mutable (since v3.2.0+).
* update_compaction_num_threads_per_disk: Yes, it is mutable.
2. How to run the update
You can target all BE nodes at once, or specific ones using the `BE_ID`:
sql
-- Update all BE nodes at once
UPDATE information_schema.be_configs
SET VALUE = '12'
WHERE NAME = 'compact_threads';
-- Update a specific BE node
UPDATE information_schema.be_configs
SET VALUE = '16'
WHERE NAME = 'transaction_apply_worker_count' AND BE_ID = 10001;
3. Changes are Ephemeral (Transient)
This is the most important part: Changes made via UPDATE information_schema.be_configs (or via curl) are stored in memory. If the BE process restarts, it will revert to the values defined in your be.conf file.
Best Practice:
1. Run the UPDATE SQL command to see the immediate effect on your compaction score and CPU.
2. Once you are happy with the performance, manually update the be.conf file on your BE servers so the changes persist after a reboot.
Summary Checklist
Configuration | Mutable? | Recommended Action
compact_threads | Yes | Set to 10-12 via SQL; update be.conf later.
transaction_apply_worker_count | Yes | Set to 16 via SQL; update be.conf later.
update_compaction_num_threads_per_disk | Yes | Set to 4-6 via SQL; update be.conf later.
update_compaction_per_tablet_min_interval_seconds | Yes | Set to 30 via SQL; update be.conf later.
If you run the UPDATE and see Query OK, X rows affected, the BEs have already adjusted their internal thread pools and you should see the change in your monitoring (Grafana/Dashboard) within seconds later.
References
• administration/management/BE_configuration.mdMinn Fong
04/24/2026, 5:00 PMSELECT
BE_ID,
VALUE as max_pk_compaction_score
FROM information_schema.be_metrics
WHERE NAME = 'tablet_update_max_compaction_score';
Is this query or the grafana stats starrocks_be_tablet_update_max_compaction_score more accurateRocky
04/24/2026, 5:00 PMinformation_schema.be_metrics)
* Accuracy: Real-time Snapshot.
* Best for: Verifying the immediate impact of configuration changes. When you run that SQL command, StarRocks fetches the current value from the BE's memory at that exact millisecond.
* Behavior: It bypasses any scraping latency. If a compaction task just finished 1 second ago, the SQL query will reflect the new, lower score immediately.
2. Grafana (starrocks_be_tablet_update_max_compaction_score)
* Accuracy: Historical Trend / Scraped Snapshot.
* Best for: Monitoring health over hours or days and spotting "spikes."
* Behavior: It is limited by your Prometheus scrape interval (usually 15s or 30s). If your score fluctuates rapidly, Grafana might show a "smoothed" version or miss a peak that happened between scrapes.
Which one should you trust for your optimization?
Since you are currently tuning compact_threads and update_compaction_num_threads_per_disk and want to see if that score of 45 drops:
1. Use the SQL Query for the next 10 minutes. Run it every 60 seconds after your UPDATE to see if the threads are actually working through the backlog.
2. Use Grafana to ensure that after you stop watching, the score stays low and doesn't slowly creep back up to 45 overnight.
One Technical Nuance
The metric tablet_update_max_compaction_score represents the single highest score among all tablets on that BE.
* If you have 1000 tablets and 999 have a score of 1, but one tablet is stuck at 45, the metric will show 45.
_ If you want to see if the _entire node* is improving, you might also want to check be_compactions as mentioned earlier:
sql
SELECT BE_ID, CANDIDATE_MAX_SCORE, LATEST_COMPACTION_SCORE
FROM information_schema.be_compactions;
This table provides more context on whether the "45" is a single outlier or the average state of your candidates.
Summary: Trust the SQL Query for immediate feedback on your config changes; trust Grafana for long-term stability monitoring.
References
• administration/management/monitoring/metrics.md
• sql-reference/information_schema/be_compactions.md
• administration/management/compaction.md
• administration/management/BE_configuration.mdMinn Fong
04/24/2026, 5:16 PMRocky
04/24/2026, 5:17 PMcompact_threads with Disk Parallelism
You have 4 disks and update_compaction_num_threads_per_disk = 4. This means the Primary Key engine is capable of running 16 concurrent tasks. However, your compact_threads = 12 acts as a global "ceiling."
* Action: Increase compact_threads to 16.
* Why: This matches your physical disk concurrency. Even if all 16 threads fire, your CPU utilization will likely only hit 60-70% because compaction is often I/O bound on EBS. This still leaves plenty of room for your 150ms "Apply" phase.
2. Increase Per-Disk Concurrency
EBS volumes (especially GP3 or IO2) can often handle more than 4 concurrent I/O streams.
* Action: Increase update_compaction_num_threads_per_disk from 4 to 6.
* Action: Increase compact_threads to 24 (to allow the global pool to accommodate $6 \times 4$ disks).
* Why: If your tablets are not perfectly distributed across all 4 disks, a single "hot" disk might be stuck at 4 threads while the others are idle. Increasing the per-disk limit allows the BE to be more aggressive on the specific volumes where the data is landing.
3. Shorten the "Check" Intervals
Even with the min_interval at 30s, the BE might not be scanning for new work frequently enough.
* Action: Check update_compaction_check_interval_seconds (Default is often 2-5s). Ensure it is not set higher.
* Action: Set max_cumulative_compaction_num_singleton_deltas = 100.
_ _Note:* By merging fewer segments at a time, each compaction task finishes faster. This cycles the threads back into the pool more quickly, allowing the scheduler to pick up the next "Version 45" tablet sooner.
4. Adjust the Scoring "Greediness"
If the BE thinks a compaction task isn't "worth it," it won't run it even if threads are free.
* Action: Set update_compaction_ratio_threshold = 0.1 (Default 0.5).
* This makes the BE more willing to compact even if the new rowset is small relative to the base data.
* Action: Set update_compaction_delvec_file_io_amp_ratio = 10 (Default 2).
* This forces the BE to prioritize tablets that have many "Delete Vectors," which is likely what is keeping your score at 45.
Updated Action Plan (SQL Commands)
Run these on your cluster to force the BEs out of "lazy" mode:
sql
-- Allow more concurrent tasks globally
UPDATE information_schema.be_configs SET VALUE = '24' WHERE NAME = 'compact_threads';
-- Allow more tasks per physical EBS volume
UPDATE information_schema.be_configs SET VALUE = '6' WHERE NAME = 'update_compaction_num_threads_per_disk';
-- Prioritize tablets with delete-vector versions (common in PK tables)
UPDATE information_schema.be_configs SET VALUE = '10' WHERE NAME = 'update_compaction_delvec_file_io_amp_ratio';
-- Make tasks smaller and faster to cycle threads
UPDATE information_schema.be_configs SET VALUE = '100' WHERE NAME = 'max_cumulative_compaction_num_singleton_deltas';
What to watch for:
Watch your Disk IOPS and Throughput in CloudWatch or Grafana. If you hit the EBS burst limit, your latency will spike. If CPU stays under 50% and EBS metrics look healthy, you can even push update_compaction_num_threads_per_disk to 8.
References
• administration/management/compaction.md
• knowledge/admin_and_operation/shared_data_compaction.mdRocky
04/24/2026, 5:17 PMMinn Fong
04/24/2026, 5:19 PMRocky
04/24/2026, 5:20 PMcompact_threads to about 25-50% of your CPU cores.
The reason for that rule is to prevent compaction from "starving" your SQL queries of CPU resources during peak hours.
Why I suggested exceeding that rule in your case:
You are in a specific troubleshooting state where:
1. CPU is "Lazy": You have 16 cores but are only using ~3 cores worth of power (20%).
2. Backlog is High: Your compaction score is 45 (well above the healthy target of <10).
3. I/O Bound vs. CPU Bound: Compaction on Primary Key tables involves reading/writing to EBS and checking Bloom filters. These threads spend a significant amount of time in "I/O Wait" (waiting for the disk).
When threads are waiting for I/O, they aren't using the CPU. Therefore, having 24 threads on 16 cores does not mean you are oversubscribing the CPU; it just means you are allowing the BE to have more "irons in the fire" so that while 10 threads are waiting for EBS to respond, the other 14 can still be processing data.
The Nuance: Global vs. Per-Disk
There is a distinction between the different thread pools that often causes confusion:
* compact_threads (Global Pool): This is the "Master Ceiling" for all compaction types (Cumulative, Base, and PK). If this is 12, no more than 12 tasks will run, regardless of other settings.
* update_compaction_num_threads_per_disk (PK Specific): Since you have 4 disks, setting this to 4 creates a potential for 16 threads ($4 \times 4$).
If I previously said "don't exceed the number of cores," I was likely referring to the sum of all active worker pools to avoid context-switching overhead. However, since your CPU busy util is only 20%, you have a massive amount of "thermal headroom."
Updated Advice for your 16-core / 4-disk nodes:
If you want to clear that score of 45 quickly without hitting a CPU bottleneck:
1. Set compact_threads to 16 (1:1 with cores). This is a safe "aggressive" setting.
2. Set update_compaction_num_threads_per_disk to 4.
3. Watch the CPU: If it jumps from 20% to 50-60%, stay there. If it stays at 20%, you are being bottlenecked by I/O throughput or the compaction interval, not the number of threads.
Summary: The "25% of cores" is a rule for sustained health. When you have a backlog spike and idle CPU, you should temporarily increase these limits to 100% of cores (or slightly above if I/O wait is high) to "flush" the system. Once the score is back under 10, you can scale them back down to the conservative 25-50% range.
References
• knowledge/admin_and_operation/shared_data_compaction.md
• administration/management/compaction.md
• administration/management/BE_configuration.mdMinn Fong
04/24/2026, 5:24 PMRocky
04/24/2026, 5:24 PMcompact_threads and update_compaction_num_threads_per_disk, watch these four categories of metrics:
1. The "Backlog" Metrics (Are you winning?)
These tell you if your changes are actually reducing the work queue.
* tablet_update_max_compaction_score: (The one you're already watching). If this doesn't trend down toward 10, your ingestion is still outpacing your compaction.
* pk_index_compaction_queue_count: If this is high (>0 consistently), it means tablets are waiting for a thread to become available. If this is 0 but your score is 45, it means the BE is choosing not to schedule the task (check your min_interval or ratio_threshold).
* information_schema.be_compactions (CANDIDATE_MAX_SCORE): Use this to see if the "45" is just one tablet or if many tablets are hovering at high scores.
2. The "Utilization" Metrics (Is it actually working?)
These confirm if the BE is utilizing the threads you've granted it.
* running_update_compaction_task_num: This should now be hitting your compact_threads ceiling. If you set compact_threads = 16 but this metric only shows 4, the BE is being throttled by another setting (like update_compaction_per_tablet_min_interval_seconds).
* be_base_compaction_rowsets_per_second: This measures throughput. As you tune, you want to see this number increase.
3. The "Hardware Bottleneck" Metrics (The "Why" behind 20% CPU)
If CPU is low but the score is high, you are likely hitting an external wall:
* Disk I/O Wait (iostat -x or CloudWatch): Look for %util on your disks. If your EBS volumes are at 90-100% utilization, adding more threads will not help; it will just increase latency.
* EBS Burst Balance/IOPS: If you are using AWS GP3, ensure you haven't exhausted your IOPS or throughput credits.
* mem_tracker (Type: update): PK tables keep the primary key index in memory. If the BE is hitting its memory limit, it may pause compaction to avoid an OOM.
* Check: http://<BE_IP>:8040/mem_tracker?type=update
4. The "Internal Throttling" Logs
If metrics look "fine" but the system is still slow, check for these messages in the <http://be.INFO|be.INFO> log or via SQL:
* Ingestion Slowdown: Run SHOW PROC '/transactions/<db_name>/running';.
* If the ErrMsg field says Partition's compaction score is larger than 100.0, delay commit, StarRocks is intentionally slowing down your inserts to let compaction catch up.
* Compaction Trace: If a single compaction task takes longer than compaction_trace_threshold (default 60s), it will print a "Trace" in the logs. This will tell you exactly which phase (reading, filtering, or writing) is the bottleneck.
Summary Checklist for your next "Push":
1. Monitor running_update_compaction_task_num: Does it equal your compact_threads?
2. Monitor Disk Latency: Is it staying under 10-20ms?
3. Check pk_index_compaction_queue_count: If this is 0 but scores are high, lower your update_compaction_per_tablet_min_interval_seconds further (try 10s).
Rocky's Pro-Tip: If your CPU stays at 20% even after increasing threads, the bottleneck is almost certainly Disk I/O throughput (the speed at which data moves to/from EBS) or a Concurrency Lock on specific hot tablets.
References
• administration/management/monitoring/metrics.md
• administration/management/BE_configuration.md
• sql-reference/information_schema/be_compactions.md
• administration/management/compaction.mdRocky
04/24/2026, 5:24 PMMinn Fong
04/24/2026, 5:31 PMpk_index_compaction_queue_count always 0
average compaction score from DB jumps between 30-70 now. More often than not it is above 50 during the concurrent flushes.
update_compaction_per_tablet_min_interval_seconds set to 30 seconds
BE memory usage is healthy
All EBS volumes have ~99% time spent idle.
So best option now is to lower the compaction min interval and ratio threshold? They're 30 seconds and 0.5 respectively now.
@RockyRocky
04/24/2026, 5:32 PMpk_index_compaction_queue_count is 0, the StarRocks BE is essentially deciding not to work. It isn't being blocked by resources; it's being blocked by its own "worthiness" and "safety" logic.
Your score of 30-70 means you have a significant backlog of rowset versions. To force the BE to be more aggressive, you should focus on the scheduling triggers.
1. Lower the "Patience" (Min Interval)
Even at 30 seconds, if you are performing frequent flushes (e.g., every 5-10 seconds), the BE will skip the tablet for several flush cycles.
* Recommendation: Set update_compaction_per_tablet_min_interval_seconds = 5.
* Why: In high-concurrency ingestion, 30 seconds is an eternity. Lowering this to 5s or 10s ensures that as soon as a tablet hits a "messy" state, it becomes eligible for a thread immediately.
2. Lower the "Gain" Threshold (Ratio)
The update_compaction_ratio_threshold (Default 0.5) acts as a "is this worth it?" check. It compares the size of the rowsets to be merged against the total size of the tablet.
* Recommendation: Set update_compaction_ratio_threshold = 0.1 (or even 0.01 if your data is very large).
* Why: If you have 10GB of base data and you just flushed 10MB, the ratio is 0.001. At a threshold of 0.5, the BE will ignore this "tiny" update even if your version count is climbing. Lowering this forces the BE to merge small updates into the base data much sooner.
3. Tighten the Check Cycle
The BE only looks for new compaction work every few seconds.
* Action: Check update_compaction_check_interval_seconds.
* Recommendation: Set it to 2 (Default is usually 10).
* Why: This reduces the "sleep" time of the background scheduler, making it more responsive to the scores jumping to 70.
4. Increase "Delvec" Priority
Since you are using Primary Key tables, "Delete Vectors" are a major source of read amplification.
* Action: Increase update_compaction_delvec_file_io_amp_ratio.
* Recommendation: Set it to 10 or 20 (Default 2).
* Why: This artificially inflates the "importance" of tablets with many updates/deletes, moving them to the front of the line for the compact_threads.
Suggested SQL to "Wake Up" the BE:
sql
-- Trigger compaction much more frequently
UPDATE information_schema.be_configs SET VALUE = '5' WHERE NAME = 'update_compaction_per_tablet_min_interval_seconds';
-- Merge even tiny updates into the base data
UPDATE information_schema.be_configs SET VALUE = '0.1' WHERE NAME = 'update_compaction_ratio_threshold';
-- Check for new work every 2 seconds instead of 10
UPDATE information_schema.be_configs SET VALUE = '2' WHERE NAME = 'update_compaction_check_interval_seconds';
-- Prioritize tablets with high update/delete volume
UPDATE information_schema.be_configs SET VALUE = '20' WHERE NAME = 'update_compaction_delvec_file_io_amp_ratio';
Why your pk_index_compaction_queue_count is 0:
This metric specifically tracks the Index compaction pool (merging the PK indexes). If this is 0 but your score is high, it confirms the bottleneck is in the Data compaction (merging rowsets), which uses the general compact_threads.
Final Check:
If you apply these and be_running_update_compaction_task_num still stays at 2, then look at your FE configurations. If this is a shared-data (lake) cluster, the FE might be limiting the number of concurrent tasks globally via lake_compaction_max_tasks.
References
• administration/management/BE_configuration.md
• administration/management/compaction.md
• knowledge/admin_and_operation/shared_data_compaction.mdRocky
04/24/2026, 5:32 PMMinn Fong
04/24/2026, 5:37 PMRocky
04/24/2026, 5:37 PMupdate_compaction_check_interval_seconds | How often the BE background thread "wakes up" to look for any tablets that need work. | The Guard's Rounds: Every 10s, the guard walks past all the cells (tablets) to see if anyone is calling for help.
update_compaction_per_tablet_min_interval_seconds | The "Lockout" period for a specific tablet. After Tablet A is compacted, it cannot be touched again for this long. | The Cooldown: After a tablet gets "medical attention," it's banned from the clinic for 30s, even if it gets injured again immediately.
Why your BE tasks are "Horribly Low":
You are flushing data every 5 seconds.
1. A tablet gets compacted.
2. 5 seconds later, a new version arrives. Score goes up.
3. 5 seconds later, another version arrives. Score goes up.
4. The tablet is now eligible for compaction again, BUT it is locked out for 30 seconds.
5. By the time the 30s "cooldown" expires, that tablet has accumulated 6 new versions.
6. This cycle repeats, keeping your "average score" high (around 50-70) while your threads sit idle because they are legally forbidden from helping that specific tablet until the timer hits 0.
2. Why is "Merge Commit Latency" high but "Publish" low?
* Transaction Publish Latency (~180ms): This is just the "handshake" between the BE and FE confirming the data is safely on disk. It doesn't care about the state of the table.
* Merge Commit Load Latency (~20s): This includes the Apply Phase. For Primary Key tables, every load must check the PK Index to see if the new rows are inserts or updates.
* The Bottleneck: When your compaction score is 50-70, it means the "Apply" process has to scan many small rowsets and delete-vector files to ensure data consistency.
* The Result: High version counts (high compaction score) directly cause high load latency because the "Apply" work becomes 10x harder.
──────────
Recommended Strategy
You have plenty of CPU and Disk I/O headroom. You should "break the safety glass" on these throttles:
1. Lower update_compaction_per_tablet_min_interval_seconds to 5:
* Matches your merge commit interval. This allows a "hot" tablet to be compacted as soon as the next flush arrives if the score is high.
2. Lower update_compaction_check_interval_seconds to 2:
* Makes the BE more responsive to score spikes.
3. Lower update_compaction_ratio_threshold to 0.1:
* The default 0.5 is often too "picky" for large tables. If your tablet is 100GB, it might refuse to merge a 100MB flush because 100MB/100GB < 0.5. Setting this to 0.1 forces the merge.
SQL to apply immediately:
sql
ADMIN SET FRONTEND CONFIG ("tablet_stat_update_interval_second" = "30"); -- FE sees scores faster
-- Run these on each BE or via a global config change
UPDATE information_schema.be_configs SET VALUE = '5' WHERE NAME = 'update_compaction_per_tablet_min_interval_seconds';
UPDATE information_schema.be_configs SET VALUE = '2' WHERE NAME = 'update_compaction_check_interval_seconds';
UPDATE information_schema.be_configs SET VALUE = '0.1' WHERE NAME = 'update_compaction_ratio_threshold';
What to expect:
Within minutes, your be_running_update_compaction_task_num should jump from 2 to 8-12. Once the "backlog" of scores drops below 10, your Merge Commit Load Latency will drop significantly because the "Apply" phase only has to look at 1 or 2 rowsets instead of 50.
References
• administration/management/BE_configuration.mdMinn Fong
04/24/2026, 5:39 PMupdate_compaction_ratio_threshold what ratio is this? Im stream loading 1.5 GB per batchRocky
04/24/2026, 5:40 PMupdate_compaction_ratio_threshold is a safety throttle (a "maximum" limit) rather than a trigger. Here is the breakdown of what it means and how it interacts with your 1.5 GB stream load.
1. What is the Ratio?
The ratio is defined as:
Ratio = (Total Size of Rowsets to be Merged) / (Total Size of the Tablet)
* The Default (0.5): This means StarRocks is allowed to merge rowsets that, in total, represent up to 50% of the tablet's total size in a single compaction task.
* Why it exists: It prevents the "Small Write, Massive Rewrite" problem. If you have a 100GB tablet and you just added 10MB of data, you don't want the BE to rewrite 100GB of data just to incorporate 10MB. That would be a waste of I/O.
* In Shared-Nothing: While the documentation often highlights this for shared-data, in recent versions (v3.1.10+ and v3.2.5+), it is a BE configuration that helps control write amplification in Primary Key tables.
2. How your 1.5 GB Batch fits in
Since you are loading 1.5 GB per batch, the impact on this ratio depends entirely on your number of tablets (buckets):
* Scenario A (Few Tablets): If your 1.5 GB goes into 10 tablets, each tablet gets 150 MB. If the tablet is 1 GB total, the ratio is 0.15. This is well below the 0.5 threshold, so compaction is allowed.
* Scenario B (Many Tablets): If your 1.5 GB is spread across 500 tablets, each tablet only gets ~3 MB. If the tablet size is 10 GB, the ratio is 0.0003.
3. The "Real" Bottleneck: update_compaction_size_threshold
If your BE is "lazy" (tasks < 2) despite a high score, the issue is likely not the ratio, but how the Compaction Score is calculated for Primary Key tables.
For PK tables, the score isn't just the "number of files." It is calculated as:
Score = Rowset Size / update_compaction_size_threshold
_(Default update_compaction_size_threshold = 256 MB)_
* The Problem: If your 1.5 GB batch is split into 100 tablets, each tablet gets a 15 MB rowset.
* The Calculation: $15\text{ MB} / 256\text{ MB} = \mathbf{0.06}$ points per load.
* The Result: You would need to perform 160 loads (at 15 MB each) before a tablet even hits a score of 10 (the minimum to start compaction).
Recommendations for your 1.5 GB Stream Load:
If your score is high (30-70) but the BE isn't picking up tasks, it means the BE thinks the tasks are "too small to be worth the effort" or it's hitting the interval lockout.
1. Lower `update_compaction_size_threshold`:
If you want the BE to be more aggressive with smaller flushes, lower this from 256MB to 64MB or 128MB.
_ _Effect:* This inflates the compaction score, making the BE treat smaller files as "more urgent."
* UPDATE information_schema.be_configs SET VALUE = '67108864' WHERE NAME = 'update_compaction_size_threshold';
2. Keep update_compaction_ratio_threshold at 0.5 (or higher):
Contrary to the previous suggestion, if you want to merge a lot of small versions into a large base file, you want this ratio to be large (e.g., 0.8) so the BE doesn't "give up" on large tablets.
3. Check the "Minimum Worthiness":
Ensure update_compaction_per_tablet_min_interval_seconds is low (5s-10s) so the 1.5 GB batches don't stack up while the tablet is "cooling down."
Summary: Your 1.5 GB batch is large, but once partitioned into tablets, the individual rowsets might be too small to trigger the "lazy" default settings. Lower the size_threshold to make the BE respect your 1.5 GB loads as "significant work."
References
• administration/management/BE_configuration.md
• best_practices/primarykey_table.md
• administration/management/compaction.mdMinn Fong
04/24/2026, 5:50 PMRocky
04/24/2026, 5:51 PMcompact_threads is that for Primary Key tables in Shared-Nothing, there is a secondary "throttle" that acts as a multiplier based on your hardware.
1. The Limiter: update_compaction_num_threads_per_disk
In StarRocks, Primary Key compaction tasks are constrained by the number of data disks you have configured.
* The Config: update_compaction_num_threads_per_disk (Default: 1)
* The Logic: Max Tasks = (Number of Data Directories) * update_compaction_num_threads_per_disk
If your BE nodes have only 2 or 3 EBS volumes (or a single local disk), the BE will ignore your compact_threads = 12 and cap the tasks at 2 or 3 to prevent "disk thrashing."
Recommendation:
Since your EBS volumes are 99% idle, you can safely increase this.
sql
-- Increase threads allowed per disk for PK tables
UPDATE information_schema.be_configs SET VALUE = '4' WHERE NAME = 'update_compaction_num_threads_per_disk';
If you have 3 disks, this will allow up to 12 concurrent tasks (3 disks * 4 threads). This should finally saturate your compact_threads.
──────────
2. Primary Indicators of Ingestion Health (Beyond the Score)
While the Compaction Score is a great "backlog" indicator, it doesn't tell the whole story. For a high-concurrency PK table environment, you should monitor these four metrics to ensure ingestion isn't "secretly" suffering:
A. Apply Latency (update_rowset_commit_apply_duration_us)
* What it is: The time it takes for a newly flushed rowset to be "applied" (merging PKs and generating delete vectors).
* Healthy Range: < 1 second.
* Warning: If this starts climbing (e.g., your ~20s load latency), it means your compaction is too slow, and the "Apply" thread is struggling to scan through too many old versions.
B. Primary Index Memory (update_mem_bytes)
* What it is: The RAM consumed by the PK indexes.
* Health Check: If this approaches your BE memory limit, StarRocks will start evicting indexes to disk (if enable_persistent_index is true) or fail loads (if false).
* Note: If you see pk_index_compaction_queue_count climb above 0, it means your index-specific compaction is falling behind.
C. Read Amplification (Delete Vector Size)
* How to check: Monitor the size of .del files or the metric update_del_vector_num.
* Health Check: In PK tables, updates don't change the original data file; they mark rows as deleted in a "Delete Vector." If your compaction score is low but query performance is slow, you likely have massive Delete Vectors that haven't been "physically" merged yet.
D. Transaction Success Rate
* What to look for: Search BE logs for too many versions or too many rowsets.
* The Limit: tablet_max_versions (Default 1000).
* Health Check: If your score is 55, you are safe. If it ever hits 500+, you are at risk of immediate ingestion failure.
Summary Checklist for you:
1. Bump update_compaction_num_threads_per_disk to 4 or 6.
2. Monitor be_running_update_compaction_task_num (Should now hit 8-12).
3. Watch your Merge Commit Load Latency. It should drop from 20s to < 2s once the backlog is cleared.
References
• administration/management/BE_configuration.md
• best_practices/primarykey_table.md
• administration/management/monitoring/metrics.md
References
• administration/management/compaction.md
• knowledge/admin_and_operation/shared_data_compaction.mdMinn Fong
04/24/2026, 5:57 PMupdate_compaction_num_threads_per_disk and compact_threads set to 12. CPU util still averaging 30%. What's the limitation nowRocky
04/24/2026, 5:57 PMupdate_compaction_num_threads_per_disk and compact_threads to 12, but the system is still only running ~3 tasks, you are likely hitting one of the secondary "safety valves" StarRocks uses to prevent compaction from overwhelming the system.
In a Shared-Nothing architecture with Primary Key tables, there are three specific areas where your "tasks < 3" bottleneck is likely hiding:
1. The "Permit" System (total_permits_for_compaction_score)
StarRocks uses a permit system to decide if it can afford to start a new compaction task. Every tablet has a compaction score. When a task starts, it "consumes" a number of permits equal to its score.
* The Config: total_permits_for_compaction_score (Default: 100)
* The Math: If your tablets have an average score of 30, then 3 tasks consume 90 permits. If the 4th tablet has a score of 15, the BE will refuse to start it because 90 + 15 > 100.
* Why it's there: To prevent a few extremely "unhealthy" tablets (high score) from spawning many tasks that crash the BE.
* Fix: Increase this to 500 or 1000 to allow more simultaneous "medium-score" tasks.
sql
UPDATE information_schema.be_configs SET VALUE = '1000' WHERE NAME = 'total_permits_for_compaction_score';
2. Disk Concurrency Limit (pindex_major_compaction_limit_per_disk)
Even if you allow 12 threads per disk via the update config, StarRocks has a separate, more global limit on Major Compaction (which Primary Key compaction essentially is) to prevent disk I/O from stalling user queries.
* The Config: pindex_major_compaction_limit_per_disk (Default: 1)
* The Math: If you have 3 data directories (disks) configured on your BE, and this parameter is set to 1, you will never see more than 3 concurrent tasks on that node, regardless of your thread settings.
* Fix: Increase this to match your performance needs (e.g., 4 or 8).
sql
UPDATE information_schema.be_configs SET VALUE = '4' WHERE NAME = 'pindex_major_compaction_limit_per_disk';
3. Memory Reservation (compaction_memory_limit_per_worker)
StarRocks estimates how much memory a compaction task will need. If the sum of these estimates exceeds the total memory allocated for compaction, no new tasks will start.
* The Configs:
* compaction_memory_limit_per_worker (Default: 2GB)
* compaction_max_memory_limit_percent (Default: 100% of process memory)
* The Math: If your BE has 8GB of memory available for compaction, and each worker is "reserving" 2GB, the BE will hard-cap you at 4 workers, even if they aren't actually using that much RAM.
* Fix: Check your BE memory. If you have a large BE, this is rarely the issue. If you are on smaller nodes (e.g., 16GB), lower the per_worker limit slightly (e.g., to 1GB).
──────────
Recommended Next Steps
Run these commands to see which one "unclogs" your worker queue:
1. Release the Permits (Most Likely):
sql
UPDATE information_schema.be_configs SET VALUE = '1000' WHERE NAME = 'total_permits_for_compaction_score';
2. Increase Disk Concurrency:
sql
UPDATE information_schema.be_configs SET VALUE = '4' WHERE NAME = 'pindex_major_compaction_limit_per_disk';
Ingestion Health Indicators (Beyond Score)
As you requested for other health metrics, once you fix the task count, monitor these to ensure you aren't "over-compacting":
1. update_rowset_commit_apply_duration_us: This is the heart of PK table performance. If this stays low (e.g., < 500ms), your compaction is doing its job. If it spikes, your tablets are too fragmented.
2. be_compaction_mem_bytes: Check this in Grafana. If compaction memory usage is flat but tasks are low, you are hitting a thread/permit limit. If it's hitting a ceiling, you're hitting a memory limit.Rocky
04/24/2026, 5:57 PMp50_compaction_score vs max_compaction_score: If your Max is 55 but your P50 is 2, only a few tablets are "hot." You don't need 12 threads for that. If both are ~30, you need higher concurrency (the settings above).
References
• knowledge/admin_and_operation/shared_data_compaction.md
• administration/management/compaction.mdMinn Fong
04/24/2026, 6:01 PMRocky
04/24/2026, 6:01 PMcompact_threads and update_compaction_num_threads_per_disk set to 12 is likely due to a different disk-level throttle that acts as a hard cap.
The Actual Bottleneck: pindex_major_compaction_limit_per_disk
In StarRocks Primary Key tables, the system limits how many "major" compaction tasks (which includes the primary key compaction you are seeing) can run per physical data directory to avoid saturating disk I/O.
* The Parameter: pindex_major_compaction_limit_per_disk
* Default: 1
* The Logic: Total Concurrent Tasks = (Number of Data Directories) * pindex_major_compaction_limit_per_disk
If your BE nodes are configured with 3 data directories (e.g., /data1, /data2, /data3), StarRocks will only allow 3 concurrent tasks total, even if you have 100 idle threads. Since you mentioned seeing exactly 3 tasks, this is almost certainly the limit you are hitting.
The Fix:
You should increase this value. Since your CPU is only at 30% and your EBS volumes are healthy, try increasing it to 4 or 8:
sql
UPDATE information_schema.be_configs
SET VALUE = '4'
WHERE NAME = 'pindex_major_compaction_limit_per_disk';
(If you have 3 disks, this will allow up to 12 concurrent tasks, matching your thread count.)
──────────
Other "Invisible" Limits to Check
If increasing the disk limit doesn't immediately scale the tasks to 12, check these two parameters in your `be_configs`:
1. max_compaction_concurrency:
* Ensure this is set to -1 (default) or at least 12. If someone manually capped this to 3, it will override everything else.
2. compaction_memory_limit_per_worker:
* StarRocks "reserves" memory for each task before starting it. The default is 2GB.
_ If your BE has a strict memory limit, the BE might be refusing to start a 4th task because 4 _ 2GB = 8GB might exceed the allowable compaction memory pool.
_ _Check:* be_compaction_mem_bytes in your metrics. If it’s high, you might need to lower the per-worker reservation to 1GB.
Summary Recommendation
Your hardware has plenty of headroom. To get those 12 threads working:
1. Increase pindex_major_compaction_limit_per_disk to 4.
2. Verify max_compaction_concurrency is -1.
3. Monitor be_running_update_compaction_task_num again. It should now scale up to your compact_threads limit.
References
• administration/management/BE_configuration.md
• best_practices/primarykey_table.mdMinn Fong
04/24/2026, 6:02 PMRocky
04/24/2026, 6:03 PMpindex_major_compaction_limit_per_disk to 3 (4 disks * 3 = 12) is the correct mathematical configuration to align with your compact_threads = 12.
Why you were seeing 3 tasks instead of 4
If you have 4 disks and the limit was set to the default of 1, you should have seen 4 tasks. The fact that you saw 3 suggests one of the following:
1. Data Skew: Your "hot" tablets (those with high compaction scores) might only be residing on 3 of the 4 disks at that moment. StarRocks will not pull a task from Disk D just because Disk A, B, and C are busy.
2. Storage Path Config: Double-check your be.conf for the storage_root_path. Ensure all 4 EBS volumes are explicitly listed and that none have run out of space (StarRocks will stop scheduling tasks to a disk if it hits the capacity_used_total_confirm_limit or is nearly full).
The "Golden Triangle" for PK Compaction
To ensure you actually reach 12 tasks, these three parameters must "agree":
Parameter | Recommended Value | Reason
compact_threads | 12 | The global "ceiling" for the BE.
update_compaction_num_threads_per_disk | 4 (or 3) | Allows the PK thread pool to scale per disk.
pindex_major_compaction_limit_per_disk | 3 | The "concurrency" gatekeeper that prevents disk I/O bottlenecks.
Important Note on Memory:
Since you are pushing for 12 concurrent tasks, watch your BE memory. StarRocks reserves memory for each compaction task.
* Check compaction_memory_limit_per_worker (Default is 2GB).
_ 12 tasks _ 2GB = 24GB of RAM reserved just for compaction.
* If your BEs have less than 32GB-64GB of RAM, the system might refuse to start the 12th task because it would exceed the compaction_max_memory_limit_percent (which is a percentage of your total BE mem_limit).
How to verify it’s working
After applying pindex_major_compaction_limit_per_disk = 3, check the internal metrics:
sql
-- Check how many tasks are actually running now
SHOW PROC '/be_metrics' LIKE '%compaction_task_num%';
You should see be_running_update_compaction_task_num start to climb toward 12. If it still hovers at 3, check the BE log (<http://be.INFO|be.INFO>) for messages containing memory limit or no enough permits, which would indicate the memory reservation is the final hurdle.
References
• administration/management/BE_configuration.md
• administration/management/compaction.md
• best_practices/primarykey_table.md
References
• knowledge/admin_and_operation/shared_data_compaction.md
• administration/management/monitoring/metrics.md
• administration/management/FE_configuration.md
• administration/management/compaction.md
• administration/management/BE_configuration.mdMinn Fong
04/24/2026, 7:08 PMRocky
04/24/2026, 7:08 PMenable_merge_commit: true
* Benefit: Even if your 24 workers flush frequently (to keep latency low), StarRocks will group them into one version. This drastically reduces the compaction score because you generate 1 version per 5-10 seconds instead of 24 versions per flush cycle.
3. Tune the PK "Apply" Workers
Since you are doing upserts, the bottleneck is often not the disk I/O of compaction, but the Apply thread pool that processes the Primary Key index.
* Config: transaction_apply_worker_count (Default: CPU cores)
* If your CPU is at 30%, you have headroom. If you see "slowdown" messages in SHOW PROC '/transactions/<db>/running', increase this to allow more concurrent upsert processing.
4. Adjust Compaction "Frequency" vs "Wait"
In Shared-Nothing architecture, StarRocks won't compact a tablet too frequently by default to save resources.
* update_compaction_per_tablet_min_interval_seconds: Default is 120 (2 minutes).
* If your version count (compaction score) is still high despite large batches, increase this to 300 (5 minutes). This forces the system to wait longer and collect even more versions into a single "Mega-Compaction" task, which is much more efficient for the CPU.
5. Persistent Index (Crucial for Memory)
Ensure your PK table has enable_persistent_index = true.
* At 4k QPS upserts, if the index is in-memory only, your BE memory will grow linearly with the number of unique keys.
* The Persistent Index keeps the mapping on disk (EBS) and only caches the "hot" parts in RAM, which prevents ingestion from crashing the BE as your dataset grows.
Summary Checklist for your Workers:
1. Inserts (50k QPS): Keep the 1.5GB / 5-minute flush. These are "append-only" and very cheap for StarRocks.
2. Upserts (4k QPS): Move to a 256MB / 60-second flush. This prevents giant "Apply" spikes while still being large enough for efficient compaction.
3. Global: Add enable_merge_commit: true to your Stream Load headers to let StarRocks handle the final grouping.
References
• best_practices/primarykey_table.md
• loading/Flink-connector-starrocks.md
• administration/management/compaction.mdRocky
04/24/2026, 7:08 PMMinn Fong
04/24/2026, 7:53 PMRocky
04/24/2026, 7:53 PMomitempty in your Go structs.
When you use omitempty, the field is completely removed from the JSON payload if it is a "zero value." When StarRocks performs a Stream Load and encounters a JSON record where a key is missing, it follows these rules:
1. Nullable Columns: If the column in StarRocks is defined as NULLABLE, StarRocks will automatically fill that column with NULL for the missing key.
2. Default Values: If the column has a DEFAULT value defined in the schema, StarRocks will use that default value instead of NULL when the key is missing.
3. Strict Mode: If the column is NOT NULL and has no default value, the row will typically be filtered out as an error (especially if strict_mode: true is set in your Stream Load headers).
Important Go Implementation Tip
Since you are dealing with nullable rows, be careful with Go's omitempty behavior on primitive types:
* Primitive Types (int, string, bool): omitempty will omit the field if the value is 0, "", or false. This might lead to unintended NULLs in StarRocks if you actually wanted to store a 0 or an empty string.
* *Pointer Types (_int, _string, *bool):* This is the recommended way for nullable columns. If the pointer is nil, the field is omitted (resulting in NULL in StarRocks). If the pointer is &0, the field is included as "field": 0 (resulting in 0 in StarRocks).
Example Go Struct:
go
type User struct {
ID int64 `json:"id"`
// Use pointers for fields that can be NULL in StarRocks
Age *int `json:"age,omitempty"`
Email *string `json:"email,omitempty"`
}
Stream Load Behavior
When StarRocks receives:
{"id": 123} (Age and Email omitted via omitempty)
It internally processes it as:
id | age | email
123 | NULL | NULL
Performance Note
Since you are doing 50k QPS, using omitempty is actually slightly more efficient for your network bandwidth and StarRocks' JSON parser because it reduces the overall payload size compared to sending "field": null for every empty column after column.
Summary
* Compatible? Yes.
* Result? Missing keys → NULL in StarRocks (for nullable columns).
* Best Practice: Use pointers in your Go struct to distinguish between a "Zero Value" (like 0) and a "Null Value."
References
• loading/StreamLoad.md
• loading/Json_loading.md
• sql-reference/sql-statements/loading_unloading/STREAM_LOAD.md