景象
ExcuteSql不工作不调度,stop也进行不了,active的工作个数也不升高。
场景复现
1、模拟现场结构数据
2、Tc命令模仿现场网络环境模拟丢包30%
tc qdisc del dev enp4s0f0 root netem loss 30%
问题排查
netstat -pan | grep $NIFI_PID
能够看到和数据库开启了5个tcp连贯,也能够看到有五个socket处于连贯状态
间接看线程
jstack -l $NIFI_PID | grep 'java.net.SocketInputStream.socketRead0(Native Method)' -C 10
察看了一段时间,socket依然没有敞开,能够根本必定现场环境应该曾经复现。
问题剖析
一次残缺的数据库申请包含三个阶段:
1、建设连贯
2、数据传输
3、断开连接connect timeout:如果与服务器(这里指数据库)申请建设连贯的工夫超过ConnectionTimeOut,就会抛 ConnectionTimeOutException,即服务器连贯超时,没有在规定的工夫内建设连贯。
socket timeout:如果与服务器连贯胜利,就开始数据传输了。如果服务器解决数据用时过长,超过了SocketTimeOut,就会抛出SocketTimeOutExceptin,即服务器响应超时,服务器没有在规定的工夫内返回给客户端数据。
在未设置超时工夫场景下,nifi通过jdbc获取数据库数据,实质是操作系统在调用Socket.read(),如果网络问题被阻塞住,那么操作系统会很少在调用Socket,java培训因为底层没有数据交互,那么其无奈晓得对端是否宕机,所以会始终期待。
难道零碎没有默认的socketTimeout?
有的,上述场景下内核会在一个socket两个小时都没有数据交互状况下(可设置)启动keepalive定时器来探测对端的socket。
也就是说呈现假死会在7875秒后复原,大略两个多小时吧。
这就是nifi端线程假死的起因;
论断
JDBC的socket未设置超时,呈现了死连贯。
JDBC 驱动是用 Socket 形式与数据库连贯的,应用程序和数据库之间的连贯超时并不是由数据库解决的。
当数据库忽然宕掉或产生网络谬误(设施故障等)时,JDBC 驱动的 Socket 超时的值是必须的。因为 TCP/IP 的构造,Socket 没有方法检测到网络谬误,因而利用不能检测到与数据库到连贯断开了。如果没有设置 Socket 超时,应用程序会始终期待数据库返回后果。(这个连贯也被叫做“死连贯”) 为了防止死连贯,Socket 必须要设置超时工夫。Socket 超时能够通过 JDBC 驱动程序配置。通过设置 Socket 超时,能够防止出现网络谬误时始终期待的状况并缩短故障工夫。
在timeout为0的时候,走默认的零碎调用不设置超时工夫的逻辑。在timeout>0时,将socket设置为非阻塞,而后用select零碎调用去模仿超时,而没有走linux自身的超时逻辑。
解决措施
设置socket和Connection的超时工夫。
避免因为网络问题呈现死连贯,给数据库的拜访url加socket timeout和Connection timeout。