yugabytedb 查找TTL row超时原因调查

129 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情

在前一篇文章juejin.cn/post/717218… 我们提到使用SELECT * from examples.concurrent_executions去查找10w条全部超时的记录,100%卡住,这里面为何yugabyteDB没用使用file filter过滤掉不必要的数据呢?今天啃了一天代码,记录如下: 其实真实答案是,yugabyteDB根本没有实现!select * from table 时,底层是转化为Scan的,最开始的入口为:

 Status QLReadOperation::Execute(const YQLStorageIf& ql_storage,
                                 CoarseTimePoint deadline,
                                 const ReadHybridTime& read_time,
                                 const DocReadContext& doc_read_context,
                                 const Schema& projection,
                                 QLResultSet* resultset,
                                 HybridTime* restart_read_ht) {
   const auto& schema = doc_read_context.schema;
   //根據SQL 條件構建Spec
   ql_storage.BuildYQLScanSpec(
       request_, read_time, schema, read_static_columns, static_projection, &spec,
       &static_row_spec);
    //spec可以根據where條件謂詞,生成seek iter ,注意這裏有我們想要的filter
     ql_storage.GetIterator(
       request_, projection, doc_read_context, txn_op_context_, deadline, read_time,
       *spec, &iter));
     ....
 }

这里有重要的spec构建迭代器,输出iter。Spec对象是用SQL的的where条件,if条件构建的。

 //注意这里是QLScan强制转换为DocQLScanSpec
 DoInit(down_cast<const DocQLScanSpec&>(spec));
 //注意QLScanSpec有很多参数,都是根据sql的条件变量构建的
 QLScanSpec(const QLConditionPB* condition,
              const QLConditionPB* if_condition,
              const bool is_forward_scan,
              QLExprExecutorPtr executor = nullptr);

看到ql_storage是一个基类YQLStorageIf,真實對象是:src/yb/docdb/ql_rocksdb_storage.cc的一個實現

class QLRocksDBStorage : public *YQLStorageIf*。我们发现成员变量的迭代器,是DocRowwiseIterator:

 Status QLRocksDBStorage::GetIterator(...)
     auto doc_iter = std::make_unique<DocRowwiseIterator>(
       projection, doc_read_context, txn_op_context, doc_db_, deadline, read_time);
 //接下来根据spec初始化迭代器,我们来看看怎么实现的
 doc_iter->Init(spec);
 Status DocRowwiseIterator::Init(const QLScanSpec& spec) {
   table_type_ = TableType::YQL_TABLE_TYPE;
   return DoInit(down_cast<const DocQLScanSpec&>(spec));
 }

我们看到了自己最想要的迭代器构建:确实doc_spec.CreateFileFilter()有创建file filter,但是我们的SQL却没用任何condition 部分,所以无法构建CreateFileFilter。至此,我们select 超时的原因已经找到:

 Status DocRowwiseIterator::DoInit(const T& doc_spec) {
 db_iter_ = CreateIntentAwareIterator(
       doc_db_, mode, lower_doc_key.AsSlice(), doc_spec.QueryId(), txn_op_context_,
       deadline_, read_time_, doc_spec.CreateFileFilter());

也就是说,SELECT * from examples.concurrent_executions 这种sql,没有任何SQL where condition,也不支持TTL 做condition,是不能去过滤TTL sst的,也比较好理解,因为yugabyteDB不是一个时序数据库,TTL可能散乱在任何SST文件中,在散乱的TTL key、row聚合成的sst,或者经过compaction将这些不同的TTL的key聚合到一个SST文件,CreateFileFilter将无法发挥作用(他们也没有去优化、实现)。