doris通过dataX导入数据发生宕机问题解决

依赖版本

  • doris: 2.1.0
  • clickhouse: 22.1.3.7
  • dataX: 使用代码自己编译的最新版本

问题发现

创建一个正常的dataX 采集任务,从clickhouse的一张表里向doris里写数据, 使用的是clickhousereaderdoriswriter

很简单的一个任务,数据量理论上也不多,才16万,60多M的注解,可是一执行,doris的be就全部宕机了。

问题是我们用这套环境跑过很多种数据库的数据采集,比如mysql,oracle, postgresql等,结果都正常。只有clickhouse数据库的采集任务,一执行就报错!

报的错有两种形式:
一种是直接提示be服务连接失败:
doris be拒接连接
另一种还有返回值,但是提示Label already exists的错误:
Label already exists

问题排查

在排查问题前,我们要先了解一下dataX同步数据到doris的方式,只有如此我们才能按图索骥来定位问题,而不是漫无目的的乱猜。

以下是dataX官网对其架构的设计理念:

为了解决异构数据源同步问题,DataX将复杂的网状的同步链路变成了星型数据链路,DataX作为中间传输载体负责连接各种数据源。当需要接入一个新的数据源的时候,只需要将此数据源对接到DataX,便能跟已有的数据源做到无缝数据同步。

datax框架设计

如此,我们可以了解到,在dataX的设计里,reader和writer两个独立的模块,是可以任意组合复用的。通过控制变量法,既然其他数据库的数据能正常导入到doris,那说明doriswriter应该是没有问题的。

所以,我们的第一怀疑对象是clickhouse的问题,要么是clickhouse表的问题,要么是clickhousereader的问题。但是当我们把clickhouse同样的表接入到mysql里时,却发现数据采集成功了!!竟然成功了!

这么说,clickhouse采集端也没有问题,那问题出在哪里了?

按照上面dataX的设计图,我们再次把目光看向了doris,这次我们不再怀疑doriswriter,而是直接怀疑doris本身。

这次我们查看doris的数据表,发现在系统建表的时候出现了大量的varchar(0)的表字段,通过将varchar(0)字段改为正常的有长度的字段,比如varchar(2000),问题就解决了。

但是问题真的是这样吗?

因为我们建表系统bug的原因,其他源采集数据到doris里时,也有可能产生varchar(0)的情况,说明varchar(0)并不会真正的阻碍dorisstream load数据的导入。

接下来我们尝试对每个varchar(0)字段进行修复的方式,逐个字段排查,最后定位到syslogid这个字段,其对应的值是6f336347a90549789092b11d31b2197a
这个字段只要长度为0,即使有一条数据,也能把doris的be全部干崩溃(全部崩溃是dataX重试的锅)。

然后在be.out日志里,我们发现报错信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
*** Query id: 5a4698a1afd40053-50e26699312ee9a5 ***
*** tablet id: 0 ***
*** Aborted at 1739168366 (unix time) try "date -d @1739168366" if you are using GNU date ***
*** Current BE git commitID: 91efb6a43d ***
*** SIGSEGV unknown detail explain (@0x0) received by PID 25235 (TID 26356 OR 0x7fbaf0c76700) from PID 0; stack trace: ***
0# doris::signal::(anonymous namespace)::FailureSignalHandler(int, siginfo_t*, void*) at /home/zcp/repo_center/doris_release/doris/be/src/common/signal_handler.h:417
1# os::Linux::chained_handler(int, siginfo*, void*) in /root/java/jdk1.8.0_221/jre/lib/amd64/server/libjvm.so
2# JVM_handle_linux_signal in /root/java/jdk1.8.0_221/jre/lib/amd64/server/libjvm.so
3# signalHandler(int, siginfo*, void*) in /root/java/jdk1.8.0_221/jre/lib/amd64/server/libjvm.so
4# 0x00007FBE7F8FA400 in /lib64/libc.so.6
5# __memcmp_sse4_1 in /lib64/libc.so.6
6# doris::FieldTypeTraits<(doris::FieldType)13>::cmp(void const*, void const*) at /home/zcp/repo_center/doris_release/doris/be/src/olap/types.h:1349
7# doris::segment_v2::TypedZoneMapIndexWriter<(doris::PrimitiveType)10>::flush() at /home/zcp/repo_center/doris_release/doris/be/src/olap/rowset/segment_v2/zone_map_index.cpp:90
8# doris::segment_v2::ScalarColumnWriter::finish_current_page() at /home/zcp/repo_center/doris_release/doris/be/src/olap/rowset/segment_v2/column_writer.cpp:683
9# doris::segment_v2::ScalarColumnWriter::finish() at /home/zcp/repo_center/doris_release/doris/be/src/olap/rowset/segment_v2/column_writer.cpp:593
10# doris::segment_v2::VerticalSegmentWriter::write_batch() at /home/zcp/repo_center/doris_release/doris/be/src/olap/rowset/segment_v2/vertical_segment_writer.cpp:719
11# doris::SegmentFlusher::_add_rows(std::unique_ptr<doris::segment_v2::VerticalSegmentWriter, std::default_delete<doris::segment_v2::VerticalSegmentWriter> >&, doris::vectorized::Block const*, unsigned long, unsigned long) at /home/zcp/repo_center/doris_release/doris/be/src/olap/rowset/segment_creator.cpp:183
12# doris::SegmentFlusher::flush_single_block(doris::vectorized::Block const*, int, long*) at /home/zcp/repo_center/doris_release/doris/be/src/olap/rowset/segment_creator.cpp:76
13# doris::SegmentCreator::flush_single_block(doris::vectorized::Block const*, int, long*) at /home/zcp/repo_center/doris_release/doris/be/src/olap/rowset/segment_creator.cpp:422
14# doris::BaseBetaRowsetWriter::flush_memtable(doris::vectorized::Block*, int, long*) at /home/zcp/repo_center/doris_release/doris/be/src/olap/rowset/beta_rowset_writer.cpp:489
15# doris::FlushToken::_do_flush_memtable(doris::MemTable*, int, long*) at /home/zcp/repo_center/doris_release/doris/be/src/olap/memtable_flush_executor.cpp:144
16# doris::FlushToken::_flush_memtable(std::unique_ptr<doris::MemTable, std::default_delete<doris::MemTable> >, int, long) in /opt/module/doris/be/lib/doris_be
17# doris::MemtableFlushTask::run() at /home/zcp/repo_center/doris_release/doris/be/src/olap/memtable_flush_executor.cpp:59
18# doris::ThreadPool::dispatch_thread() in /opt/module/doris/be/lib/doris_be
19# doris::Thread::supervise_thread(void*) at /home/zcp/repo_center/doris_release/doris/be/src/util/thread.cpp:499
20# start_thread in /lib64/libpthread.so.0
21# clone in /lib64/libc.so.6

可以看出是memcmp导致的crash,这个就是doris自身的问题了。

现在这个问题已经提给doris官方了,不过官方会不会处理就不确定了,因为高版本已经没这个问题了。

问题解决

  1. 修复建表语句,避免varchar(0)这种非法的字段格式的出现。
  2. 升级doris,实测doris3.0版本没有此问题

参考

dataX技术设计

doris stream load机制

提交的doris崩溃 bug


doris通过dataX导入数据发生宕机问题解决
https://www.hancher.top/2025/02/11/exception-doris-stream-load-from-clickhouse-by-data-crash/
作者
寒澈
发布于
2025年2月11日
更新于
2025年2月12日
许可协议