问题研究

项目中需要利用DataImportHandler从hive中sync数据到solr。发现有时候hive sql已经执行完几个小时了,sync任务还没有完成,貌似哪里卡住了。重启solr后重新sync又成功了,所以之前虽然遇到很多次这个问题也没有去深究。今天又出现了同样的问题,决定花点时间研究下到底是什么原因造成的。

利用jstack dump了几遍线程栈,发现很多个线程都卡在同一个地方,at java.net.SocketInputStream.socketRead0(Native Method),显然这些进程都在等待jdbc从hive中读取数据。初步判断可能是网络原因导致网络中断,TcpIp没有侦测到连接已经失败,我们在data-config.xml中配置hive数据源的时候又没有设置超时时间,导致线程一直傻傻等待接收数据sync任务一直无法完成,也没有任何异常抛出。之所以问题出现的这么频繁应该是因为我们的hive服务器设在美国,而solr服务器在国内。看来加上超时时间是很有必要的,难怪很多文章都提到为了不让比较慢的客户端拖垮服务器程序的性能必须加上超时时间。这些无限等待的线程都是在做无用功啊,又浪费服务器资源,设置超时时间后就会在超时时间到达时抛出timeout异常,退出线程。

"Thread-32" prio= tid=0x00007f077c052800 nid=0x3b04 runnable [0x00007f06fec7d000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:)
at java.net.SocketInputStream.read(SocketInputStream.java:)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:)
at java.io.BufferedInputStream.read(BufferedInputStream.java:)
- locked <0x00000000d8ccf078> (a java.io.BufferedInputStream)
at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:)
at org.apache.thrift.transport.TTransport.readAll(TTransport.java:)
at org.apache.thrift.transport.TSaslTransport.readLength(TSaslTransport.java:)
at org.apache.thrift.transport.TSaslTransport.readFrame(TSaslTransport.java:)
at org.apache.thrift.transport.TSaslTransport.read(TSaslTransport.java:)
at org.apache.thrift.transport.TSaslClientTransport.read(TSaslClientTransport.java:)
at org.apache.thrift.transport.TTransport.readAll(TTransport.java:)
at org.apache.thrift.protocol.TBinaryProtocol.readAll(TBinaryProtocol.java:)
at org.apache.thrift.protocol.TBinaryProtocol.readI32(TBinaryProtocol.java:)
at org.apache.thrift.protocol.TBinaryProtocol.readMessageBegin(TBinaryProtocol.java:)
at org.apache.thrift.TServiceClient.receiveBase(TServiceClient.java:)
at org.apache.hive.service.cli.thrift.TCLIService$Client.recv_ExecuteStatement(TCLIService.java:)
at org.apache.hive.service.cli.thrift.TCLIService$Client.ExecuteStatement(TCLIService.java:)
at org.apache.hive.jdbc.HiveStatement.execute(HiveStatement.java:)
at org.apache.solr.handler.dataimport.JdbcDataSource$ResultSetIterator.<init>(JdbcDataSource.java:)
at org.apache.solr.handler.dataimport.JdbcDataSource.getData(JdbcDataSource.java:)
at org.apache.solr.handler.dataimport.JdbcDataSource.getData(JdbcDataSource.java:)
at org.apache.solr.handler.dataimport.SqlEntityProcessor.initQuery(SqlEntityProcessor.java:)
at org.apache.solr.handler.dataimport.SqlEntityProcessor.nextRow(SqlEntityProcessor.java:)
at org.apache.solr.handler.dataimport.EntityProcessorWrapper.nextRow(EntityProcessorWrapper.java:)
at org.apache.solr.handler.dataimport.DocBuilder.buildDocument(DocBuilder.java:)
at org.apache.solr.handler.dataimport.DocBuilder.buildDocument(DocBuilder.java:)
at org.apache.solr.handler.dataimport.DocBuilder.doDelta(DocBuilder.java:)
at org.apache.solr.handler.dataimport.DocBuilder.execute(DocBuilder.java:)
at org.apache.solr.handler.dataimport.DataImporter.doDeltaImport(DataImporter.java:)
at org.apache.solr.handler.dataimport.DataImporter.runCmd(DataImporter.java:)

  

