doris 4.0.5疑似page cache bug

Viewed 11

版本: doris-4.0.5-rc01 (commit: 59de8c4c524)
影响: BE 反复段错误崩溃 (122次), audit_log 分区 p20260518 数据文件损坏, 查询间歇性返回 RPC UNAVAILABLE


一、问题现象

用户执行 SQL 查询时收到错误:

SQL 错误 [1105] [HY000]: RpcException, msg: send fragments failed.
io.grpc.StatusRuntimeException: UNAVAILABLE: io exception, host: 192.168.1.118

二、环境信息

集群配置

项目
FE 版本 doris-4.0.5-rc01 (commit: 59de8c4c524)

三、完整时间线

阶段一: 文件损坏产生 (5/18)

5/18 09:34 — Compaction 产出损坏文件

文件路径: /data/doris/be/storage/data/194/1815518124650/173204708/
          020000000000dc83844902009917fdfb91110df9bcffd0b4_0.dat
文件大小: 35,845,523 字节 (35MB)
创建时间: 2026-05-18 09:34
所属表:   __internal_schema.audit_log
所属分区: p20260518 (Tablet ID: 1815518124650)

该文件是 compaction 合并输出 (远大于同目录下每分钟写入的 15KB-3MB 小文件)。

阶段二: ColumnReaderCache 崩溃 (5/22)

5/22 11:34 — 首次缓存相关崩溃

*** Aborted at 1779420889 (unix time) → 2026-05-22 11:34
*** SIGSEGV unknown detail explain (@0x0) received by PID 1842829
  0# doris::signal::FailureSignalHandler
  ...
  4# doris::segment_v2::ColumnReader::~ColumnReader()
       at column_reader.cpp:294
  5# doris::segment_v2::ColumnReader::~ColumnReader()
       at column_reader.cpp:294
  6# std::_Sp_counted_base::_M_release_last_use_cold()
       at shared_ptr_base.h:198
  7# std::_List_base<CacheNode>::_M_destroy_node()
       at stl_list.h:845
  8# doris::segment_v2::ColumnReaderCache::_insert_locked_nocheck()
       at column_reader_cache.cpp:74
  9# doris::segment_v2::ColumnReaderCache::get_column_reader()
       at column_reader_cache.cpp:109
 10# doris::segment_v2::Segment::get_column_reader()
 11# doris::segment_v2::Segment::new_column_iterator()
       at segment.cpp:679
 12# doris::vectorized::VStatisticsIterator::init()
       at vgeneric_iterators.cpp:54
 ...
 17# doris::BetaRowsetReader::next_batch()
       at beta_rowset_reader.h:116
 18# doris::vectorized::VCollectIterator::Level0Iterator::next()
       at vcollect_iterator.cpp:578
 22# doris::vectorized::BlockReader::_direct_next_block()
       at block_reader.cpp:268

关键: 崩溃发生在 BetaRowsetReader::next_batch()ColumnReaderCache::get_column_reader() 路径上, 这是 compaction 读取阶段 的调用链。ColumnReaderCache 的 use-after-free bug 在缓存淘汰旧条目时触发空指针。

阶段三: PageCache 崩溃循环 (5/23 起)

5/23 10:01 — 首次 PageCache 崩溃

*** Aborted at 1779501667 (unix time) → 2026-05-23 10:01
*** SIGSEGV unknown detail explain (@0x0) received by PID 3151440
  4# google::protobuf::internal::RepeatedPtrFieldBase::DestroyProtos()
  5# doris::segment_v2::ColumnMetaPB::SharedDtor()
       at segment_v2.pb.cc:4758
  8# doris::segment_v2::SegmentFooterPB::SharedDtor()
       at segment_v2.pb.cc:6363
  9# doris::segment_v2::SegmentFooterPB::~SegmentFooterPB()
       at segment_v2.pb.cc:6358
 10# doris::MemoryTrackedPageBase::~MemoryTrackedPageBase()
       at page_cache.h:48
 11# doris::MemoryTrackedPageWithPagePtr::~MemoryTrackedPageWithPagePtr()
       at page_cache.cpp:69
 12# doris::LRUCache::prune_if()
       at lru_cache.cpp:627
 14# doris::LRUCachePolicy::prune_stale()
 15# doris::CacheManager::for_each_cache_prune_stale()
       at cache_manager.cpp:46
 16# doris::Daemon::cache_prune_stale_thread()
       at daemon.cpp:566

此后持续崩溃, 全部相同堆栈:

时间 PID tablet_id
5/23 10:01 3151440 0
5/23 11:42 3576641 0
5/28 11:48 3613021 1815518124650
5/28 20:27 1636049 0
5/30 20:00 1809319 1815518124650
5/31 12:24 4062478 1815518124650

累计 122 次 SIGSEGV (be.out 统计)。

阶段四: 数据损坏暴露 (5/29 起)

5/29 02:55 — Compaction 首次读到损坏文件

W20260529 02:55:04.701244 1809681 status.h:439] meet error status:
  [CORRUPTION]Bad page: checksum mismatch
  (actual=103909948 vs expect=704282814),
  file=/data/doris/be/storage/data/194/1815518124650/173204708/
       020000000000dc83844902009917fdfb91110df9bcffd0b4_0.dat

W20260529 02:55:04.701385 1809681 merger.cpp:309]
  failed to read next block when merging rowsets of tablet 1815518124650,
  error: [CORRUPTION]Bad page: checksum mismatch...

W20260529 02:55:04.706915 1809681 tablet.cpp:1892]
  failed to do cumulative compaction, tablet=1815518124650 :
  [CORRUPTION]Bad page: checksum mismatch...

此后每次 compaction 尝试处理 tablet 1815518124650 都会失败, 每 8 秒重试一次, WARNING 日志膨胀到 10MB+。


四、根因分析

4.1 两个独立的缓存 Bug

Bug 1: ColumnReaderCache use-after-free

  • 位置: column_reader_cache.cpp:74_insert_locked_nocheck()
  • 触发路径: Segment 读取 → ColumnReaderCache::get_column_reader() → 淘汰旧缓存条目 → ColumnReader 析构 → SIGSEGV
  • 影响: compaction 读取阶段返回脏数据, 直接导致数据损坏

Bug 2: PageCache (SegmentFooterPB) use-after-free

  • 位置: lru_cache.cpp:627LRUCache::prune_if()
  • 触发路径: 后台清理线程 → prune_stale() → SegmentFooterPB 析构 → RepeatedPtrFieldBase::DestroyProtos() → SIGSEGV
  • 影响: 后台线程崩溃, 导致 BE 进程状态异常

4.2 数据损坏的因果链

ColumnReaderCache use-after-free bug
  ↓
Compaction 读取阶段通过 ColumnReaderCache 获取 ColumnReader
  ↓
Cache 返回悬空指针指向的 ColumnReader
  ↓
通过悬空指针读取的数据 = 垃圾数据
  ↓
垃圾数据被写入新的 compaction 输出 segment 文件
  ↓
Footer checksum 基于正确的元数据计算, 但数据页已被污染
  ↓
checksum mismatch → [CORRUPTION]

4.3 恶性循环

损坏文件 → compaction 反复尝试读取 → 失败 → 损坏的 page 进入 PageCache
  → PageCache prune 线程触发 use-after-free → SIGSEGV
    → BE 崩溃/异常 → 更多 compaction 中断 → 循环

(以上内容为AI读取日志生成的报告)

1 Answers

您能同步一份 be.out 和 be.INFO 文件给我吗?可以加私聊我主页微信发我下