Apache Doris
从0.15到1.1.5属于一个大版本升级,部分语法和使用方式也发生了较大的变化,本文除前期兼容性调研(可以通过官网查到到一部分兼容性问题)已知问题外,生产环境正式升级之后遇到的突发问题进行整理总结,作为一个避坑指南,后期也会不定期更新。
升级到1.0及以上版本后会出现ODBC
版本兼容性问题,具体报错信息如下:
这个报错官网也有说明,具体原因不再赘述了,需要注意的是只要是从1.0以下版本升级到1.0及以上版本的,都会出现这个问题。解决方案可以分为以下几种:
ODBC
驱动包。具体安装流程可以参考:Doris升级至1.0发行版后MySQL ODBC 不可用解决方案。SQL
语句,将ODBC
外表替换成OLAP
表。以上2种方案,都可以解决目前遇到的问题,但具体分析来看:
Doris
官网已经明确说过,1.2版本以后将不会再维护ODBC
外表了,同时通过实际生产中的应用来看,ODBC
的性能和稳定性与OLAP
表相差甚远,很难满足快速响应需求;
如果重新安装ODBC
驱动包,以前的ODBC
表也没办法再使用,需要利用新的驱动重新创建ODBC
,返工成本高;
综上所述,修改SQL
语句才是持久化的调整方式。
如果升级之前SQL
中出现了ODBC
外表和OLAP
表关联查询,开启向量化引擎之后,会导致BE节点挂掉。附上一个异常样例SQL
:
SELECT
`text1`,
`text2`,
`text3`,
`text4`
FROM
test1.ods_odbc_mapping
WHERE
DATE_FORMAT( text1, '%Y-%m-%d' ) >= DATE_SUB( CURDATE(), INTERVAL 35 DAY )
AND concat( text2, text3, text4 ) NOT IN (
SELECT
concat( text5, '00000000000', text3, text4 )
FROM
test2.ods_olap_delta )
具体be.out
堆栈日志信息如下:
F0704 12:58:53.773236 185790 column_vector.cpp:210] Parameters start = 0, length = 1024, are out of bound in ColumnVector<T>::insert_range_from method (data.size() = 0).
[root@gaia-pro-bigdata-be01 log]# vim be.out.bak
start time: Mon Jul 3 21:39:37 CST 2023
WARNING: Logging before InitGoogleLogging() is written to STDERR
I0703 21:39:37.529274 452701 env.cpp:46] Env init successfully.
F0704 12:58:53.773236 185790 column_vector.cpp:210] Parameters start = 0, length = 1024, are out of bound in ColumnVector<T>::insert_range_from method (data.size() = 0).
@ 0x55f96e8131fa doris::PlanFragmentExecutor::get_vectorized_internal()
@ 0x55f96e8177bd doris::PlanFragmentExecutor::open_vectorized_internal()
@ 0x55f96e81926f doris::PlanFragmentExecutor::open()
@ 0x7f47096f3dd5 start_thread
@ 0x7f4709a05ead __clone
@ (nil) (unknown)
*** Query id: 0-0 ***
*** Aborted at 1688446733 (unix time) try "date -d @1688446733" if you are using GNU date ***
start time: Mon Jul 3 21:39:37 CST 2023
WARNING: Logging before InitGoogleLogging() is written to STDERR
I0703 21:39:37.529274 452701 env.cpp:46] Env init successfully.
F0704 12:58:53.773236 185790 column_vector.cpp:210] Parameters start = 0, length = 1024, are out of bound in ColumnVector<T>::insert_range_from method (data.size() = 0).
@ 0x55f96e8131fa doris::PlanFragmentExecutor::get_vectorized_internal()
@ 0x55f96e8177bd doris::PlanFragmentExecutor::open_vectorized_internal()
@ 0x55f96e81926f doris::PlanFragmentExecutor::open()
@ 0x7f47096f3dd5 start_thread
@ 0x7f4709a05ead __clone
@ (nil) (unknown)
*** Query id: 0-0 ***
*** Aborted at 1688446733 (unix time) try "date -d @1688446733" if you are using GNU date ***
*** SIGABRT unkown detail explain (@0x6e85d) received by PID 452701 (TID 0x7f460dec9700) from PID 452701; stack trace: ***
0# doris::signal::(anonymous namespace)::FailureSignalHandler(int, siginfo_t*, void*) at /mnt/disk2/ygl/code/github/apache-doris/be/src/common/signal_handler.h:428
1# 0x00007F470993E280 in /lib64/libc.so.6
2# gsignal in /lib64/libc.so.6
3# abort in /lib64/libc.so
.6
4# 0x000055F96E01EAFE in /soft/apache-doris-be-1.1.5-bin-x86_64/lib/doris_be
5# 0x000055F97046E32D in /soft/apache-doris-be-1.1.5-bin-x86_64/lib/doris_be
6# google::LogMessage::SendToLog() in /soft/apache-doris-be-1.1.5-bin-x86_64/lib/doris_be
7# google::LogMessage::Flush() in /soft/apache-doris-be-1.1.5-bin-x86_64/lib/doris_be
8# google::LogMessageFatal::~LogMessageFatal() in /soft/apache-doris-be-1.1.5-bin-x86_64/lib/doris_be
9# doris::vectorized::ColumnVector::insert_range_from(doris::vectorized::IColumn const&, unsigned long, unsigned long) at /mnt/disk2/ygl/code/github/apache-doris/be
/src/vec/columns/column_vector.cpp:21810# doris::vectorized::HashJoinNode::_build_output_block(doris::vectorized::Block*, doris::vectorized::Block*) at /mnt/disk2/ygl/code/github/apache-doris/be/src/vec/exec/j
oin/vhash_join_node.cpp:147611# doris::vectorized::HashJoinNode::get_next(doris::RuntimeState*, doris::vectorized::Block*, bool*) at /mnt/disk2/ygl/code/github/apache-doris/be/src/vec/exec/join/vhash
_join_node.cpp:104712# doris::PlanFragmentExecutor::get_vectorized_internal(doris::vectorized::Block**) at /mnt/disk2/ygl/code/github/apache-doris/be/src/runtime/plan_fragment_executor.cpp:3
5213# doris::PlanFragmentExecutor::open_vectorized_internal() at /mnt/disk2/ygl/code/github/apache-doris/be/src/runtime/plan_fragment_executor.cpp:301
14# doris::PlanFragmentExecutor::open() at /mnt/disk2/ygl/code/github/apache-doris/be/src/runtime/plan_fragment_executor.cpp:259
15# doris::FragmentExecState::execute() at /mnt/disk2/ygl/code/github/apache-doris/be/src/runtime/fragment_mgr.cpp:249
16# doris::FragmentMgr::_exec_actual(std::shared_ptr, std::function) at /mnt/disk2/ygl/code/github/apache-do
ris/be/src/runtime/fragment_mgr.cpp:48717# std::_Function_handler, std::function
(doris::PlanFragmentExecutor*)>))(std::shared_ptr<doris::FragmentExecState>, std::function<void (doris::PlanFragmentExecutor*)>)> >::_M_invoke(std::_Any_data const&) at /mnt/disk2/ygl/installs/ldbtools/include/c++/11/bits/std_function.h:29118# doris::ThreadPool::dispatch_thread() at /mnt/disk2/ygl/code/github/apache-doris/be/src/util/threadpool.cpp:578
19# doris::Thread::supervise_thread(void*) at /mnt/disk2/ygl/code/github/apache-doris/be/src/util/thread.cpp:407
20# start_thread in /lib64/libpthread.so.0
21# __clone in /lib64/libc.so.6
从BE端源码insert_range_from
这个方法判断,可能是因为data.size()
为空,进入到if
判断后,输出了从be.out中看到的日志信息Parameters start = 0, length = 1024, are out of bound in ColumnVector
,但程序并没有返回,而是继续执行memcpy
这个内存拷贝方法,导致操作系统内存分配异常,然后Aborted
掉这个进程导致的,但至于为什么内存拷贝会出现异常,这个就没有继续深入追踪了。
解决方案:
Doris
1.1.5版本向量化引擎默认是关闭状态,但在1.2版本以后,向量化引擎是默认开启的;SQL
语句,将ODBC
外表替换成OLAP
表。综合来看,向量化引擎是Doris
的一个重大功能,它能极致提高查询性能,为了快速响应需求,在实际业务中肯定是要开启的,我们不可能因为使用ODBC
外表而放弃向量化引擎,因此最优的解决方案就是修改SQL
语句,将SQL
中的ODBC
外表替换掉。
在1.0版本以下时,如果要查看一个表的所有tablet
,我们常用的语法是show tablet from table
,但在1.0及以后的版本中,该语法发生了变化,如果还是继续使用旧的语法会出现以下报错:
mysql> show tablet from ods_test_delta\G;
ERROR 1105 (HY000): errCode = 2, detailMessage = Syntax error in line 1:
show tablet from ods_test_delta
^
Encountered: FROM
Expected
mysql>
解决方案:
使用新的查看语法show tablets from table
即可。
mysql> show tablets from test_cdc_sink\G;
*************************** 1. row ***************************
TabletId: 3944055
ReplicaId: 3944056
BackendId: 10003
SchemaHash: -1
Version: 1
LstSuccessVersion: 1
LstFailedVersion: -1
LstFailedTime: NULL
LocalDataSize: 0
RemoteDataSize: 0
RowCount: 0
State: NORMAL
LstConsistencyCheckTime: NULL
CheckVersion: -1
VersionCount: 1
PathHash: -1
MetaUrl: http://172.0.0.1:8040/api/meta/header/3944055
CompactionStatus: http://172.0.0.1:8040/api/compaction/show?tablet_id=3944055
CHAR
类型字段隐士转换问题:在1.0以下版本中,如果OLAP
表中的字段是char
类型,在使用in过滤数据时,如果in里面的过滤条件是数值类型,是可以执行的;但在1.0及以后的版本,如果in里面继续使用数值类型,会报类型转换异常detailMessage = can not cast from origin type TINYINT to target type=CHAR(2)
,具体测试参考如下:
##建表语句
CREATE TABLE `ods_test_in_delta` (
`id` INT NULL COMMENT 'id',
`name` varchar(500) NULL COMMENT 'name',
`age` int NULL COMMENT 'age',
`address` varchar(500) NULL COMMENT 'address',
`status` char(2) NULL COMMENT 'status',
`ranke` varchar(1) NULL COMMENT 'ranke',
`grade` TINYINT(1) NULL COMMENT 'grade'
) ENGINE=OLAP
UNIQUE KEY(`id`)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(`id`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 3",
"in_memory" = "false",
"storage_format" = "V2",
"disable_auto_compaction" = "false"
);
##插入语句
insert into ods_test_in_delta(id,name,age,address,status,ranke,grade) VALUES(1,"张三",28,"西安","1","1",1);
insert into ods_test_in_delta(id,name,age,address,status,ranke,grade) VALUES(2,"李四",21,"上海","2","2",6);
insert into ods_test_in_delta(id,name,age,address,status,ranke,grade) VALUES(3,"王二",22,"北京","1","3",2);
insert into ods_test_in_delta(id,name,age,address,status,ranke,grade) VALUES(4,"麻子",18,"天津","3","6",1);
insert into ods_test_in_delta(id,name,age,address,status,ranke,grade) VALUES(5,"横七",56,"济南","4","4",3);
insert into ods_test_in_delta(id,name,age,address,status,ranke,grade) VALUES(6,"竖八",47,"杭州","5","5",4);
status
字段类型为char
,根据status in (1,3,5)
,会出现报错:mysql> SELECT * from ods_test_in_delta where status in (1,3,5)\G;
ERROR 1105 (HY000): errCode = 2, detailMessage = can not cast from origin type TINYINT to target type=CHAR(2)
ERROR:
No query specified
mysql>
grade
字段类型为tinyint
,根据grade in ("1","3","2")
,可以正常查询出结果:mysql> SELECT * from ods_test_in_delta where grade in ("1","3","2");
+------+--------+------+---------+--------+-------+-------+
| id | name | age | address | status | ranke | grade |
+------+--------+------+---------+--------+-------+-------+
| 1 | 张三 | 28 | 西安 | 1 | 1 | 1 |
| 3 | 王二 | 22 | 北京 | 1 | 3 | 2 |
| 4 | 麻子 | 18 | 天津 | 3 | 6 | 1 |
| 5 | 横七 | 56 | 济南 | 4 | 4 | 3 |
+------+--------+------+---------+--------+-------+-------+
4 rows in set (0.01 sec)
mysql>
ranke
字段类型为varchar
,根据 ranke in (2,3,5)
,可以正常查询出结果:mysql> SELECT * from ods_test_in_delta where ranke in (2,3,5);
+------+--------+------+---------+--------+-------+-------+
| id | name | age | address | status | ranke | grade |
+------+--------+------+---------+--------+-------+-------+
| 2 | 李四 | 21 | 上海 | 2 | 2 | 6 |
| 3 | 王二 | 22 | 北京 | 1 | 3 | 2 |
| 6 | 竖八 | 47 | 杭州 | 5 | 5 | 4 |
+------+--------+------+---------+--------+-------+-------+
3 rows in set (0.01 sec)
mysql>
从以上3个case 可以看出,1.0以上版本兼容了 varchar
和int
之间的隐士转换,但对char
类型没有做类型转换。遇到这种情况,只能提高SQL
书写规范,尽量减少这种类型转换的需求。
通过本次从0.15升级到1.1.5版本的过程中来看,因为前期也做了大量兼容性调研工作,所以升级工作整体还是比较顺利的,但升级过后也遇到以上这些问题在调研过程中并没有涉及到。目前已知问题中,除了ODBC
与OLAP
关联会导致BE节点down机外,暂时还没有发现其他比较严重的问题,所以大家在升级Apache Doris
时还是要做好前提兼容性调研的工作,避免出现不可控异常导致生产环境瘫痪,后续如果有新的版本兼容问题,也会持续更新。
换的需求。
通过本次从0.15升级到1.1.5版本的过程中来看,因为前期也做了大量兼容性调研工作,所以升级工作整体还是比较顺利的,但升级过后也遇到以上这些问题在调研过程中并没有涉及到。目前已知问题中,除了ODBC
与OLAP
关联会导致BE节点down机外,暂时还没有发现其他比较严重的问题,所以大家在升级Apache Doris
时还是要做好前提兼容性调研的工作,避免出现不可控异常导致生产环境瘫痪,后续如果有新的版本兼容问题,也会持续更新。