扩展阅读

遇到这个问题以后想了解下jdbc的超时机制,所以google了一把,看到两篇文档对我很有帮助,文档链接在文章的最后。一篇是关于jdbc超时机制的,另一篇是关于socket的keepalive。

总结一下jdbc相关的timeout有以下几种:

Transaction Timeout,用来限制一个事务的执行时间。

Statement Timeout,限制一条查询的执行时间,设置方法:java.sql.Statement.setQueryTimeout(int timeout)。

Socket Timeout,又包含connection timeout和read/write timeout,限制建立连接的时间和等待读取或者等待写数据的时间。

OS level socket Timeout,这个其实是Linux系统环境下的Socket的KeepAlive机制。java的Socket类里有个setKeepAlive(boolean on)方法可能就是用来设置KeepAlive机制是否生效。

KeepAlive的作用:

之前一直不明白为什么很多系统都要自己实现一个心跳机制,比如微信,导致信令风暴啊什么的很多问题。看完KeepAlive的文章后才有这样的感觉,原来如此啊!

1,检查连接是否活着

KeepAlive可以侦测到一些原因造成的失效的socket连接,比如内核错误或者连接的进程强制退出,还比如虽然连接的机器和进程都正常,但是网络已经出现故障。这些情况下,TCP是不知道连接已经失效的。

考虑下面这种情况,A发送SYN给B发起连接,B回复一个ACK/SYN,A又发送ACK到B,完成TCP的三次握手,连接建立成功。这个时候如果B突然崩溃,没有发送任何消息给A告知其已经崩溃,A就会一直以为B还活着。如果A正在等待B发送过来的数据,那么就会一直在那傻等着,而B即使重启成功它也不知道之前和A有连接,所以A永远等不到B的数据。如果有KeepAlive的话,它就会定时的发送数据给B,B收到数据后找不到对应的连接就会回复一个reset信息,那么A收到reset信息以后就知道连接已经失效。

    _____                                                     _____
| | | |
| A | | B |
|_____| |_____|
^ ^
|--->--->--->-------------- SYN -------------->--->--->---|
|---<---<---<------------ SYN/ACK ------------<---<---<---|
|--->--->--->-------------- ACK -------------->--->--->---|
| |
| system crash ---> X
|
| system restart ---> ^
| |
|--->--->--->-------------- PSH -------------->--->--->---|
|---<---<---<-------------- RST --------------<---<---<---|
| | 2,防止连接长时间无数据传输而被断开
比如下图的情况,NAT会监控A和B之间的所有连接,如果连接长时间处于闲置状态就会被断开。KeepAlive定期的发送数据可以促使连接不会被断开。
    _____           _____                                     _____
| | | | | |
| A | | NAT | | B |
|_____| |_____| |_____|
^ ^ ^
|--->--->--->---|----------- SYN ------------->--->--->---|
|---<---<---<---|--------- SYN/ACK -----------<---<---<---|
|--->--->--->---|----------- ACK ------------->--->--->---|
| | |
| | <--- connection deleted from table |
| | |
|--->- PSH ->---| <--- invalid connection |
| | |

下午的时候还做了个小测试,在一台机器上运行一个SocketServer的程序,另外一台运行Socket程序去连接SocketServer,这个时候我并没有设置Socket的任何timeout。然后断开网线,发现Socket抛出ReadTimeout异常。当时觉得很奇怪,还以为是底层有KeepAlive呢。后来想想可能是操作系统侦测到网线被拔掉了吧O(∩_∩)O~。

参考文献

http://www.cubrid.org/blog/dev-platform/understanding-jdbc-internals-and-timeout-configuration/

http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/

