[Stream Load 超时问题排查1] - 源码排查定位- timeout by txn manager

2022-07-24 09:37:08 浏览数 (1)

问题现象

doris 现象: timeout by txn manager

nginx现象

代码语言:javascript复制
<html>
<head><title>504 Gateway Time-out</title></head>
<body bgcolor="white">
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx</center>
</body>
</html>

问题分层怀疑、定位

在分层定位问题前需要先知道Doris的整体部署结构, 方便定位问题. 部署结构如下:

由错误信息可以做如下猜测:

  1. nginx本身在请求超时时间是60s, 小于doris本身的超时时间
  2. doris本身的超时时间是60s
  3. 用户指定了超时时间是60s
  4. Load Blance (LB)本身超时时间是60s

通过排查,

  • 首先否定4. 原因: “timeout by txn manager”是doris任务执行时间太长被主动结束了. 和LB没关系
  • 其次check nginx各种超时配置后, 否定1
  • check doris配置后, 否定2, 默认是Config.stream_load_default_timeout_second, 应该为300s

具体朝3的方向分析

问题分析

  1. 查看Doris Stream Load报错详情后, 可以看到Prepare Time和Finish Time相差60s
  2. 翻看Doris源码, 确认 “timeout by txn manager”报错位置: 源码位置. 确认是Doris会定时检查哪些导入事物超时了, 超时后主动停止该任务. 通过翻看DatabaseTransactionMgr.java代码,最后可以知道是TransactionState.java中timeout参数控制超时时间.默认是Config.stream_load_default_timeout_second, 该配置默认300秒. 但是本次超时是60秒, 说明timeout参数沟通TransactionState.java的构造函数被重置了.
  3. 确认isTimeout数来源: 查找TransactionState构造函数的依赖关系, 可以找到如下代码截图: 按照标号顺序看:

说明: FrontendServiceImpl.java是fe提供的RPC服务接口. 提供库、表、事物等的基本操作服务.

到这里貌似就知道地方RPC请求了loadTxnBegin()方法, 什么地方调用的不清楚. 是broker ? be ? 猜测是be

回头再看看stream load在Fe中的处理过程.

stream load我们知道是http请求, 从源码包中我们查到到如下代码

翻看代码, 通古注册的url可以知道stream load是LoadAction.java这个类处理的. 请求是如何被转到这里处理的, 下回再分解.

代码语言:javascript复制
 public static void registerAction(ActionController controller) throws IllegalArgException {
        ExecuteEnv execEnv = ExecuteEnv.getInstance();
        LoadAction action = new LoadAction(controller, execEnv);
        controller.registerHandler(HttpMethod.PUT,
                                   "/api/{"   DB_KEY   "}/{"   TABLE_KEY   "}/_load", action);

        controller.registerHandler(HttpMethod.PUT,
                                   "/api/{"   DB_KEY   "}/{"   TABLE_KEY   "}/_stream_load",
                                   new LoadAction(controller, execEnv, true));
    }
代码语言:javascript复制

executeWithoutPassword()这个方法是当有stream load请求到fe时, 请求会被转发到这个方法处理, 代码核心如下:

代码语言:javascript复制
TNetworkAddress redirectAddr;
if (!isStreamLoad && !Strings.isNullOrEmpty(request.getSingleParameter(SUB_LABEL_NAME_PARAM))) {
    ...
} else {
    ...
    redirectAddr = new TNetworkAddress(backend.getHost(), backend.getHttpPort());
}

LOG.info("redirect load action to destination={}, stream: {}, db: {}, tbl: {}, label: {}",
        redirectAddr.toString(), isStreamLoad, dbName, tableName, label);
redirectTo(request, response, redirectAddr);


这个核心代码逻辑比较简单, fe会把stream load的请求redirect到一个be节点处理, 这个be节点称为Coordinator节点. 这个be节点会负责和fe通信生成导入执行计划, 处理导入事物等. 下面我们再细说.

那我们看看be是如何处理fe转发过来的stream load请求的.

0 人点赞