概述
最近负责的一款数据产品。有个功能:选择某个数据源,比如阿里云的MaxCompute数据源,然后手写SQL,点击自动生成字段(即获取前置SQL里的查询字段。前置SQL可以有drop then create table动作子句,但是最后一个子句必须得是select子句),然后选择数据的去向,比如MQ,需要指定一个已存在的topic,即实现数据推送功能。
都在做业务出海的大背景下,我们也需要部署一套环境在菲律宾马尼拉。后来,商业分析同事反馈MaxCompute数据源无法自动生成字段,并给出报错信息截图,报错信息如下:SQLException: create download session failed: instance id=, Error:ErrorCode=Local Error, ErrorMessage=Hi, HTTP/1.0 is not allowed。
自动生成字段的逻辑是:先使用alibaba druid sql-parser解析SQL获取查询字段,但是select *
这种无法解析,因为sql-parser并不会执行SQL语句,只是通过AST等语法树技术去做词法和句法分析。然后代码逻辑判断select *
这种情况抛异常,后续逻辑捕获异常,通过拿到数据源信息,提交执行SQL,进而拿到执行结果,最后解析结果数据。
也就是说,现在是执行这个SQL:select * from phl_anls.tmp_liujun_iview_test limit 1
失败。
网络只找到一个类似帖子,但是没有什么参考价值。
问题背景,另一篇文章:连接阿里云MaxCompute数据源报错504 Gateway Time-out
排查
另外,阿里云日志查询平台,搜不到系统报错日志。初步怀疑,SQL执行提交到MC数据源,并没有拿到结果数据?也就不会有我们平台产品层面的报错日志?
搜索条件改为:_container_name_:cloud-*-autojob-fat-v1
,发现其实有日志的:
ERROR c.x.c.a.b.s.DataProviderService- sendEmail error:org.springframework.mail.MailSendException: Mail server connection failed; nested exception is javax.mail.MessagingException: Could not connect to SMTP host: smtpdm-ap-southeast-1.aliyun.com, port: 25;
ERROR c.x.c.a.b.d.b.JdbcDataProvider- jdbc execAutoWork ??????_copy, sqlNum = 1, error:
ERROR com.aliyun.odps.jdbc.OdpsConnection- no fallback
ERROR com.aliyun.odps.jdbc.OdpsConnection- enableLimitFallback: false
ERROR com.aliyun.odps.jdbc.OdpsConnection- create download session failed: ErrorCode=Local Error, ErrorMessage=Hi, HTTP/1.0 is not allowed
WARN com.aliyun.odps.jdbc.OdpsConnection- task summary is empty
INFO com.aliyun.odps.jdbc.OdpsConnection- It took me 3623 ms to run sql
INFO com.aliyun.odps.jdbc.OdpsConnection- http://logview.odps.aliyun.com/logview/?h=http://dataworks.companyapi.com/api&p=phl_anls&i=20221216034615839gqoz6af03&token===
INFO com.aliyun.odps.jdbc.OdpsConnection- Enabled SQL task properties: {odps.idata.useragent=JDBC-Version:3.3.6 SDK-Version:0.40.10-public}
INFO com.aliyun.odps.jdbc.OdpsConnection- create prepared statements: SELECT * FROM phl_anls.tmp_liujun_iview_test LIMIT 1
INFO c.xy.cloudiview.common.util.JdbcUtil- MaxCompute ds getConnection success
INFO com.aliyun.odps.jdbc.OdpsConnection- Connect to odps project phl_anls successfully
INFO com.aliyun.odps.jdbc.OdpsConnection- JVM timezone : Asia/Manila
INFO com.aliyun.odps.jdbc.OdpsConnection- endpoint=http://dataworks.companyapi.com/api, project=phl_anls, schema=null
INFO com.aliyun.odps.jdbc.OdpsConnection- ODPS JDBC driver, Version 3.3.6
也就是说,通过odps-jdbc驱动(版本为当前最新版3.3.6)方式提交SQL,MC数据源连接成功,SQL提交成功,然后阿里云会生成一个odps logview地址。但是下一步获取Summary
信息失败,日志级别为Warn:task summary is empty
。
该死,查询日志语句应该是:_container_name_:cloud-iview-autojob-fat-v1 and content:ERROR
,不能写成and content:ERROR/WARN
一次性查询两种级别的日志。
与此同时,我们这边的运维同事也在与阿里云的网络支持持续沟通中,涉及到一些网络层面的专业术语,不是很懂,情况也不容乐观。
本地(国内开发机)不能测试MC数据源(部署在新加坡)的联通性:
2022-12-12 16:37:11,553 [http-nio-8082-exec-2] INFO 1- ODPS JDBC driver, Version 3.2.21
2022-12-12 16:37:11,553 [http-nio-8082-exec-2] INFO 1- endpoint=http://dataworks.companyapi.com/api, project=phl_anls
2022-12-12 16:37:11,553 [http-nio-8082-exec-2] INFO 1- JVM timezone : Asia/Shanghai
2022-12-12 16:37:11,553 [http-nio-8082-exec-2] INFO 1- charset=UTF-8, logview host=null
2022-12-12 16:45:52,139 [http-nio-8082-exec-2] ERROR c.xy.cloudiview.common.util.JdbcUtil- MaxCompute ds getConnection error: {}
com.aliyun.odps.ReloadException:
at com.aliyun.odps.LazyLoad.lazyLoad(LazyLoad.java:65)
at com.aliyun.odps.Project.getProperty(Project.java:505)
at com.aliyun.odps.jdbc.OdpsConnection.<init>(OdpsConnection.java:181)
at com.aliyun.odps.jdbc.OdpsDriver.connect(OdpsDriver.java:59)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:247)
at com.xy.cloudiview.common.util.JdbcUtil.getConnection(JdbcUtil.java:67)
at com.xy.cloudiview.autojob.business.dataprovider.business.JdbcDataProvider.getSqlColumn(JdbcDataProvider.java:454)
省略若干行
Caused by: com.aliyun.odps.OdpsException:
at com.aliyun.odps.rest.RestClient.handleErrorResponse(RestClient.java:398)
at com.aliyun.odps.rest.RestClient.request(RestClient.java:330)
at com.aliyun.odps.rest.RestClient.request(RestClient.java:284)
at com.aliyun.odps.Project.reload(Project.java:332)
at com.aliyun.odps.LazyLoad.lazyLoad(LazyLoad.java:63)
... 62 common frames omitted
总结
跨地域,走公网+https(即:jdbc:odps:https://service.ap-southeast-1.maxcompute.aliyun.com/api?project=phl_anls) ,数据源连接成功,SQL提交执行也是成功,可以拿到数据。不过评估下来,不能走公网方式;
走内网,不管是http还是https(jdbc:odps:https://service.ap-southeast-1.maxcompute.aliyun-inc.com/api?project=phl_anls),数据源连接失败,报错:504 Gateway Time-out
于是建议走代理方式,代理后的URL,http方式(jdbc:odps:http://dataworks.companyapi.com/api?project=phl_anls),数据源连接成功;https方式(jdbc:odps:https://dataworks.companyapi.com/api?project=phl_anls),数据源连接失败,报错:504 Gateway Time-out
代理后的http方式,通过odps-jdbc提交SQL,打开 logview 链接,报错提示:
但是我手动调整这个logview 地址,看起来是可以拿到执行记录和执行结果的:
解决
问题前前后后排查长达2周。。
这中间,尝试过使用客户端odpscmd;也看过网络部署方案,涉及知识盲区:
后面再次排查时,发现如下日志:
ErrorCode=Local Error, ErrorMessage=Failed to create download session with tunnel endpoint http://dt.ap-southeast-1.maxcompute.aliyun-inc.com
ERROR com.aliyun.odps.jdbc.OdpsConnection- create download session for session failed: ErrorCode=Local Error, ErrorMessage=Failed to create download session with tunnel endpoint http://dt.ap-southeast-1.maxcompute.aliyun-inc.com
at com.aliyun.odps.tunnel.InstanceTunnel$DownloadSession.initiate(InstanceTunnel.java:514)
at com.aliyun.odps.tunnel.InstanceTunnel$DownloadSession.<init>(InstanceTunnel.java:253)
at com.aliyun.odps.tunnel.InstanceTunnel$DownloadSession.<init>(InstanceTunnel.java:228)
at com.aliyun.odps.tunnel.InstanceTunnel.createDownloadSession(InstanceTunnel.java:78)
at com.aliyun.odps.jdbc.OdpsStatement.getResultSet(OdpsStatement.java:688)
at com.aliyun.odps.jdbc.OdpsStatement.executeQuery(OdpsStatement.java:404)
看到一个很重要的信息:Failed to create download session with tunnel endpoint http://dt.ap-southeast-1.maxcompute.aliyun-inc.com
。
咨询阿里云,这个地址dt.ap-southeast-1.maxcompute.aliyun-inc.com
是新加坡的odpstunnel的下载内网地址,也就是数据源连接成功(参考前面的日志),SQL提交成功(executeQuery),执行也是成功,获取结果集(getResultSet),最后需要下载结果集,于是需要createDownloadSession
,就会走这个地址。
故而nginx代理需要加上odpstunnel域名(dt.ap-southeast-1.maxcompute.aliyun-inc.com
)的代理。
另外,之前多次排查问题时,日志并没有记录到这个tunnel endpoint
信息,就有点盲人摸象的感觉。