利用DataImportHandler建索引时一直无法完成的更多相关文章

  1. [慢查优化]建索引时注意字段选择性 & 范围查询注意组合索引的字段顺序

    文章转自:http://www.cnblogs.com/zhengyun_ustc/p/slowquery2.html 写在前面的话: 之前曾说过"不要求每个人一定理解 联表查询(join/ ...

  2. java web轻量级开发面试教程读书笔记:建索引时我们需要权衡的因素

    场景一,数据表规模不大,就几千行,即使不建索引,查询语句的返回时间也不长,这时建索引的意义就不大.当然,若就几千行,索引所占的空间也不多,所以这种情况下,顶多属于"性价比"不高. ...

  3. oracle建索引的可选项

    oracle中建索引可能大家都会,但是建索引是有几个选项参数却很少有人关注,在某些特殊环境下,可能会非常有用,下面一一说明: 1.NOSORT,记录排序可选项. 默认情况下,在表中创建索引的时候,会对 ...

  4. Oracle使用并行建索引须要注意的问题

    建索引时.我们为了建索引快.会加上并行,加上并行之后.此列索引就会是并行了. 訪问有并行度的索引时,CBO可能可能会考虑并行运行.这可能会引发一些问题,如在server资源紧张的时候用并行会引起更加严 ...

  5. INDEX--创建索引和删除索引时的SCH_M锁

    最近有一个困惑,生产服务器上有一表索引建得乱七八糟,经过整理后需要新建几个索引,再删除几个索引,建立索引时使用联机(ONLINE=ON)创建,查看下服务器负载(磁盘和CPU压力均比较低的情况)后就选择 ...

  6. 索引时利用K-邻近算法过滤重复歌曲

    最近一直在做公司搜索的优化与维护,做完索引和搜索的分离之后,又有一个新需求,因为做的是歌曲方面的搜索,所以在数据库中有多个同歌名,同演唱者的的数据,这样在用户搜索的时候,会出来一大堆不同版本的歌曲,影 ...

  7. Mongodb 3 查询优化(语句优化、建索引)

    一.explain(),语句分析工具 MongoDB 3.0之后,explain的返回与使用方法与之前版本有了很大的变化,介于3.0之后的优秀特色和我们目前所使用给的是3.0.7版本,本文仅针对Mon ...

  8. Mysql索引分析:适合建索引?不适合建索引?【转】

    数据库建立索引常用的规则如下: 1.表的主键.外键必须有索引: 2.数据量超过300的表应该有索引: 3.经常与其他表进行连接的表,在连接字段上应该建立索引: 4.经常出现在Where子句中的字段,特 ...

  9. MySQL 分区建索引

    200 ? "200px" : this.width)!important;} --> 介绍 mysql分区后每个分区成了独立的文件,虽然从逻辑上还是一张表其实已经分成了多张 ...

随机推荐

  1. 用sudo命令无法读取环境变量

    通过sudo -l来查看sudo的限制: $ sudo -l Matching Defaults entries for xxx on this host: env_reset, mail_badpa ...

  2. 二十五、oracle pl/sql进阶--控制结构(分支,循环,控制)

    一.pl/sql的进阶--控制结构在任何计算机语言(c,java,pascal)都有各种控制语句(条件语句,循环结构,顺序控制结构...),在pl/sql中也存在这样的控制结构.在本部分学习完成后,希 ...

  3. Python3与Python2的区别汇总

    1.print 在Python3.0  是一个函数,正确输入应该是:print (3x) 2.raw_input 在Python3.0改成input

  4. ARM驱动调试方法、思路总结、笔记

    驱动程序的调试一. 打印: prink, 自制proc文件UBOOT传入console=ttySAC0 console=tty11. 内核处理UBOOT传入的参数console_setup add_p ...

  5. TESTNG重试、截屏、监听

    http://qa.blog.163.com/blog/static/19014700220138585422735/

  6. 第九十六节,JavaScript概述

    JavaScript概述 学习要点: 1.什么是JavaScript 2.JavaScript特点 3.JavaScript历史 4.JavaScript核心 5.开发工具集 JavaScript诞生 ...

  7. Sass入门:第四章

    1.加法 加法运算是Sass中运算的一种,在变量或属性中都可以做加法运算.如: .box { width: 20px + 8in; } 编译出来的CSS: .box { width: 788px; } ...

  8. Exception fixing docBase for context

    原因在给tomcat的war包,传输过程中出了问题,或者不是2进制传输,重新用2进制传送到linux里的tomcat webapps 目录中  就解决了.

  9. ckplayer 实现

    <div id="flashcontent"></div> <div id="video" style="positio ...

  10. js禁止浏览器后退,防止重复支付

    <script language="JavaScript"> javascript:window.history.forward(1);</script>