remy.chantenay
08/07/2026, 9:55 AMRocky
08/07/2026, 9:55 AMenable_background_refresh_connector_metadata is true (default). This allows StarRocks to poll the REST catalog periodically (default 10 mins) to refresh the FE's internal manifest cache, keeping queries "local" to the FE for planning.
* Distributed Planning: For tables with massive numbers of manifest files, ensure plan_mode is set to distributed (or auto) to spread the metadata parsing work across your BE/CN nodes.
3. Data Latency & Concurrency Acceleration
* Data Cache (on SSDs): This is non-negotiable for low latency. Map your BE/CN local SSDs to the Data Cache. Since you are using Iceberg, the first query will fetch from remote storage, but subsequent concurrent queries will hit the SSD cache.
* Asynchronous Materialized Views (MV): For "extreme" concurrency (thousands of QPS), raw Iceberg scans might still hit storage bottlenecks. Use StarRocks MVs to pre-aggregate or join Iceberg data into StarRocks' native storage. The Transparent Rewrite feature ensures your users' SQL remains unchanged while StarRocks automatically routes them to the MV.
* Query Queue & Resource Groups: Use StarRocks' Resource Groups to isolate traffic. You can set a concurrency_limit and cpu_core_limit for specific tenants or apps to ensure one heavy user doesn't spike latency for others.
4. Handling Semi-Structured Data
* Native Variant Type: If your Iceberg data contains JSON or dynamic fields, use the new Variant type in 4.1. Unlike the old JSON type, the Variant type in 4.1 is integrated into the vectorized engine, allowing for predicate pushdown and high-performance execution directly on semi-structured Iceberg data.
Next Steps for Brainstorming:
* What is your target QPS and p99 latency requirement?
* Are your queries mostly point-lookups, range scans, or heavy aggregations?
* Do you have specific security requirements (e.g., OAuth2/JWT for the REST catalog)?
References
• data_source/catalog/iceberg/iceberg_catalog.md
• data_source/feature-support-data-lake-analytics.mdremy.chantenay
08/07/2026, 11:16 AMRocky
08/07/2026, 11:22 AMm6a.8xlarge, a 1:5 or 1:8 FE-to-CN ratio is common. Monitor the FE's CPU and Java Heap; if planning latency spikes under load, scale the FEs.
* #2 Shared-Data vs. Shared-Nothing: Validated. Internal benchmarks show Shared-Data (with Data Cache) can be 1.2x faster than Shared-Nothing for data lake queries because it eliminates the overhead of managing local replicas while providing SSD-speed access via the unified Data Cache.
* #3 FE Observer Nodes: Validated. Use 3 Followers (for HA/Raft) and then scale with Observers to handle the read-only REST API and SQL planning traffic without impacting the Leader's metadata operations.
* #4 Prepared Statements: Essential for high-concurrency "point lookups" or simple queries. In 4.1, this drastically reduces the FE overhead per request.
* #5 Data Spill: enable_spill is a safety net. For an SLO < 3s, you should aim to avoid spilling. Use Resource Groups to kill queries that exceed memory limits rather than letting them spill to disk, as disk I/O on m6a (EBS) will likely break your 3s SLO.
* #6 & #7 Parallelism & Planning:
* Set plan_mode = 'distributed' for your Iceberg tables if they have thousands of manifest files.
* Tuning connector_io_tasks_per_scan_operator is critical; however, in 4.1, enable_connector_adaptive_io_tasks (default true) usually handles this. Only manual-tune if you see uneven BE CPU usage.
* #8 Lean Read-Path: This likely refers to minimizing "write-on-read" overhead.
* Recommendation: Disable enable_profile and enable_audit_log (or set to SLOW_QUERY only) in production to save CPU cycles.
* DataCache Variants: Experiment with enable_datacache_async_populate_mode. Setting this to false (synchronous) ensures data is cached on the first read, which is better for "warming" but adds latency to the very first query.
──────────
2. Missing "Heavy Artillery" for 7-10 Table Joins
Given your join-heavy workload, these three 4.1 features are arguably more impactful than the ones above:
A. Asynchronous Materialized Views (The "Silver Bullet")
For 7-10 table joins on Iceberg, raw scans will eventually hit AWS S3/REST API throughput limits.
* Strategy: Create an Async MV in StarRocks that pre-joins these tables.
* Transparent Rewrite: Your users still query the Iceberg catalog, but StarRocks' optimizer automatically rewrites the query to hit the local, pre-joined MV.
* Benefit: Reduces 10 remote scans to 1 local SSD scan. Latency will drop from seconds to milliseconds.
B. Global Runtime Filters (RF)
In massive joins, RFs are the primary mechanism StarRocks uses to prune data early.
* Tip: Ensure enable_global_runtime_filter = true.
* Experiment: Check your query profile for RuntimeFilterBloomFilter and RuntimeFilterMinMax. If your dimension tables are small, ensure they are being broadcast to build these filters for the large fact table scans.
C. The New "Variant" Type (if applicable)
If your Iceberg tables contain JSON or semi-structured data, the 4.1 Variant type allows for high-performance vectorized execution on dynamic columns, which was a bottleneck in 3.x.
──────────
3. Iceberg REST Catalog Specifics (4.1)
* Vended Credential Caching: 4.1 introduces optimized caching for vended credentials. Ensure your catalog is configured with aws.s3.use_vended_credentials = true. This prevents the FE from hammered the REST API for every single query's file access.Rocky
08/07/2026, 11:22 AMbackground_refresh_metadata_interval_millis to something like 300000 (5 mins). This ensures the FE has the latest manifest list in memory, keeping planning fast.
4. Hardware/OS Tuning for m6a.8xlarge
* Network: These instances have up to 25Gbps. Ensure your Iceberg storage (S3) is in the same region/AZ.
* Local SSD: m6a instances are EBS-only. For the Data Cache, ensure you are using GP3 volumes with high provisioned IOPS (at least 10k-16k) or move to m6id instances which have local NVMe for the cache. EBS latency for Data Cache can be a bottleneck for sub-3s SLOs.
Recommended Next Experiment:
Compare a raw Iceberg 10-table join vs. a Transparently Rewritten MV join. This usually yields the biggest performance jump for your specific profile-heavy concurrent traffic.
References
• data_source/catalog/iceberg/iceberg_catalog.md
• using_starrocks/async_mv/use_cases/data_lake_query_acceleration_with_materialized_views.md
• sql-reference/System_variable.md
• data_source/data_cache.md
References
• using_starrocks/async_mv/use_cases/data_lake_query_acceleration_with_materialized_views.md
• using_starrocks/async_mv/use_cases/query_rewrite_with_materialized_views.mdremy.chantenay
08/07/2026, 1:09 PMRocky
08/07/2026, 1:11 PMconcurrency_limit: This is critical for your SLO. If you expect 50 users but your BEs can only handle 20 heavy 10-table joins concurrently, setting this to 20 will trigger the Query Queue. It’s better for a user to wait 1 second in a queue than for all 50 queries to contend for CPU and fail the 3s SLO.
* cpu_weight vs exclusive_cpu_cores:
* Use cpu_weight for "Fair Sharing." If group A and B both have weight 100, they split CPU 50/50 when busy.
_ Use exclusive_cpu_cores (Hard Isolation) if you have a "Gold" tenant that _must* have 16 cores available regardless of other traffic.
* big_query_mem_limit: Set this to prevent a single "rogue" query (e.g., a massive join without filters) from eating the entire group's memory. If a query hits this, it’s killed or spilled, protecting the other concurrent "small" queries.
2. Memory Limits: query_mem_limit vs. exec_mem_limit
In the StarRocks Pipeline Engine (v3.x and v4.1), query_mem_limit is the modern session variable.
* How it works: It sets the memory limit for a single query on a single BE node.
* The Relation: You might see exec_mem_limit in older docs or logs; in 4.1, query_mem_limit is the preferred alias. If both are set, query_mem_limit usually takes precedence in the pipeline engine.
* Best Practice: Set query_mem_limit to roughly Resource Group Mem Limit / Expected Concurrency. For example, if a group has 40GB and you expect 4 concurrent queries, set query_mem_limit = 10G.
3. Instance Types: Why NVMe (m6id) is the Game Changer
You mentioned m6a.8xlarge (EBS-only). For a 3s SLO on 10-table joins, I strongly recommend moving to m6id or r6id (local NVMe).
The "Data Cache" (Block Cache)
StarRocks 4.1 uses a Block Cache that splits Iceberg files into small chunks (default 1MB).
* The EBS Bottleneck: EBS volumes (even GP3) have higher latency (~ms) and limited IOPS compared to local NVMe (~μs). In a 10-table join, the engine is doing massive amounts of random reads across these blocks.
* NVMe Advantage: Local NVMe provides hundreds of thousands of IOPS and sub-millisecond latency. This is the difference between a join finishing in 1.5s (NVMe) vs. 5s (EBS) when the cache is being hammered by 20 concurrent threads.
The "Other" Caches
When you use NVMe for the Data Cache, you are actually benefiting from three layers:
1. Page Cache (In-Memory): StarRocks uses a portion of BE RAM to cache the most frequently accessed blocks.
2. Data Cache (Local NVMe): This is where the 1MB Iceberg blocks live. This is persistent across BE restarts in 4.1.
3. Metadata Cache (Manifest Cache): Managed by the FE. It stores Iceberg manifest files. NVMe doesn't affect this directly (it's in RAM), but fast BEs mean the FE spends less time waiting for I/O reports.
4. Refining Your Experiment Treatments
For your "Lean Read-Path" experiment (#8), consider these specific 4.1 "treatments" for the Data Cache:
* Treatment A (Strict Performance):
* enable_datacache_async_populate_mode = true (Don't slow down the first query to write to cache).
* datacache_eviction_policy = 'SLRU' (Better for preventing "scan-heavy" queries from evicting "point-lookups").
* Treatment B (Aggressive Warming):
* populate_datacache_mode = 'always' (Force every scan to cache, regardless of StarRocks' internal cost-model).
* enable_datacache_async_populate_mode = false (First query will be slower, but subsequent ones are guaranteed hits).
* Treatment C (IO Resilience):Rocky
08/07/2026, 1:11 PMenable_datacache_io_adaptor = true (If NVMe latency spikes, StarRocks automatically switches to fetching from S3 to keep the query moving).
Rocky's Pro Tip: If cost is truly not an issue, try r6id.8xlarge. The extra RAM will allow a larger Page Cache (In-Memory), which is the only way to get sub-second responses on complex joins across Iceberg.
References
• data_source/data_cache.md
• administration/management/resource_management/resource_group.md
• administration/management/resource_management/Memory_management.md
• sql-reference/System_variable.md
• administration/management/resource_management/query_queues.md
• data_source/data_cache_troubleshooting.md
References
• data_source/data_cache.md
• data_source/data_cache_troubleshooting.md
• sql-reference/System_variable.md
• deployment/shared_data/feature-support-shared-data.md
• using_starrocks/caching/block_cache.mdremy.chantenay
08/07/2026, 2:56 PMconcurrency_limit and query_mem_limitRocky
08/07/2026, 2:57 PMconcurrency_limit to a safe number (e.g., 10) and query_mem_limit to (BE_Total_RAM * 0.8) / 10.
2. The Stressor: Use a tool (like JMeter or k6) to send a steady stream of your 10-table joins at 3x the baseline concurrency.
3. The Variable: Gradually increase the Resource Group's concurrency_limit while monitoring the QueryQueue metrics and BE CPU/Memory Usage.
1. Experiment: "Queue Wait vs. Execution Speed"
In 4.1, the Leader FE manages the query queue centrally. This experiment determines if your 3s SLO is better served by queries waiting in line or queries running with less memory.
* Treatment A (Strict Queuing): Set concurrency_limit = 8. Queries will wait in the FE queue. Measure total latency (Wait Time + Execution Time).
* Treatment B (High Concurrency / Low Memory): Set concurrency_limit = 24 but lower the session query_mem_limit to a level that forces StarRocks to use smaller Hash Tables.
* Treatment C (The "Big Query" Circuit Breaker): Use the 4.1 big_query_mem_limit within the Resource Group. Set it to 20% of BE RAM. If a join query tries to build a hash table larger than this, it is killed instantly.
What to look for:
* The "Queue Sweet Spot": At what point does Wait Time + Execution Time stay under 3s? Often, a query that waits 0.5s in a queue and runs in 1.5s is more stable than a query that starts immediately but takes 4s due to resource contention.
* Hash Join Memory Hits: Check EXPLAIN ANALYZE or the query profile. If query_mem_limit is too low, joins might fallback to "Serialized" or "Spill" modes. Avoid any treatment where spilling occurs, as it will break your 3s SLO.
2. Experiment: query_mem_limit vs. big_query_mem_limit
There is a nuanced difference here that is worth testing:
* query_mem_limit (Session Variable): A "soft" limit that triggers a warning or error at the operator level.
* big_query_mem_limit (Resource Group Property): A "hard" governor. If a query hits this, it’s killed to save the group.
Suggested Test: Set query_mem_limit higher than big_query_mem_limit. This allows individual queries to be "ambitious" with memory, but ensures the Resource Group kills them if they threaten the BE's stability.
3. The "Cache-Aware" Concurrency Test (m6id NVMe)
If you move to m6id (NVMe), your concurrency_limit can likely be much higher.
* The Experiment: Run the same 10-table joins concurrently. Monitor the Data Cache Hit Rate and NVMe Disk IOPS.
* Why: With EBS, high concurrency leads to "IO Wait" as multiple threads fight for the limited EBS bandwidth. With NVMe, you want to find the concurrency level where the Local Data Cache starts to get evicted too quickly (LRU thrashing). If your working set for the joins is 100GB and your NVMe is 200GB, you can handle high concurrency. If the working set is 500GB, you need to tighten the concurrency_limit to prevent the cache from constantly reloading from S3.
Recommended Metric Monitoring
During these experiments, watch these specific 4.1 internal metrics:
* `starrocks_fe_query_queue_pending_queries`: Are queries piling up?
* `starrocks_be_resource_group_cpu_limit_ratio`: Is the Resource Group actually throttling CPU?
* `starrocks_be_data_cache_read_throughput`: Is your NVMe/EBS hitting a ceiling?
Summary for your Brainstorm:Rocky
08/07/2026, 2:57 PMremy.chantenay
08/07/2026, 3:32 PMRocky
08/07/2026, 3:33 PMstarrocks_fe_query_queue_pending: The current number of queries waiting in the global queue. If this is consistently > 0, your cluster is at capacity.
* starrocks_fe_resource_group_query_queue_pending: (Use the name label) This tells you which specific resource group is hitting its limit. This is vital if you have different SLAs for different users.
* starrocks_fe_query_queue_timeout: The number of queries that were killed because they waited in the queue longer than query_queue_pending_timeout_second. If this is > 0, your users are seeing errors.
* starrocks_fe_query_err_cnt: Monitor this alongside queue metrics to ensure queuing isn't causing upstream application timeouts.
2. SQL Commands (Best for Real-time Debugging)
When you notice latency spiking during a test, run these:
* SHOW RUNNING QUERIES;: This is the most detailed view in v3.1+. It shows:
* `State`: PENDING (in queue) vs RUNNING.
* `PendingTimeout`: When the query will "give up" and error out.
* `ResourceGroupId`: Which group is responsible for the queue.
* SHOW PROCESSLIST;: Check the IsPending column. If it's true, the query has been planned but is waiting for resources to start execution.
* SHOW PROC '/backends';: Check the NumRunningQueries column for each BE. If one BE has significantly more queries than others, you might have a data skew issue or an unbalanced FE-to-BE mapping.
3. FE Audit Log (Best for SLO Analysis)
To calculate your 3s SLO accurately, you must differentiate between Execution Time and Wait Time.
* PendingTimeMs: This field in fe.audit.log tells you exactly how many milliseconds the query sat in the queue.
* QueryTimeMs: This is the Total Time (Wait + Execution).
The Calculation:
If QueryTimeMs is 4000ms and PendingTimeMs is 2500ms, your StarRocks engine is actually very fast (1.5s execution), but your cluster is under-provisioned for the concurrent load. This indicates you should Scale Out (Add BEs) or Increase concurrency_limit if memory allows.
Summary Checklist for your Experiments:
Goal | Metric to Watch
Avoid User Errors | starrocks_fe_query_queue_timeout (Keep at 0)
Check Group Pressure | starrocks_fe_resource_group_query_queue_pending
Optimize SLO | PendingTimeMs vs QueryTimeMs in Audit Logs
Identify Bottlenecks | NumRunningQueries in SHOW PROC '/backends'
Rocky's Tip: If you see PendingTimeMs increasing while CpuUsedPct (from SHOW PROC '/backends') is low, it means your concurrency_limit is set too conservatively—you are queuing queries even though the hardware has room to work!
References
• administration/management/resource_management/query_queues.md
• administration/management/monitoring/metrics.md
• administration/management/resource_management/resource_group.mdremy.chantenay
08/07/2026, 3:54 PMRocky
08/07/2026, 3:54 PMRocky
08/07/2026, 3:54 PMremy.chantenay
08/07/2026, 7:57 PMRocky
08/07/2026, 7:57 PMstarrocks_fe_resource_group_query_queue_pending: Tracks if queries are stacking up in the FE before execution starts.
* resource_group_running_queries: Actual concurrent query count per BE (cross-reference with concurrency_limit).
* starrocks_fe_query_resource_group_latency: Monitor the 99_quantile to see exactly when latency breaks your 3s SLO.
* resource_group_cpu_limit_ratio: Tells you if the Resource Group is actually hitting its CPU ceiling or if it’s idling.
* resource_group_mem_inuse_bytes: Check if memory usage is nearing the Resource Group’s mem_limit.
2. Queue Wait vs. Execution Speed
* PendingTimeMs (Audit Log): The "hidden" latency. If this is > 500ms, your queue is becoming a bottleneck.
* QueryTimeMs (Audit Log): Total end-to-end time. Compare this with PendingTimeMs to see if the engine is fast but the queue is full.
* starrocks_fe_resource_group_query_queue_timeout: If this count increases, your query_queue_pending_timeout_second is too short or the cluster is overloaded.
* starrocks_fe_query_resource_group_err: Watch for spikes in errors as concurrency increases (indicates resource exhaustion).
3. query_mem_limit vs. big_query_mem_limit
* resource_group_bigquery_count: Number of queries killed for exceeding the "hard" big_query_mem_limit.
* resource_group_concurrency_overflow_count: Frequency of queries being rejected before entering the queue.
* SpillWriteBytes / SpillReadBytes (Query Profile): If these are non-zero, your query_mem_limit is too low, forcing slow disk I/O for joins.
* starrocks_be_mem_usage_pct: Overall BE memory health to ensure the Resource Group isn't starving the rest of the system.
4. Cache-Aware Concurrency (m6id NVMe)
* block_cache_hit_rate: Should ideally be > 0.80 for repetitive 10-table joins.
* DataCacheReadBytes vs. BytesRead: If DataCacheReadBytes is low compared to BytesRead, you are pulling too much from S3 (Cache Miss).
* fslib_read_io_latency: Specifically monitors the NVMe drive latency. If this spikes, you are saturating the local disk IOPS.
* fslib_star_cache_data_disk_size: The "Fullness" of your NVMe cache. If it's always at 100%, you are likely thrashing (evicting data as fast as you load it).
5. MV Refresh Nuances (Shared-Data)
* starrocks_fe_mv_refresh_total: Count of successful vs. failed MV refreshes.
* starrocks_fe_mv_refresh_latency: Time taken to refresh the MV from the Iceberg REST catalog.
* starrocks_be_data_cache_write_throughput: Monitor this during an MV refresh to see how much "Write" pressure it puts on your NVMe cache.
References
• best_practices/query_tuning/query_profile_operator_metrics.md
• sql-reference/System_variable.md
• administration/management/monitoring/metrics.md
• administration/management/resource_management/spill_to_disk.mdremy.chantenay
08/07/2026, 8:06 PMRocky
08/07/2026, 8:07 PMget_query_profile()) for deep-dives into individual SQL behavior.
#1 – Cluster Provisioning (Scaling)
* starrocks_be_cpu_utilization: Ensure even load across new nodes; look for "hot" nodes indicating skew.
* starrocks_fe_query_latency (P99/P95): The primary success metric for scaling.
* starrocks_fe_query_total (QPS): Verifies if the cluster can handle more concurrent requests after scaling.
* starrocks_be_mem_usage_pct: Tracks if scaling up (larger nodes) provides enough headroom for your 10-table joins.
#2 – Shared-Nothing vs. Shared-Data
* block_cache_hit_rate: Crucial for Shared-Data; if this is low (<80%), you are bottlenecked by S3/Object Store.
* starrocks_be_data_cache_read_throughput: Measures the speed of the NVMe cache in Shared-Data mode.
* s3_get_object_latency: Monitor this in Shared-Data to identify external cloud provider spikes.
* starrocks_be_disk_read_latency: Compare this (Shared-Nothing local disk) against S3 latency to justify the model choice.
#3 – FE Observer Nodes
* starrocks_fe_query_total (per node): Verify that your load balancer is actually distributing traffic to Observers.
* starrocks_fe_jvm_gc_sec: High GC on Follower nodes indicates Raft consensus stress; Observers should show lower/more stable GC.
* starrocks_fe_connection_total: Ensures connection limits aren't being hit on the Leader FE.
* starrocks_fe_edit_log_write_latency: Ensures adding nodes doesn't slow down metadata synchronization.
#4 – Prepared Statements
* PlanTimeMs (Audit Log): This should drop significantly (often <1ms) as the FE reuses plans.
* starrocks_fe_query_latency_plan: Prometheus metric to see the aggregate reduction in planning overhead.
* FE CPU Utilization: Should decrease at high concurrency due to reduced parsing/binding cycles.
* Parser time (Query Profile): Specifically look for the parser phase to disappear or minimize.
#5 – Data Spill
* SpillWriteBytes / SpillReadBytes: If > 0, the query successfully spilled to disk instead of crashing with OOM.
* SpillWriteDuration: The latency "penalty" paid for spilling.
* starrocks_be_process_mem_usage: Should remain stable (flat-topped) during heavy joins rather than spiking and crashing.
* starrocks_be_query_err_cnt: Specifically watch for a decrease in "Memory Limit Exceeded" errors.
#6 – Query Parallelism (pipeline_dop)
* DegreeOfParallelism (Query Profile): Confirms the query is actually running with the intended pipeline_dop.
* ActiveTime vs ScheduleTime: If ScheduleTime is high, your pipeline_dop is too high, causing CPU context-switching overhead.
* ScanTime (Scan Operator): Higher DOP should reduce this for Iceberg scans, up to the limit of S3 throughput.
* starrocks_be_cpu_utilization: Watch for 100% saturation; if hit, increasing DOP further will degrade performance.
#7 – Distributed Planning
* DeployTime (Query Profile): Measures the time the FE takes to send fragments to BEs.
* PlanTimeMs: For Iceberg tables with thousands of manifest files, distributed planning should significantly lower this.
* DeployDataSize: Monitors the size of the metadata being sent; if too large, it can cause network jitter.
* FE Network Out: High metadata traffic can sometimes bottleneck the FE NIC during distributed planning.
#8 – Lean Read-Path (Optimization)
* QueryTimeMs (P99): The end-to-end impact of stripping auditing/profiling side effects.
* DataCacheReadBytes: Essential for comparing the three cache treatment variants (to see if "Lean" impacts cache efficiency).
* starrocks_fe_audit_log_latency: If using a lean path that reduces audit logging, monitor this to see the performance gain.Rocky
08/07/2026, 8:07 PMCollect Profile Time: Specifically check if asynchronous profile collection reduces the user-perceived query latency.
References
• administration/management/monitoring/metrics.md
• best_practices/query_tuning/query_profile_operator_metrics.md