StarRocks关于ConcurrentModificationException 问题的解决
背景
本文基于 StarRocks 3.1.7
目前在基于Starrocks做一些数据分析的操作(主要是做一些简单的查询),同事遇到了一些并发的问题:
ontent:2024-11-27 07:04:34,048 WARN (starrocks-mysql-nio-pool-214933|3593819) [StmtExecutor.execute():643] execute Exception, sql SELECT distinct(id) FROM `db`.`table` WHERE col1='xxx' AND col2='xxx'
java.util.ConcurrentModificationException: nullat java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:719) ~[?:?]at java.util.LinkedHashMap$LinkedValueIterator.next(LinkedHashMap.java:746) ~[?:?]at com.starrocks.sql.optimizer.statistics.StatisticsCalcUtils.deltaRows(StatisticsCalcUtils.java:176) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.statistics.StatisticsCalcUtils.getTableRowCount(StatisticsCalcUtils.java:114) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.statistics.StatisticsCalculator.computeOlapScanNode(StatisticsCalculator.java:257) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.statistics.StatisticsCalculator.visitLogicalOlapScan(StatisticsCalculator.java:225) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.statistics.StatisticsCalculator.visitLogicalOlapScan(StatisticsCalculator.java:161) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.operator.logical.LogicalOlapScanOperator.accept(LogicalOlapScanOperator.java:149) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.statistics.StatisticsCalculator.estimatorStats(StatisticsCalculator.java:177) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.task.DeriveStatsTask.execute(DeriveStatsTask.java:57) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.task.SeriallyTaskScheduler.executeTasks(SeriallyTaskScheduler.java:69) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.Optimizer.memoOptimize(Optimizer.java:595) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.Optimizer.optimizeByCost(Optimizer.java:201) ~[starrocks-fe.jar:?]at com.starrocks.sql.optimizer.Optimizer.optimize(Optimizer.java:134) ~[starrocks-fe.jar:?]at com.starrocks.sql.StatementPlanner.createQueryPlan(StatementPlanner.java:146) ~[starrocks-fe.jar:?]at com.starrocks.sql.StatementPlanner.planQuery(StatementPlanner.java:121) ~[starrocks-fe.jar:?]at com.starrocks.sql.StatementPlanner.plan(StatementPlanner.java:92) ~[starrocks-fe.jar:?]at com.starrocks.sql.StatementPlanner.plan(StatementPlanner.java:61) ~[starrocks-fe.jar:?]at com.starrocks.qe.StmtExecutor.execute(StmtExecutor.java:456) ~[starrocks-fe.jar:?]at com.starrocks.qe.ConnectProcessor.handleQuery(ConnectProcessor.java:392) ~[starrocks-fe.jar:?]at com.starrocks.qe.ConnectProcessor.dispatch(ConnectProcessor.java:506) ~[starrocks-fe.jar:?]at com.starrocks.qe.ConnectProcessor.processOnce(ConnectProcessor.java:782) ~[starrocks-fe.jar:?]at com.starrocks.mysql.nio.ReadListener.lambda$handleEvent$0(ReadListener.java:69) ~[starrocks-fe.jar:?]at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]at java.lang.Thread.run(Thread.java:829) ~[?:?]
涉及到的表如下:
CREATE TABLE `table` (`id` bigint(20) NOT NULL ,`create_date` datetime NOT NULL ,`col1` varchar(64) NOT NULL ,`col2` varchar(20) NOT NULL
) ENGINE = OLAP PRIMARY KEY(`create_date`, `id`
) COMMENT ""
PARTITION BY date_trunc('month', create_date) DISTRIBUTED BY HASH(`id`) PROPERTIES ("replication_num" = "3", "in_memory" = "false", "enable_persistent_index" = "true", "replicated_storage" = "true", "partition_live_number" = "18", "compression" = "LZ4");
结论
StarRocks 对分区带有TTL的表,会后台启动线程轮询的去删除分区,轮询的间隔受到 dynamic_partition_check_interval_seconds
控制,
然而在查询的时候, Starrocks会做语法解析,以及基于CBO的优化,在这期间会统计涉及到的表的分区信息统计,而此时恰好遇到了后台线程的分区删除,导致了ConcurrentModificationException
并发异常。
目前可以参考这个issue ConcurrentModificationException when query during drop partition,以及 增大 dynamic_partition_check_interval_seconds(目前是10分钟) 这个参数来降低这种冲突的概率。
分析
这里主要涉及到两个部分:
一个部分是查询部分(主要是StmtExecutor.execute),一个是后台清理分区部分(DynamicPartitionScheduler)
查询部分
每个SQL查询都会经过 StmtExecutor.execute
方法,进而生成物理执行计划,而在生成物理执行计划的阶段,会经过Optimizer
阶段,这个阶段由于默认情况下是基于CBO的优化,所以会统计涉及的表所扫描的数据量,最终会走到 StatisticsCalcUtils.deltaRows
方法:
private static long deltaRows(Table table, long totalRowCount) {long tblRowCount = 0L;for (Partition partition : table.getPartitions()) {long partitionRowCount;TableStatistic tableStatistic = GlobalStateMgr.getCurrentStatisticStorage().getTableStatistic(table.getId(), partition.getId());if (tableStatistic.equals(TableStatistic.unknown())) {partitionRowCount = partition.getRowCount();} else {partitionRowCount = tableStatistic.getRowCount();}tblRowCount += partitionRowCount;}if (tblRowCount < totalRowCount) {return Math.max(1, (totalRowCount - tblRowCount) / table.getPartitions().size());} else {return 0;}}
这里会对 table.getPartitions
进行 迭代,也就是OlapTable的 idToPartition.valus
进行迭代, 注意 idToPartition
是HashMap
类型的,
总体的流程如下:
StmtExecutor.execute||\/
StatementPlanner.plan||\/
StatementPlanner.planQuery||\/
StatementPlanner.createQueryPlan||\/
Optimizer.optimize||\/
Optimizer.optimizeByCost||\/
Optimizer.memoOptimize||\/
SeriallyTaskScheduler.executeTasks||\/
DeriveStatsTask.execute||\/
StatisticsCalculator.estimatorStats||\/
StatisticsCalculator.computeOlapScanNode||\/
StatisticsCalcUtils.getTableRowCount||\/
StatisticsCalcUtils.deltaRows
后台清理部分
对于这种带有TTL的分区表来说,会有 DynamicPartitionScheduler
这个后台线程进行分区的删除。具体代码见:
protected void runAfterCatalogReady() {if (!initialize) {// check Dynamic Partition tables only when FE startinitDynamicPartitionTable();}setInterval(Config.dynamic_partition_check_interval_seconds * 1000L);if (Config.dynamic_partition_enable) {executeDynamicPartition();}executePartitionTimeToLive();}
其中删除分区的频率就是由 Config.dynamic_partition_check_interval_seconds
也就是dynamic_partition_check_interval_seconds
来决定的,
其中executeDynamicPartition
方法就是执行分区删除,具体数据流如下 :
executeDynamicPartition||\/
executeDynamicPartitionForTable||\/
getDropPartitionClause||\/
GlobalStateMgr.getCurrentState().dropPartition(db, olapTable, dropPartitionClause);||\/
olapTable.dropPartition(db.getId(), partitionName, clause.isForceDrop());||\/
idToPartition.remove(partition.getId());
其中 在 executeDynamicPartitionForTable
中 RangePartitionInfo rangePartitionInfo = (RangePartitionInfo) olapTable.getPartitionInfo();
会根据PartitionInfo
的信息来进行判断,只有 RangePartitionInfo
类型支持partition TTL删除,也就是Expression partitioning (recommended) 和Dynamic partitioning支持.
在最后的idToPartition.remove(partition.getId())
中就会删除正在进行查询迭代的idToPartition.values
,就是导致并发问题
相关文章:

StarRocks关于ConcurrentModificationException 问题的解决
背景 本文基于 StarRocks 3.1.7 目前在基于Starrocks做一些数据分析的操作(主要是做一些简单的查询),同事遇到了一些并发的问题: ontent:2024-11-27 07:04:34,048 WARN (starrocks-mysql-nio-pool-214933|3593819) [StmtExecutor.execute():643] execute Exceptio…...

网络安全防护指南:筑牢网络安全防线(5/10)
一、网络安全的基本概念 (一)网络的定义 网络是指由计算机或者其他信息终端及相关设备组成的按照一定的规则和程序对信息收集、存储、传输、交换、处理的系统。在当今数字化时代,网络已经成为人们生活和工作中不可或缺的一部分。它连接了世…...

替代FTP最佳跨网文件传输解决方案——FileLink
在传统的企业文件传输中,FTP(文件传输协议)曾因其便捷性和高效性被广泛应用。然而,其固有的安全漏洞、对大文件传输支持的局限性、易受网络攻击等问题,已逐渐暴露出FTP在现代企业环境下的不足。针对这一问题࿰…...

Cesium在vue2中的引入和注意事项
在Vue2中,可以使用npm包管理工具来安装Cesium,并通过import语句将其引入到项目中。下面是在Vue2中引入Cesium的步骤和注意事项: 步骤: 首先,打开终端并进入Vue项目的根目录。 运行以下命令来安装Cesium: …...

CentOS 9 配置静态IP
文章目录 1_问题原因2_nmcli 配置静态IP3_使用配置文件固定IP4_重启后存在的问题5_nmcli 补充 1_问题原因 CentOS 7 于 2014年6月发布,基于 RHEL 7,并在 2024年6月30日 结束维护。 CentOS 9 作为目前的最新版本,今天闲来闲来无事下载下来后…...

深入解析 Webhook:从原理到实践的全面指南
1. 引言 1.1 什么是 Webhook? Webhook 是一种基于 HTTP 回调的轻量级通信机制,它允许一个系统实时向另一个系统发送数据。当特定事件发生时,Webhook 会主动向指定的 URL 发送 HTTP 请求,通常携带事件相关的数据。这种被动接收通…...

基于springboot+vue实现的创新创业学分管理系统 (源码+L文+ppt)4-111
4 系统总体设计 4.1系统功能结构设计图 根据需求说明设计系统各功能模块。采用模块化设计方法实现一个复杂结构进行简化,分成一个个小的容易解决的板块,然后再将小的板块继续分化成功能单一的更小模块。模块化设计方法使测试调试、维护更容易ÿ…...

如何高效地架构一个Java项目
引言 Java是企业级应用开发的主流语言之一,而我们作为使用Java语言的程序员,职称有初级、中级、高级、资深、经理、架构,但我们往往只是慢慢通过经验的积累迭代了自己的等级,如果没有保持学习的习惯,大多数程序员会停留…...

Scala的模式匹配(8)
package hfdobject Test35_1 { //需求:现在有一个数组Array(1,2,3,4)。我希望能定义三个变量,他们的值分别是数组中的第1,2,3个元素的值 def main(args: Array[String]): Unit {val arr Array(1,2,3,4,5)//第一个元素的值:arr(0…...

nodejs30: CSS 剪辑路径clip-path导致伪元素不可见问题及解决方法
相关问题 应用圆角裁剪时无法显示::after 取消clip-path设置: 完整问题代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, i…...

Git分布式版本控制工具 Git基本概念、Git工作流程、Git常用命令、Git远程仓库、IDEA操作Git
目录 1.Git基本概念 1.1 概述 1.1.1 开发中的实际场景 1.1.2 版本控制器的方式 1.1.2.1 集中式版本控制工具(SVN) 1.1.2.2 分布式版本控制工具(Git) 2.概述git工作流程 3.Git常用命令 3.1 Git环境配置 3.1.1 下载与安装 3.1.2 基本配置 3.1.3 为常用指令配置别名&…...

十,[极客大挑战 2019]Secret File1
点击进入靶场 查看源代码 有个显眼的紫色文件夹,点击 点击secret看看 既然这样,那就回去查看源代码吧 好像没什么用 抓个包 得到一个文件名 404 如果包含"../"、"tp"、"input"或"data",则输出"…...

Android 获取数字键盘和输入类型
在Android中,获取数字键盘可以通过为EditText设置输入类型为number或numberPassword来实现。以下是一个简单的例子: <!-- 在XML布局文件中 --> <EditText android:id"id/editTextNumber" android:layout_width"match_parent…...

8. 一分钟读懂“代理模式”
8.1 模式介绍 代理模式是一种结构型设计模式,它通过提供一个代理对象来替代对另一个对象(真实对象)的访问。代理对象与真实对象实现相同的接口,并通过代理类对真实对象的访问进行控制,可以在调用前后执行附加操作&…...

【实战攻略】如何从零开始快速实现深度学习新想法?——四步走战略
标题 【实战攻略】如何从零开始快速实现深度学习新想法?——四步走战略 【核心结论】 通过四步走战略,即找到baseline论文、深入baseline代码、搭建自己的pipeline、融入核心算法,新手也能快速实现深度学习新想法。 【通俗解释࿰…...

Creating Server TCP listening socket *:6379: bind: No error
启动redis报错:Creating Server TCP listening socket *:6379: bind: No error 解决方案: 1、直接在命令行中输入 redis-cli.exe 2、输入shutdown,关闭 3、输exit,退出 4、重新输入 redis-server.exe redis.windows.conf&…...

Go热加载工具air-使用说明-win11问题解决指南
写web程序 每次都要ctrlc 然后go run .非常但疼 用一下这个热加载工具air Live reload for Go apps 贴个github地址:https://github.com/air-verse/air 1. go版本1.23先install一下 go install github.com/air-verse/airlatest下载完发现输入air windows还是报…...

华为HarmonyOS 让应用快速拥有账号能力 -- 2 获取用户头像昵称
场景介绍 如应用需要完善用户头像昵称信息,可使用Account Kit提供的头像昵称授权能力,用户允许应用获取头像昵称后,可快速完成个人信息填写。以下只针对Account kit提供的头像昵称授权能力进行介绍,若要获取头像还可通过场景化控…...

oracle表迁移至postgre
第一步: 导出表结构 进入脚本 第二步: 删除spool相关和prompt相关(不需要表空间的情况下) 类似以下语句 第三步: 修改数据类型 VARCHAR2 --> VARCHAR VARCHAR2(200 CHAR) --> VARCHAR(200) NUMBER(10,2) --> numeric(10,2…...

【PlantUML系列】类图(一)
目录 一、类 二、接口 三、抽象类 四、泛型类 五、类之间的关系 六、添加注释 七、包图 八、皮肤参数 一、类 使用class关键字定义类,类名后跟大括号,声明类的属性和方法。 属性:格式为{visibility} attributeName : AttributeType…...

Unity AssetBundles(AB包)
目录 前言 AB包是什么 AB包有什么作用 1.相对Resources下的资源AB包更好管理资源 2.减小包体大小 3.热更新 官方提供的打包工具:Asset Bundle Browser AB包资源加载 AB包资源管理模块代码 前言 在现代游戏开发中,资源管理是一项至关重要的任务。随着游戏内容…...

腾讯面试:如何解决哈希冲突?
我们面试时经常被问到HashMap是怎么解决哈希冲突的,很多同学对其含糊其词、一知半解。因此小编对相关知识进行了总结,希望帮助读者加深对其理解。 哈希表就是通过散列函数将键映射到定值,简单来说就是一个键对应一个值。 而通过散列函数映射…...

【动手学运动规划】 4.5 A*算法
我宁愿永远做我自己,也不愿成为别人,即使那个人比你更快乐。 —《成为简奥斯汀》 🏰代码及环境配置:请参考 环境配置和代码运行! 4.5.1 概述 Dijkstra算法是基于广度优先搜索策略来遍历空间内的所有节点,最终计算出…...

Spring Boot 3.4.0 发布:功能概览与示例
Spring Boot 3.4.0 带来了许多增强功能,使现代应用开发更加高效、便捷和强大。以下是最新功能的完整概述,以及一些帮助您快速入门的代码示例。 1. 应用程序版本管理 Spring Boot 引入了 spring.application.version 属性,方便开发者设置和访…...

【48】Android通过libjpeg-turbo库实现图片压缩
(1)公司为节约图片占用服务器存储资源成本,需要对Android手机客户端所传递到云存储服务器中的图片进行压缩,在不影响图片失真程度的情况下,最大限度的压缩图片以节省图片所占用的存储空间。 (2)…...

Linux输入设备应用编程
本章学习输入设备的应用编程,首先要知道什么是输入设备?输入设备其实就是能够产生输入事件的设备就称为输入设备,常见的输入设备包括鼠标、键盘、触摸屏、按钮等等,它们都能够产生输入事件,产生输入数据给计算机系统。…...

【Vulkan入门】03-创建Device
目录 先叨叨git信息关键代码VulkanEnv::CreateDevice() 编译并运行程序题外话 先叨叨 在上篇已经选择了一个合适的PhysicalDevice。 本篇要为这个PhysicalDevice创将一个Device。Device可以理解为APP与PhysicalDevice之间的代理。 所有APP与PhysicalDevice之间交互的资源都通过…...

【jvm】C2编译器
目录 1. 说明2. 编译流程3. 使用与配置4. 性能优化与监控5. 局限性 1. 说明 1.JVM(Java虚拟机)C2编译器是Java编译过程中的重要环节,专门用于将Java字节码编译成高效的本地机器代码,以提升Java程序的执行效率。2.特点:…...

使用 Acme.sh 自动生成和续签免费 SSL 证书(含通配符支持)
Acme.sh 是一个开源的脚本,能够从 ZeroSSL、Let’s Encrypt 等证书颁发机构(CA)获取免费的 HTTPS 证书。该脚本特别简单易用,并且支持多种验证方式。下面将详细介绍使用 Acme.sh 生成、安装和更新证书的各个步骤。 Github地址 使用…...

Android 图形系统之四:Choreographer
Choreographer 是 Android 系统中负责帧同步的核心组件,它协调输入事件、动画和绘制任务,以确保界面以固定频率(通常是每 16ms,一帧)流畅渲染。通过管理 VSYNC 信号和调度任务,Choreographer 是实现流畅 UI…...