问题现象
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的整体部署结构, 方便定位问题. 部署结构如下:
由错误信息可以做如下猜测:
- nginx本身在请求超时时间是60s, 小于doris本身的超时时间
- doris本身的超时时间是60s
- 用户指定了超时时间是60s
- 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的方向分析
问题分析
- 查看Doris Stream Load报错详情后, 可以看到Prepare Time和Finish Time相差60s
- 翻看Doris源码, 确认 “timeout by txn manager”报错位置: 源码位置. 确认是Doris会定时检查哪些导入事物超时了, 超时后主动停止该任务. 通过翻看DatabaseTransactionMgr.java代码,最后可以知道是TransactionState.java中timeout参数控制超时时间.默认是Config.stream_load_default_timeout_second, 该配置默认300秒. 但是本次超时是60秒, 说明timeout参数沟通TransactionState.java的构造函数被重置了.
- 确认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请求的.