场景一
用户A
A: “亲,用 MaxCompute Java SDK 跑作业,为什么卡住不动了?”
me: “有 Logview 吗?发来看下”
A: “没有,我用的是SDK,没Logview”
场景二
用户B
B :“亲,用 MaxCompute Java SDK 访问 Table,为什么卡住半天没反应?”
me:“卡在哪一行了?”
B:"就 RestClient retry 然后卡住了"
去繁就简
用户 A 的问题在于没有 instance 的 logview,导致无法追踪 instance 的运行过程。
通常用户在创建 instance 后会调用 instance.waitForSuccess() 来等待作业运行完成,一旦作业耗时巨大,程序就卡在这一步了,此时如果有 logview ,就能查看追踪查看作业等待的具体原因了。
用户 B 的问题在于 sdk 的 Restclient 本身有重试机制,从表面来看就是卡住了,没有任何输出。
如果在每次重试的时候都输出错误,就可以快速定位问题节约时间了。我已经遇到好几个公共云用户因为缺包导致一直卡住几分钟才丢出异常,严重影响了工作效率。
那么问题可以归结为下面两点:
1【 怎么使用 MaxCompute Java SDK 生成 instance Logview 】
答案很简单, MaxCompute Java SDK 提供了 logview 接口,详情可查看 SDK Java Doc
<span style="color:#f8f8f2"><code class="language-java">String logview = odps.<span style="color:#e6db74">logview</span>().<span style="color:#e6db74">generateLogView</span>(instance, <span style="color:#ae81ff">7</span> * <span style="color:#ae81ff">24</span>);</code></span>
两个参数: instance 对象,logview token 超时时间 (单位:小时)
再次提醒用户,在使用 SDK 的时候,请为每个 instance 记录 Logview,一旦遇到问题可快速追踪。
当然如果改代码很麻烦,那还有一个绝招。在 MaxCompute Console 中使用 wait <instance_id>
命令也可以得到Logview。
2【 能不能在每次重试的时候,都把错误输出呢?】
当然可以。MaxCompute Java SDK 提供了抽象类 RetryLogger
详情可查看 SDK Java Doc
<span style="color:#333333"><span style="color:#f8f8f2"><code class="language-java"><span style="color:#66d9ef"><span style="color:#f92672">public</span></span> <span style="color:#66d9ef"><span style="color:#f92672">static</span></span> <span style="color:#66d9ef"><span style="color:#f92672">abstract</span></span> <span style="color:#66d9ef"><span style="color:#f92672">class</span></span> RetryLogger {
<span style="color:slategray"><span style="color:#75715e">/**
* 当 RestClent 发生重试前的回调函数
*
* @param e
* 错误异常
* @param retryCount
* 重试计数
* @param retrySleepTime
* 下次需要的重试时间
*/</span></span>
<span style="color:#66d9ef"><span style="color:#f92672">public</span></span> <span style="color:#66d9ef"><span style="color:#f92672">abstract</span></span> <span style="color:#66d9ef"><span style="color:#f92672">void</span></span> <span style="color:#e6db74"><span style="color:#a6e22e">onRetryLog</span></span>(Throwable e, <span style="color:#66d9ef"><span style="color:#f8f8f2"><span style="color:#f92672">long</span></span></span> retryCount, <span style="color:#66d9ef"><span style="color:#f8f8f2"><span style="color:#f92672">long</span></span></span> retrySleepTime);
}</code></span></span>
用户只需实现一个自己的 RetryLogger
子类,然后在初始化 odps 对象的时候使用 odps.getRestClient().setRetryLogger(new UserRetryLogger());
就可以将日志输出。
一个典型的实现如下:
<span style="color:#333333"><span style="color:#f8f8f2"><code class="language-java"><span style="color:slategray"><span style="color:#75715e">// init odps</span></span>
odps.<span style="color:#e6db74">getRestClient</span>().<span style="color:#e6db74">setRetryLogger</span>(<span style="color:#66d9ef"><span style="color:#f92672">new</span></span> UserRetryLogger());
<span style="color:slategray"><span style="color:#75715e">// your retry logger</span></span>
<span style="color:#66d9ef"><span style="color:#f92672">public</span></span> <span style="color:#66d9ef"><span style="color:#f92672">class</span></span> UserRetryLogger <span style="color:#66d9ef"><span style="color:#f92672">extends</span></span> RetryLogger {
<span style="color:#75715e">@Override</span>
<span style="color:#66d9ef"><span style="color:#f92672">public</span></span> <span style="color:#66d9ef"><span style="color:#f92672">void</span></span> <span style="color:#e6db74"><span style="color:#a6e22e">onRetryLog</span></span>(Throwable e, <span style="color:#66d9ef"><span style="color:#f8f8f2"><span style="color:#f92672">long</span></span></span> retryCount, <span style="color:#66d9ef"><span style="color:#f8f8f2"><span style="color:#f92672">long</span></span></span> sleepTime) {
<span style="color:#66d9ef"><span style="color:#f92672">if</span></span> (e != <span style="color:#f92672">null</span> && e <span style="color:#66d9ef"><span style="color:#f92672">instanceof</span></span> OdpsException) {
String requestId = ((OdpsException) e).<span style="color:#e6db74">getRequestId</span>();
<span style="color:#66d9ef"><span style="color:#f92672">if</span></span> (requestId != <span style="color:#f92672">null</span>) {
System.err.<span style="color:#e6db74">println</span>(String.<span style="color:#e6db74">format</span>(
<span style="color:#a6e22e"><span style="color:#e6db74">"Warning: ODPS request failed, requestID:%s, retryCount:%d, will retry in %d seconds."</span></span>,
requestId, retryCount, sleepTime));
<span style="color:#66d9ef"><span style="color:#f92672">return</span></span>;
}
}
System.err.<span style="color:#e6db74">println</span>(String.<span style="color:#e6db74">format</span>(
<span style="color:#a6e22e"><span style="color:#e6db74">"Warning: ODPS request failed:%s, retryCount:%d, will retry in %d seconds."</span></span>, e.<span style="color:#e6db74">getMessage</span>(),retryCount,
sleepTime));
}
}</code></span></span>
掌握上面两种技巧,就可以快速定位问题。
原文链接
更多技术干货 请关注阿里云云栖社区微信号 :yunqiinsight